@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.
Files changed (38) hide show
  1. package/dist/components/glk-accordion-item.js +62 -0
  2. package/dist/components/glk-accordion.js +13 -0
  3. package/dist/components/glk-avatar.js +59 -0
  4. package/dist/components/glk-badge.js +38 -0
  5. package/dist/components/glk-button.js +81 -0
  6. package/dist/components/glk-card.js +51 -0
  7. package/dist/components/glk-checkbox.js +104 -0
  8. package/dist/components/glk-divider.js +12 -0
  9. package/dist/components/glk-input.js +139 -0
  10. package/dist/components/glk-list-item.js +188 -0
  11. package/dist/components/glk-list.js +75 -0
  12. package/dist/components/glk-modal.js +101 -0
  13. package/dist/components/glk-nav.js +13 -0
  14. package/dist/components/glk-pill.js +49 -0
  15. package/dist/components/glk-popover.js +109 -0
  16. package/dist/components/glk-progress.js +78 -0
  17. package/dist/components/glk-radio.js +110 -0
  18. package/dist/components/glk-range.js +113 -0
  19. package/dist/components/glk-search.js +88 -0
  20. package/dist/components/glk-select.js +97 -0
  21. package/dist/components/glk-status.js +36 -0
  22. package/dist/components/glk-tab-accessory.js +66 -0
  23. package/dist/components/glk-tab-bar.js +59 -0
  24. package/dist/components/glk-tab-dock.js +52 -0
  25. package/dist/components/glk-tab-item.js +93 -0
  26. package/dist/components/glk-textarea.js +96 -0
  27. package/dist/components/glk-title.js +17 -0
  28. package/dist/components/glk-toast.js +105 -0
  29. package/dist/components/glk-toggle.js +122 -0
  30. package/dist/components/shared/base-Bm9Z714o.js +199 -0
  31. package/dist/glasskit-elements.esm.js +39 -12
  32. package/dist/glasskit-elements.js +39 -12
  33. package/dist/glasskit-elements.min.js +1 -1
  34. package/package.json +7 -4
  35. package/src/base.js +11 -1
  36. package/src/components/containers/glk-list.js +2 -2
  37. package/src/components/content/glk-card.js +19 -2
  38. package/src/components/feedback/glk-modal.js +5 -5
@@ -0,0 +1,93 @@
1
+ import { G as GlkElement } from './shared/base-Bm9Z714o.js';
2
+
3
+ class GlkTabItem extends GlkElement {
4
+ static get observedAttributes() {
5
+ return ['label', 'active', 'badge'];
6
+ }
7
+
8
+ render() {
9
+ this._btn = this.createElement('button', ['glass-tab-bar__item']);
10
+ if (this.getBoolAttr('active')) this._btn.classList.add('is-active');
11
+
12
+ // Icon — clone SVG from light DOM into shadow DOM so GlassKit CSS applies
13
+ this._iconEl = this.createElement('span', ['glass-tab-bar__icon']);
14
+
15
+ // Label
16
+ this._labelEl = this.createElement('span', ['glass-tab-bar__label']);
17
+ this._labelEl.textContent = this.getAttribute('label') || '';
18
+
19
+ // Badge inside icon container (position: absolute relative to icon)
20
+ const badge = this.getAttribute('badge');
21
+ if (badge) {
22
+ this._badgeEl = this.createElement('span', ['glass-tab-bar__badge']);
23
+ this._badgeEl.textContent = badge;
24
+ this._iconEl.appendChild(this._badgeEl);
25
+ }
26
+
27
+ this._btn.appendChild(this._iconEl);
28
+ this._btn.appendChild(this._labelEl);
29
+
30
+ this._wrapper.appendChild(this._btn);
31
+
32
+ // Defer icon cloning — children may not be parsed yet
33
+ requestAnimationFrame(() => this._cloneIcon());
34
+ }
35
+
36
+ _cloneIcon() {
37
+ const svg = this.querySelector('svg');
38
+ if (svg) {
39
+ const clone = svg.cloneNode(true);
40
+ // Remove inline attributes that would override GlassKit styles
41
+ clone.removeAttribute('width');
42
+ clone.removeAttribute('height');
43
+ clone.removeAttribute('stroke');
44
+ clone.removeAttribute('stroke-width');
45
+ clone.removeAttribute('stroke-linecap');
46
+ clone.removeAttribute('stroke-linejoin');
47
+ clone.removeAttribute('fill');
48
+ this._iconEl.insertBefore(clone, this._iconEl.firstChild);
49
+ }
50
+ }
51
+
52
+ setupEvents() {
53
+ this._onClick = () => {
54
+ this.setAttribute('active', '');
55
+ this.emit('glk-tab-select');
56
+ };
57
+ this._btn.addEventListener('click', this._onClick);
58
+ }
59
+
60
+ teardownEvents() {
61
+ this._btn?.removeEventListener('click', this._onClick);
62
+ }
63
+
64
+ onAttributeChanged(name) {
65
+ if (!this._btn) return;
66
+ switch (name) {
67
+ case 'active':
68
+ this._btn.classList.toggle('is-active', this.getBoolAttr('active'));
69
+ break;
70
+ case 'label':
71
+ this._labelEl.textContent = this.getAttribute('label') || '';
72
+ break;
73
+ case 'badge': {
74
+ const badge = this.getAttribute('badge');
75
+ if (badge) {
76
+ if (!this._badgeEl) {
77
+ this._badgeEl = this.createElement('span', ['glass-tab-bar__badge']);
78
+ this._iconEl.appendChild(this._badgeEl);
79
+ }
80
+ this._badgeEl.textContent = badge;
81
+ } else if (this._badgeEl) {
82
+ this._badgeEl.remove();
83
+ this._badgeEl = null;
84
+ }
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ customElements.define('glk-tab-item', GlkTabItem);
92
+
93
+ export { GlkTabItem };
@@ -0,0 +1,96 @@
1
+ import { a as GlkFormElement } from './shared/base-Bm9Z714o.js';
2
+
3
+ class GlkTextarea extends GlkFormElement {
4
+ static get observedAttributes() {
5
+ return ['label', 'placeholder', 'rows', 'disabled', 'name', 'value', 'required'];
6
+ }
7
+
8
+ render() {
9
+ const group = this.createElement('div', ['glass-input-group']);
10
+
11
+ this._labelEl = this.createElement('label', ['glass-label']);
12
+ this._labelEl.textContent = this.getAttribute('label') || '';
13
+
14
+ this._textarea = this.createElement('textarea', ['glass-textarea']);
15
+ const placeholder = this.getAttribute('placeholder');
16
+ if (placeholder) this._textarea.setAttribute('placeholder', placeholder);
17
+
18
+ const rows = this.getAttribute('rows');
19
+ if (rows) this._textarea.setAttribute('rows', rows);
20
+
21
+ const name = this.getAttribute('name');
22
+ if (name) this._textarea.setAttribute('name', name);
23
+
24
+ const value = this.getAttribute('value');
25
+ if (value) this._textarea.value = value;
26
+
27
+ if (this.getBoolAttr('disabled')) this._textarea.disabled = true;
28
+ if (this.getBoolAttr('required')) this._textarea.required = true;
29
+
30
+ group.appendChild(this._labelEl);
31
+ group.appendChild(this._textarea);
32
+
33
+ this._wrapper.appendChild(group);
34
+ this._syncFormValue();
35
+ }
36
+
37
+ setupEvents() {
38
+ this._onInput = () => {
39
+ this._syncFormValue();
40
+ this.emit('glk-input', { value: this._textarea.value });
41
+ this.dispatchEvent(new Event('input', { bubbles: true }));
42
+ };
43
+ this._textarea.addEventListener('input', this._onInput);
44
+ }
45
+
46
+ teardownEvents() {
47
+ this._textarea?.removeEventListener('input', this._onInput);
48
+ }
49
+
50
+ onAttributeChanged(name) {
51
+ if (!this._textarea) return;
52
+ switch (name) {
53
+ case 'label':
54
+ this._labelEl.textContent = this.getAttribute('label') || '';
55
+ break;
56
+ case 'placeholder':
57
+ this._textarea.setAttribute('placeholder', this.getAttribute('placeholder') || '');
58
+ break;
59
+ case 'rows':
60
+ this._textarea.setAttribute('rows', this.getAttribute('rows') || '');
61
+ break;
62
+ case 'disabled':
63
+ this._textarea.disabled = this.getBoolAttr('disabled');
64
+ break;
65
+ case 'name':
66
+ this._textarea.setAttribute('name', this.getAttribute('name') || '');
67
+ break;
68
+ case 'value':
69
+ this._textarea.value = this.getAttribute('value') || '';
70
+ this._syncFormValue();
71
+ break;
72
+ }
73
+ }
74
+
75
+ _syncFormValue() {
76
+ this.setFormValue(this._textarea.value);
77
+ }
78
+
79
+ resetValue() {
80
+ this._textarea.value = this.getAttribute('value') || '';
81
+ this._syncFormValue();
82
+ }
83
+
84
+ get value() { return this._textarea?.value ?? ''; }
85
+ set value(v) {
86
+ if (this._textarea) this._textarea.value = v;
87
+ this._syncFormValue();
88
+ }
89
+
90
+ get disabled() { return this.getBoolAttr('disabled'); }
91
+ set disabled(v) { this.setBoolAttr('disabled', v); }
92
+ }
93
+
94
+ customElements.define('glk-textarea', GlkTextarea);
95
+
96
+ export { GlkTextarea };
@@ -0,0 +1,17 @@
1
+ import { G as GlkElement } from './shared/base-Bm9Z714o.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
+
17
+ export { GlkTitle };
@@ -0,0 +1,105 @@
1
+ import { G as GlkElement } from './shared/base-Bm9Z714o.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
+
105
+ export { GlkToast };
@@ -0,0 +1,122 @@
1
+ import { a as GlkFormElement } from './shared/base-Bm9Z714o.js';
2
+
3
+ class GlkToggle extends GlkFormElement {
4
+ static get observedAttributes() {
5
+ return ['checked', 'disabled', 'label', 'name', 'value'];
6
+ }
7
+
8
+ render() {
9
+ const label = this.createElement('label', ['glass-toggle']);
10
+
11
+ this._input = this.createElement('input', ['glass-toggle__input'], {
12
+ type: 'checkbox'
13
+ });
14
+
15
+ const name = this.getAttribute('name');
16
+ if (name) this._input.setAttribute('name', name);
17
+
18
+ const track = this.createElement('span', ['glass-toggle__track']);
19
+ const thumb = this.createElement('span', ['glass-toggle__thumb']);
20
+ track.appendChild(thumb);
21
+
22
+ this._labelEl = this.createElement('span', ['glass-toggle__label']);
23
+ this._labelEl.textContent = this.getAttribute('label') || '';
24
+
25
+ label.appendChild(this._input);
26
+ label.appendChild(track);
27
+ label.appendChild(this._labelEl);
28
+
29
+ if (this.getBoolAttr('checked')) this._input.checked = true;
30
+ if (this.getBoolAttr('disabled')) this._input.disabled = true;
31
+
32
+ this._defaultChecked = this.getBoolAttr('checked');
33
+ this._wrapper.appendChild(label);
34
+
35
+ this._syncFormValue();
36
+ this.setAttribute('role', 'switch');
37
+ this.setAttribute('aria-checked', String(this._input.checked));
38
+ if (this.getBoolAttr('disabled')) this.setAttribute('aria-disabled', 'true');
39
+ }
40
+
41
+ setupEvents() {
42
+ this._onChange = () => {
43
+ this._syncing = true;
44
+ this.setBoolAttr('checked', this._input.checked);
45
+ this._syncing = false;
46
+ this.setAttribute('aria-checked', String(this._input.checked));
47
+ this._syncFormValue();
48
+ this.emit('glk-change', { checked: this._input.checked });
49
+ this.dispatchEvent(new Event('change', { bubbles: true }));
50
+ };
51
+ this._input.addEventListener('change', this._onChange);
52
+ }
53
+
54
+ teardownEvents() {
55
+ this._input?.removeEventListener('change', this._onChange);
56
+ }
57
+
58
+ onAttributeChanged(name) {
59
+ if (this._syncing) return;
60
+ if (!this._input) return;
61
+ switch (name) {
62
+ case 'checked':
63
+ this._input.checked = this.getBoolAttr('checked');
64
+ this.setAttribute('aria-checked', String(this._input.checked));
65
+ this._syncFormValue();
66
+ break;
67
+ case 'disabled':
68
+ this._input.disabled = this.getBoolAttr('disabled');
69
+ this.setAttribute('aria-disabled', String(this.getBoolAttr('disabled')));
70
+ break;
71
+ case 'label':
72
+ this._labelEl.textContent = this.getAttribute('label') || '';
73
+ break;
74
+ case 'name':
75
+ this._input.setAttribute('name', this.getAttribute('name') || '');
76
+ break;
77
+ }
78
+ }
79
+
80
+ _syncFormValue() {
81
+ const val = this.getAttribute('value') || 'on';
82
+ this.setFormValue(this._input.checked ? val : null);
83
+ }
84
+
85
+ resetValue() {
86
+ this._input.checked = this._defaultChecked;
87
+ this.setBoolAttr('checked', this._defaultChecked);
88
+ this.setAttribute('aria-checked', String(this._defaultChecked));
89
+ this._syncFormValue();
90
+ }
91
+
92
+ restoreValue(state) {
93
+ if (state) {
94
+ this._input.checked = true;
95
+ this.setBoolAttr('checked', true);
96
+ }
97
+ }
98
+
99
+ get checked() { return this._input?.checked ?? false; }
100
+ set checked(v) {
101
+ if (this._input) this._input.checked = v;
102
+ this.setBoolAttr('checked', v);
103
+ this.setAttribute('aria-checked', String(v));
104
+ this._syncFormValue();
105
+ }
106
+
107
+ get disabled() { return this.getBoolAttr('disabled'); }
108
+ set disabled(v) { this.setBoolAttr('disabled', v); }
109
+
110
+ get name() { return this.getAttribute('name'); }
111
+ set name(v) { this.setAttribute('name', v); }
112
+
113
+ get value() { return this.getAttribute('value') || 'on'; }
114
+ set value(v) { this.setAttribute('value', v); }
115
+
116
+ get label() { return this.getAttribute('label'); }
117
+ set label(v) { this.setAttribute('label', v); }
118
+ }
119
+
120
+ customElements.define('glk-toggle', GlkToggle);
121
+
122
+ export { GlkToggle };