@adia-ai/web-components 0.4.6 → 0.4.7
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/USAGE.md +29 -9
- package/components/accordion/accordion.d.ts +17 -0
- package/components/accordion/accordion.js +10 -117
- package/components/accordion/class.js +132 -0
- package/components/action-list/action-list.d.ts +15 -0
- package/components/action-list/action-list.js +9 -140
- package/components/action-list/class.js +156 -0
- package/components/agent-artifact/agent-artifact.d.ts +25 -0
- package/components/agent-artifact/agent-artifact.js +8 -181
- package/components/agent-artifact/class.js +200 -0
- package/components/agent-feedback-bar/agent-feedback-bar.d.ts +21 -0
- package/components/agent-feedback-bar/agent-feedback-bar.js +8 -143
- package/components/agent-feedback-bar/class.js +162 -0
- package/components/agent-questions/agent-questions.d.ts +23 -0
- package/components/agent-questions/agent-questions.js +8 -180
- package/components/agent-questions/class.js +199 -0
- package/components/agent-reasoning/agent-reasoning.d.ts +23 -0
- package/components/agent-reasoning/agent-reasoning.js +8 -494
- package/components/agent-reasoning/class.js +513 -0
- package/components/agent-suggestions/agent-suggestions.d.ts +21 -0
- package/components/agent-suggestions/agent-suggestions.js +8 -78
- package/components/agent-suggestions/class.js +97 -0
- package/components/agent-trace/agent-trace.d.ts +19 -0
- package/components/alert/alert.d.ts +29 -0
- package/components/alert/alert.js +8 -175
- package/components/alert/class.js +194 -0
- package/components/avatar/avatar.d.ts +27 -0
- package/components/avatar/avatar.js +9 -159
- package/components/avatar/class.js +173 -0
- package/components/badge/badge.d.ts +27 -0
- package/components/badge/badge.js +9 -75
- package/components/badge/class.js +93 -0
- package/components/block/block.d.ts +19 -0
- package/components/block/block.js +9 -15
- package/components/block/class.js +33 -0
- package/components/breadcrumb/breadcrumb.d.ts +23 -0
- package/components/breadcrumb/breadcrumb.js +8 -113
- package/components/breadcrumb/class.js +132 -0
- package/components/button/button.d.ts +34 -0
- package/components/button/button.js +15 -66
- package/components/button/class.js +80 -0
- package/components/calendar-picker/calendar-picker.a2ui.json +6 -1
- package/components/calendar-picker/calendar-picker.js +8 -332
- package/components/calendar-picker/calendar-picker.yaml +51 -177
- package/components/calendar-picker/class.js +351 -0
- package/components/canvas/canvas.a2ui.json +6 -1
- package/components/canvas/canvas.d.ts +17 -0
- package/components/canvas/canvas.yaml +19 -36
- package/components/card/card.a2ui.json +3 -0
- package/components/card/card.d.ts +27 -0
- package/components/card/card.js +9 -50
- package/components/card/card.yaml +171 -433
- package/components/card/class.js +68 -0
- package/components/chart/chart.d.ts +41 -0
- package/components/chart/chart.js +8 -2131
- package/components/chart/class.js +2150 -0
- package/components/chart-legend/chart-legend.d.ts +27 -0
- package/components/chart-legend/chart-legend.js +8 -197
- package/components/chart-legend/class.js +215 -0
- package/components/chat-thread/chat-thread.d.ts +17 -0
- package/components/chat-thread/chat-thread.js +8 -157
- package/components/chat-thread/class.js +176 -0
- package/components/check/check.js +11 -52
- package/components/check/class.js +68 -0
- package/components/code/class.js +501 -0
- package/components/code/code.js +8 -482
- package/components/col/class.js +30 -0
- package/components/col/col.d.ts +23 -0
- package/components/col/col.js +10 -13
- package/components/color-picker/class.js +550 -0
- package/components/color-picker/color-picker.js +8 -531
- package/components/command/class.js +364 -0
- package/components/command/command.a2ui.json +3 -0
- package/components/command/command.d.ts +19 -0
- package/components/command/command.js +8 -345
- package/components/command/command.yaml +105 -124
- package/components/demo-toggle/class.js +153 -0
- package/components/demo-toggle/demo-toggle.d.ts +23 -0
- package/components/demo-toggle/demo-toggle.js +8 -135
- package/components/description-list/class.js +86 -0
- package/components/description-list/description-list.d.ts +21 -0
- package/components/description-list/description-list.js +8 -67
- package/components/divider/class.js +57 -0
- package/components/divider/divider.d.ts +19 -0
- package/components/divider/divider.js +10 -40
- package/components/drawer/class.js +306 -0
- package/components/drawer/drawer.d.ts +25 -0
- package/components/drawer/drawer.js +8 -287
- package/components/embed/class.js +73 -0
- package/components/embed/embed.d.ts +23 -0
- package/components/embed/embed.js +9 -55
- package/components/empty-state/class.js +108 -0
- package/components/empty-state/empty-state.d.ts +21 -0
- package/components/empty-state/empty-state.js +9 -90
- package/components/feed/class.js +381 -0
- package/components/feed/feed.d.ts +19 -0
- package/components/feed/feed.js +9 -367
- package/components/field/class.js +266 -0
- package/components/field/field.d.ts +23 -0
- package/components/field/field.js +8 -247
- package/components/fields/class.js +106 -0
- package/components/fields/fields.d.ts +19 -0
- package/components/fields/fields.js +8 -87
- package/components/grid/class.js +31 -0
- package/components/grid/grid.d.ts +23 -0
- package/components/grid/grid.js +10 -14
- package/components/heatmap/class.js +305 -0
- package/components/heatmap/heatmap.d.ts +31 -0
- package/components/heatmap/heatmap.js +8 -286
- package/components/icon/class.js +54 -0
- package/components/icon/icon.d.ts +23 -0
- package/components/icon/icon.js +13 -40
- package/components/image/class.js +112 -0
- package/components/image/image.d.ts +33 -0
- package/components/image/image.js +9 -94
- package/components/input/class.js +773 -0
- package/components/input/input.a2ui.json +3 -0
- package/components/input/input.js +8 -755
- package/components/input/input.yaml +171 -442
- package/components/inspector/class.js +142 -0
- package/components/inspector/inspector.a2ui.json +8 -1
- package/components/inspector/inspector.d.ts +17 -0
- package/components/inspector/inspector.js +8 -124
- package/components/inspector/inspector.yaml +15 -30
- package/components/kbd/class.js +34 -0
- package/components/kbd/kbd.a2ui.json +3 -0
- package/components/kbd/kbd.d.ts +17 -0
- package/components/kbd/kbd.js +10 -17
- package/components/kbd/kbd.yaml +54 -185
- package/components/link/class.js +187 -0
- package/components/link/link.d.ts +55 -0
- package/components/link/link.js +8 -168
- package/components/list/class.js +249 -0
- package/components/list/list.d.ts +23 -0
- package/components/list/list.js +9 -231
- package/components/menu/class.js +332 -0
- package/components/menu/menu.d.ts +21 -0
- package/components/menu/menu.js +11 -316
- package/components/modal/class.js +231 -0
- package/components/modal/modal.a2ui.json +5 -1
- package/components/modal/modal.d.ts +23 -0
- package/components/modal/modal.js +8 -212
- package/components/modal/modal.yaml +19 -39
- package/components/nav/class.js +150 -0
- package/components/nav/nav.d.ts +31 -0
- package/components/nav/nav.js +8 -131
- package/components/nav-group/class.js +152 -0
- package/components/nav-group/nav-group.d.ts +35 -0
- package/components/nav-group/nav-group.js +9 -134
- package/components/nav-item/class.js +86 -0
- package/components/nav-item/nav-item.d.ts +37 -0
- package/components/nav-item/nav-item.js +10 -69
- package/components/noodles/class.js +510 -0
- package/components/noodles/noodles.d.ts +33 -0
- package/components/noodles/noodles.js +9 -493
- package/components/option-card/class.js +167 -0
- package/components/option-card/option-card.js +8 -149
- package/components/otp-input/class.js +180 -0
- package/components/otp-input/otp-input.a2ui.json +5 -1
- package/components/otp-input/otp-input.js +9 -162
- package/components/otp-input/otp-input.yaml +45 -174
- package/components/page/class.js +97 -0
- package/components/page/page.d.ts +46 -0
- package/components/page/page.js +8 -79
- package/components/pagination/class.js +195 -0
- package/components/pagination/pagination.d.ts +23 -0
- package/components/pagination/pagination.js +9 -177
- package/components/pane/class.js +186 -0
- package/components/pane/pane.a2ui.json +12 -1
- package/components/pane/pane.d.ts +31 -0
- package/components/pane/pane.js +8 -167
- package/components/pane/pane.yaml +57 -157
- package/components/pipeline-status/class.js +189 -0
- package/components/pipeline-status/pipeline-status.a2ui.json +7 -1
- package/components/pipeline-status/pipeline-status.d.ts +21 -0
- package/components/pipeline-status/pipeline-status.js +9 -172
- package/components/pipeline-status/pipeline-status.yaml +34 -72
- package/components/popover/class.js +194 -0
- package/components/popover/popover.d.ts +23 -0
- package/components/popover/popover.js +9 -176
- package/components/progress/class.js +74 -0
- package/components/progress/progress.a2ui.json +3 -0
- package/components/progress/progress.d.ts +19 -0
- package/components/progress/progress.js +10 -57
- package/components/progress/progress.yaml +124 -287
- package/components/progress-row/class.js +110 -0
- package/components/progress-row/progress-row.d.ts +23 -0
- package/components/progress-row/progress-row.js +8 -92
- package/components/radio/class.js +83 -0
- package/components/radio/radio.js +11 -67
- package/components/range/class.js +194 -0
- package/components/range/range.js +9 -176
- package/components/rating/class.js +148 -0
- package/components/rating/rating.js +9 -130
- package/components/richtext/class.js +87 -0
- package/components/richtext/richtext.a2ui.json +7 -1
- package/components/richtext/richtext.d.ts +19 -0
- package/components/richtext/richtext.js +8 -68
- package/components/richtext/richtext.yaml +30 -65
- package/components/row/class.js +50 -0
- package/components/row/row.d.ts +27 -0
- package/components/row/row.js +10 -33
- package/components/search/class.js +134 -0
- package/components/search/search.js +10 -117
- package/components/segment/class.js +62 -0
- package/components/segment/segment.d.ts +25 -0
- package/components/segment/segment.js +10 -45
- package/components/segmented/class.js +165 -0
- package/components/segmented/segmented.a2ui.json +4 -0
- package/components/segmented/segmented.js +10 -148
- package/components/segmented/segmented.yaml +41 -59
- package/components/select/class.js +408 -0
- package/components/select/select.js +15 -396
- package/components/skeleton/class.js +52 -0
- package/components/skeleton/skeleton.d.ts +23 -0
- package/components/skeleton/skeleton.js +8 -34
- package/components/slider/class.js +184 -0
- package/components/slider/slider.js +9 -166
- package/components/stack/class.js +28 -0
- package/components/stack/stack.d.ts +17 -0
- package/components/stack/stack.js +10 -11
- package/components/step-progress/class.js +98 -0
- package/components/step-progress/step-progress.d.ts +27 -0
- package/components/step-progress/step-progress.js +8 -79
- package/components/stepper/class.js +126 -0
- package/components/stepper/stepper.d.ts +19 -0
- package/components/stepper/stepper.js +9 -112
- package/components/stream/class.js +109 -0
- package/components/stream/stream.d.ts +19 -0
- package/components/stream/stream.js +8 -90
- package/components/swatch/class.js +131 -0
- package/components/swatch/swatch.d.ts +28 -0
- package/components/swatch/swatch.js +8 -112
- package/components/swiper/class.js +373 -0
- package/components/swiper/swiper.a2ui.json +4 -0
- package/components/swiper/swiper.d.ts +31 -0
- package/components/swiper/swiper.js +8 -354
- package/components/swiper/swiper.yaml +68 -212
- package/components/switch/class.js +63 -0
- package/components/switch/switch.a2ui.json +6 -1
- package/components/switch/switch.js +11 -47
- package/components/switch/switch.yaml +70 -265
- package/components/table/class.js +1453 -0
- package/components/table/table.d.ts +37 -0
- package/components/table/table.js +8 -1435
- package/components/table-toolbar/class.js +680 -0
- package/components/table-toolbar/table-toolbar.d.ts +33 -0
- package/components/table-toolbar/table-toolbar.js +8 -689
- package/components/tabs/class.js +242 -0
- package/components/tabs/tabs.d.ts +21 -0
- package/components/tabs/tabs.js +8 -223
- package/components/tag/class.js +99 -0
- package/components/tag/tag.d.ts +27 -0
- package/components/tag/tag.js +8 -80
- package/components/text/class.js +46 -0
- package/components/text/text.d.ts +25 -0
- package/components/text/text.js +9 -28
- package/components/textarea/class.js +134 -0
- package/components/textarea/textarea.js +11 -118
- package/components/timeline/class.js +176 -0
- package/components/timeline/timeline.d.ts +19 -0
- package/components/timeline/timeline.js +9 -162
- package/components/toast/class.js +92 -0
- package/components/toast/toast.d.ts +23 -0
- package/components/toast/toast.js +9 -76
- package/components/toggle-group/class.js +154 -0
- package/components/toggle-group/toggle-group.d.ts +19 -0
- package/components/toggle-group/toggle-group.js +11 -140
- package/components/toggle-scheme/class.js +286 -0
- package/components/toggle-scheme/toggle-scheme.d.ts +41 -0
- package/components/toggle-scheme/toggle-scheme.js +8 -268
- package/components/toolbar/class.js +388 -0
- package/components/toolbar/toolbar.d.ts +23 -0
- package/components/toolbar/toolbar.js +10 -376
- package/components/tooltip/class.js +299 -0
- package/components/tooltip/tooltip.d.ts +27 -0
- package/components/tooltip/tooltip.js +8 -280
- package/components/tree/class.js +245 -0
- package/components/tree/tree.d.ts +15 -0
- package/components/tree/tree.js +9 -244
- package/components/upload/class.js +199 -0
- package/components/upload/upload.js +11 -183
- package/index.d.ts +159 -5
- package/package.json +5 -1
|
@@ -1,147 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* <toggle-option-ui value="bold" icon="text-b"></toggle-option-ui>
|
|
4
|
-
* <toggle-option-ui value="italic" icon="text-italic"></toggle-option-ui>
|
|
5
|
-
* <toggle-option-ui value="underline" icon="text-underline"></toggle-option-ui>
|
|
6
|
-
* </toggle-group-ui>
|
|
2
|
+
* `<toggle-option-ui>` — auto-registers the tag on import.
|
|
7
3
|
*
|
|
8
|
-
*
|
|
4
|
+
* For non-side-effect class import (test isolation, tag override), use
|
|
5
|
+
* the `class` subpath:
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* import { UIToggleOption, UIToggleGroup } from '@adia-ai/web-components/components/toggle-group/class';
|
|
8
|
+
*
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
13
10
|
*/
|
|
14
11
|
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
// ── Toggle Option ──
|
|
18
|
-
//
|
|
19
|
-
// Parent-managed. Selection state flows through `toggle-group-ui`'s `value`
|
|
20
|
-
// (and `single` mode flag). Items don't expose `checked` — parent applies
|
|
21
|
-
// `data-selected` on the DOM element when the item's `value` is part of the
|
|
22
|
-
// group's comma-separated `value` list. Consistent with native `<option>`
|
|
23
|
-
// inside `<select>`.
|
|
24
|
-
|
|
25
|
-
class UIToggleOption extends UIElement {
|
|
26
|
-
static properties = {
|
|
27
|
-
value: { type: String, default: '', reflect: true },
|
|
28
|
-
text: { type: String, default: '', reflect: true },
|
|
29
|
-
icon: { type: String, default: '', reflect: true },
|
|
30
|
-
disabled: { type: Boolean, default: false, reflect: true },
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
static template = () => null;
|
|
34
|
-
|
|
35
|
-
#stamped = false;
|
|
36
|
-
|
|
37
|
-
connected() {
|
|
38
|
-
this.setAttribute('role', 'button');
|
|
39
|
-
this.setAttribute('tabindex', '0');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
render() {
|
|
43
|
-
if (!this.#stamped) {
|
|
44
|
-
this.#stamped = true;
|
|
45
|
-
this.#stamp();
|
|
46
|
-
}
|
|
47
|
-
if (this.disabled) this.setAttribute('aria-disabled', 'true');
|
|
48
|
-
else this.removeAttribute('aria-disabled');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
#stamp() {
|
|
52
|
-
let inner = '';
|
|
53
|
-
if (this.icon) inner += `<icon-ui name="${this.icon}"></icon-ui>`;
|
|
54
|
-
if (this.text) inner += `<span data-text>${this.text}</span>`;
|
|
55
|
-
this.innerHTML = inner;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
disconnected() {
|
|
59
|
-
this.#stamped = false;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
customElements.define('toggle-option-ui', UIToggleOption);
|
|
63
|
-
|
|
64
|
-
// ── Toggle Group ──
|
|
65
|
-
|
|
66
|
-
class UIToggleGroup extends UIElement {
|
|
67
|
-
static properties = {
|
|
68
|
-
value: { type: String, default: '', reflect: true },
|
|
69
|
-
single: { type: Boolean, default: false, reflect: true },
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
static template = () => null;
|
|
73
|
-
|
|
74
|
-
#bound = false;
|
|
75
|
-
|
|
76
|
-
get #valueSet() {
|
|
77
|
-
return new Set(this.value ? this.value.split(',').map(v => v.trim()).filter(Boolean) : []);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
connected() {
|
|
81
|
-
if (!this.#bound) {
|
|
82
|
-
this.#bound = true;
|
|
83
|
-
this.addEventListener('click', this.#onClick);
|
|
84
|
-
this.addEventListener('keydown', this.#onKey);
|
|
85
|
-
}
|
|
86
|
-
this.setAttribute('role', 'group');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
render() {
|
|
90
|
-
const selected = this.#valueSet;
|
|
91
|
-
for (const opt of this.querySelectorAll('toggle-option-ui')) {
|
|
92
|
-
const optVal = opt.value || opt.getAttribute('value') || '';
|
|
93
|
-
if (selected.has(optVal)) {
|
|
94
|
-
opt.setAttribute('data-selected', '');
|
|
95
|
-
opt.setAttribute('aria-pressed', 'true');
|
|
96
|
-
} else {
|
|
97
|
-
opt.removeAttribute('data-selected');
|
|
98
|
-
opt.setAttribute('aria-pressed', 'false');
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
#toggle(opt) {
|
|
104
|
-
if (opt.disabled) return;
|
|
105
|
-
const optVal = opt.value || opt.getAttribute('value') || '';
|
|
106
|
-
if (!optVal) return;
|
|
107
|
-
|
|
108
|
-
const selected = this.#valueSet;
|
|
109
|
-
|
|
110
|
-
if (this.single) {
|
|
111
|
-
if (selected.has(optVal)) {
|
|
112
|
-
selected.clear();
|
|
113
|
-
} else {
|
|
114
|
-
selected.clear();
|
|
115
|
-
selected.add(optVal);
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
if (selected.has(optVal)) selected.delete(optVal);
|
|
119
|
-
else selected.add(optVal);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
this.value = [...selected].join(',');
|
|
123
|
-
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
#onClick = (e) => {
|
|
127
|
-
const opt = e.target.closest('toggle-option-ui');
|
|
128
|
-
if (opt && this.contains(opt)) this.#toggle(opt);
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
#onKey = (e) => {
|
|
132
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
133
|
-
e.preventDefault();
|
|
134
|
-
const opt = e.target.closest('toggle-option-ui');
|
|
135
|
-
if (opt && this.contains(opt)) this.#toggle(opt);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIToggleOption, UIToggleGroup } from './class.js';
|
|
138
14
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.removeEventListener('keydown', this.#onKey);
|
|
142
|
-
this.#bound = false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
customElements.define('toggle-group-ui', UIToggleGroup);
|
|
15
|
+
defineIfFree('toggle-option-ui', UIToggleOption);
|
|
16
|
+
defineIfFree('toggle-group-ui', UIToggleGroup);
|
|
146
17
|
|
|
147
|
-
export {
|
|
18
|
+
export { UIToggleOption, UIToggleGroup };
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-side-effect class export for `<toggle-scheme-ui>`.
|
|
3
|
+
*
|
|
4
|
+
* Importing this file gives you the class(es) without auto-registering the tag.
|
|
5
|
+
* Useful for test isolation, subclassing with tag-name override, or selective
|
|
6
|
+
* composition.
|
|
7
|
+
*
|
|
8
|
+
* The auto-register path stays at `@adia-ai/web-components/components/toggle-scheme`
|
|
9
|
+
* (which imports this file + calls `defineIfFree()`).
|
|
10
|
+
*
|
|
11
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* <toggle-scheme-ui>
|
|
16
|
+
*
|
|
17
|
+
* Icon-button primitive that toggles `color-scheme` between light and dark
|
|
18
|
+
* on a target element (default `:root`). Replaces the hand-wired
|
|
19
|
+
* `<button-ui id="theme-toggle"> + applyScheme()` boilerplate previously
|
|
20
|
+
* duplicated across apps/genui, apps/construct-canvas, playgrounds/chat.
|
|
21
|
+
*
|
|
22
|
+
* Composition: light-DOM host, internally stamps a single <button-ui>.
|
|
23
|
+
*
|
|
24
|
+
* Authoring API:
|
|
25
|
+
* [scheme="auto"|"light"|"dark"] initial scheme (default "auto")
|
|
26
|
+
* [target=":root"] CSS selector for target element
|
|
27
|
+
* [persist] write selection to localStorage
|
|
28
|
+
* [storage-prefix="adia-theme-"] LS key namespace (matches theme-panel)
|
|
29
|
+
* [icon-light="sun"] icon shown when active-scheme is light
|
|
30
|
+
* [icon-dark="moon"] icon shown when active-scheme is dark
|
|
31
|
+
* [label-light] aria-label / title in light mode
|
|
32
|
+
* [label-dark] aria-label / title in dark mode
|
|
33
|
+
* [size="md"] forwarded to internal <button-ui>
|
|
34
|
+
* [variant="ghost"] forwarded to internal <button-ui>
|
|
35
|
+
* [color=""] forwarded to internal <button-ui>
|
|
36
|
+
* [disabled] forwarded to internal <button-ui>
|
|
37
|
+
*
|
|
38
|
+
* Reflected state (read-only externally; use .setScheme() to mutate):
|
|
39
|
+
* [active-scheme] resolved scheme ("light" | "dark")
|
|
40
|
+
*
|
|
41
|
+
* Events:
|
|
42
|
+
* scheme-change — bubbles. detail: { scheme, source }
|
|
43
|
+
* source ∈ "press" | "media" | "programmatic"
|
|
44
|
+
*
|
|
45
|
+
* Public methods:
|
|
46
|
+
* .toggle() flip between light and dark (defeats auto)
|
|
47
|
+
* .setScheme(s) "light" | "dark" | "auto"; programmatic write
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
import { UIElement } from '../../core/element.js';
|
|
51
|
+
import '../button/button.js';
|
|
52
|
+
|
|
53
|
+
const LIGHT = 'light';
|
|
54
|
+
const DARK = 'dark';
|
|
55
|
+
const AUTO = 'auto';
|
|
56
|
+
|
|
57
|
+
export class UIToggleScheme extends UIElement {
|
|
58
|
+
static properties = {
|
|
59
|
+
scheme: { type: String, default: AUTO, reflect: true },
|
|
60
|
+
target: { type: String, default: ':root', reflect: true },
|
|
61
|
+
persist: { type: Boolean, default: false, reflect: true },
|
|
62
|
+
storagePrefix: { type: String, default: 'adia-theme-', reflect: true, attribute: 'storage-prefix' },
|
|
63
|
+
iconLight: { type: String, default: 'sun', reflect: true, attribute: 'icon-light' },
|
|
64
|
+
iconDark: { type: String, default: 'moon', reflect: true, attribute: 'icon-dark' },
|
|
65
|
+
labelLight: { type: String, default: 'Switch to dark mode', reflect: true, attribute: 'label-light' },
|
|
66
|
+
labelDark: { type: String, default: 'Switch to light mode', reflect: true, attribute: 'label-dark' },
|
|
67
|
+
size: { type: String, default: 'md', reflect: true },
|
|
68
|
+
variant: { type: String, default: 'ghost', reflect: true },
|
|
69
|
+
color: { type: String, default: '', reflect: true },
|
|
70
|
+
disabled: { type: Boolean, default: false, reflect: true },
|
|
71
|
+
activeScheme: { type: String, default: '', reflect: true, attribute: 'active-scheme' },
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
static template = () => null;
|
|
75
|
+
|
|
76
|
+
#button = null;
|
|
77
|
+
#mql = null;
|
|
78
|
+
#mqlHandler = null;
|
|
79
|
+
#onPress = null;
|
|
80
|
+
#stamped = false;
|
|
81
|
+
|
|
82
|
+
connected() {
|
|
83
|
+
if (!this.#stamped) {
|
|
84
|
+
this.#stamp();
|
|
85
|
+
this.#stamped = true;
|
|
86
|
+
}
|
|
87
|
+
this.#initState();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
disconnected() {
|
|
91
|
+
if (this.#button && this.#onPress) {
|
|
92
|
+
this.#button.removeEventListener('press', this.#onPress);
|
|
93
|
+
}
|
|
94
|
+
this.#detachPcm();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ── Public API ──────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
/** Flip between light and dark — defeats auto. */
|
|
100
|
+
toggle() {
|
|
101
|
+
const next = this.activeScheme === DARK ? LIGHT : DARK;
|
|
102
|
+
this.#apply(next, 'programmatic');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* @param {"light"|"dark"|"auto"} s
|
|
107
|
+
*/
|
|
108
|
+
setScheme(s) {
|
|
109
|
+
if (s === AUTO) {
|
|
110
|
+
this.#clearTargetOverride();
|
|
111
|
+
const resolved = this.#resolvePrefersScheme();
|
|
112
|
+
this.activeScheme = resolved;
|
|
113
|
+
this.#syncButton();
|
|
114
|
+
this.#attachPcm();
|
|
115
|
+
this.#emit('programmatic');
|
|
116
|
+
} else if (s === LIGHT || s === DARK) {
|
|
117
|
+
this.#apply(s, 'programmatic');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Internal — stamping ─────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
#stamp() {
|
|
124
|
+
const btn = document.createElement('button-ui');
|
|
125
|
+
btn.setAttribute('part', 'button');
|
|
126
|
+
btn.setAttribute('variant', this.variant || 'ghost');
|
|
127
|
+
btn.setAttribute('size', this.size || 'md');
|
|
128
|
+
if (this.color) btn.setAttribute('color', this.color);
|
|
129
|
+
if (this.disabled) btn.setAttribute('disabled', '');
|
|
130
|
+
this.appendChild(btn);
|
|
131
|
+
|
|
132
|
+
this.#button = btn;
|
|
133
|
+
this.#onPress = (e) => {
|
|
134
|
+
// Internal button bubbles 'press'; we re-emit our own 'scheme-change'
|
|
135
|
+
// so consumers see one semantic event, not the inner button's.
|
|
136
|
+
e.stopPropagation();
|
|
137
|
+
if (this.disabled) return;
|
|
138
|
+
const next = this.activeScheme === DARK ? LIGHT : DARK;
|
|
139
|
+
this.#apply(next, 'press');
|
|
140
|
+
};
|
|
141
|
+
btn.addEventListener('press', this.#onPress);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ── Internal — initial state ────────────────────────────────────────
|
|
145
|
+
|
|
146
|
+
#initState() {
|
|
147
|
+
// Priority: persisted > [scheme] attr > auto
|
|
148
|
+
let initial = null;
|
|
149
|
+
if (this.persist) {
|
|
150
|
+
try {
|
|
151
|
+
const v = localStorage.getItem(`${this.storagePrefix}scheme`);
|
|
152
|
+
if (v === LIGHT || v === DARK) initial = v;
|
|
153
|
+
} catch {}
|
|
154
|
+
}
|
|
155
|
+
if (initial === null) {
|
|
156
|
+
const attr = (this.scheme || AUTO);
|
|
157
|
+
if (attr === LIGHT || attr === DARK) initial = attr;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (initial === LIGHT || initial === DARK) {
|
|
161
|
+
// Explicit choice — write to target, no MQL listening
|
|
162
|
+
this.#writeTarget(initial);
|
|
163
|
+
this.activeScheme = initial;
|
|
164
|
+
} else {
|
|
165
|
+
// Auto — follow prefers-color-scheme, attach listener
|
|
166
|
+
this.activeScheme = this.#resolvePrefersScheme();
|
|
167
|
+
this.#attachPcm();
|
|
168
|
+
}
|
|
169
|
+
this.#syncButton();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ── Internal — mutation (single path) ───────────────────────────────
|
|
173
|
+
|
|
174
|
+
#apply(next, source) {
|
|
175
|
+
if (next !== LIGHT && next !== DARK) return;
|
|
176
|
+
this.#writeTarget(next);
|
|
177
|
+
this.activeScheme = next;
|
|
178
|
+
if (this.persist) {
|
|
179
|
+
try { localStorage.setItem(`${this.storagePrefix}scheme`, next); } catch {}
|
|
180
|
+
}
|
|
181
|
+
// User picked explicitly — stop tracking OS preference
|
|
182
|
+
this.#detachPcm();
|
|
183
|
+
this.#syncButton();
|
|
184
|
+
this.#emit(source);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
#syncButton() {
|
|
188
|
+
if (!this.#button) return;
|
|
189
|
+
const dark = this.activeScheme === DARK;
|
|
190
|
+
const icon = dark ? this.iconDark : this.iconLight;
|
|
191
|
+
const label = dark ? this.labelDark : this.labelLight;
|
|
192
|
+
if (this.#button.getAttribute('icon') !== icon) {
|
|
193
|
+
this.#button.setAttribute('icon', icon);
|
|
194
|
+
}
|
|
195
|
+
this.#button.setAttribute('aria-label', label);
|
|
196
|
+
this.#button.setAttribute('title', label);
|
|
197
|
+
// Forward style passthrough so authors can change variant/size/color
|
|
198
|
+
// at runtime and the internal button reflects it.
|
|
199
|
+
if (this.#button.getAttribute('variant') !== this.variant) {
|
|
200
|
+
this.#button.setAttribute('variant', this.variant || 'ghost');
|
|
201
|
+
}
|
|
202
|
+
if (this.#button.getAttribute('size') !== this.size) {
|
|
203
|
+
this.#button.setAttribute('size', this.size || 'md');
|
|
204
|
+
}
|
|
205
|
+
if (this.color) {
|
|
206
|
+
this.#button.setAttribute('color', this.color);
|
|
207
|
+
} else {
|
|
208
|
+
this.#button.removeAttribute('color');
|
|
209
|
+
}
|
|
210
|
+
if (this.disabled) {
|
|
211
|
+
this.#button.setAttribute('disabled', '');
|
|
212
|
+
} else {
|
|
213
|
+
this.#button.removeAttribute('disabled');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
render() {
|
|
218
|
+
// Property writes after connect (e.g. el.size = 'sm') route through here.
|
|
219
|
+
this.#syncButton();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
#emit(source) {
|
|
223
|
+
this.dispatchEvent(new CustomEvent('scheme-change', {
|
|
224
|
+
bubbles: true,
|
|
225
|
+
detail: { scheme: this.activeScheme, source },
|
|
226
|
+
}));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ── Internal — target resolution + write ────────────────────────────
|
|
230
|
+
|
|
231
|
+
#resolveTarget() {
|
|
232
|
+
const sel = this.target || ':root';
|
|
233
|
+
if (sel === ':root') return document.documentElement;
|
|
234
|
+
try {
|
|
235
|
+
return document.querySelector(sel) ?? document.documentElement;
|
|
236
|
+
} catch {
|
|
237
|
+
return document.documentElement;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
#writeTarget(scheme) {
|
|
242
|
+
const t = this.#resolveTarget();
|
|
243
|
+
t.style.setProperty('color-scheme', scheme);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
#clearTargetOverride() {
|
|
247
|
+
const t = this.#resolveTarget();
|
|
248
|
+
t.style.removeProperty('color-scheme');
|
|
249
|
+
if (this.persist) {
|
|
250
|
+
try { localStorage.removeItem(`${this.storagePrefix}scheme`); } catch {}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ── Internal — prefers-color-scheme ─────────────────────────────────
|
|
255
|
+
|
|
256
|
+
#resolvePrefersScheme() {
|
|
257
|
+
try {
|
|
258
|
+
if (typeof matchMedia === 'function' &&
|
|
259
|
+
matchMedia('(prefers-color-scheme: dark)').matches) return DARK;
|
|
260
|
+
} catch {}
|
|
261
|
+
return LIGHT;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#attachPcm() {
|
|
265
|
+
if (this.#mql || typeof matchMedia !== 'function') return;
|
|
266
|
+
try {
|
|
267
|
+
this.#mql = matchMedia('(prefers-color-scheme: dark)');
|
|
268
|
+
this.#mqlHandler = () => {
|
|
269
|
+
const resolved = this.#mql.matches ? DARK : LIGHT;
|
|
270
|
+
if (resolved === this.activeScheme) return;
|
|
271
|
+
this.activeScheme = resolved;
|
|
272
|
+
this.#syncButton();
|
|
273
|
+
this.#emit('media');
|
|
274
|
+
};
|
|
275
|
+
this.#mql.addEventListener('change', this.#mqlHandler);
|
|
276
|
+
} catch {}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#detachPcm() {
|
|
280
|
+
if (this.#mql && this.#mqlHandler) {
|
|
281
|
+
try { this.#mql.removeEventListener('change', this.#mqlHandler); } catch {}
|
|
282
|
+
}
|
|
283
|
+
this.#mql = null;
|
|
284
|
+
this.#mqlHandler = null;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<toggle-scheme-ui>` — Icon-button primitive that toggles `color-scheme` between light and dark on a target element (default `:root`). Encapsulates the prefers-color-scheme initial-resolution, the inline-style write to the target, optional localStorage persistence (sharing the `adia-theme-` namespace with <theme-panel>), and the moon/sun icon swap. Replaces the hand-wired `<button-ui id="theme-toggle">` + `applyScheme()` pattern previously duplicated across apps/genui, apps/construct-canvas, playgrounds/chat.
|
|
3
|
+
*
|
|
4
|
+
* @see https://ui-kit.exe.xyz/site/components/toggle-scheme
|
|
5
|
+
*
|
|
6
|
+
* Type declarations generated by scripts/build/dts-codegen.mjs from
|
|
7
|
+
* the component's `.a2ui.json` sidecar. Edit the source `.yaml`,
|
|
8
|
+
* run `npm run components`, then `npm run codegen:dts` to regenerate;
|
|
9
|
+
* or hand-author this file fully if rich event types are needed.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { UIElement } from '../../core/element.js';
|
|
13
|
+
|
|
14
|
+
export class UIToggleScheme extends UIElement {
|
|
15
|
+
/** Resolved scheme ("light" | "dark"). Read-only; mutate via .setScheme() or .toggle(). */
|
|
16
|
+
activeScheme: '' | 'light' | 'dark';
|
|
17
|
+
/** Semantic intent forwarded to the internal <button-ui>. */
|
|
18
|
+
color: '' | 'default' | 'accent' | 'info' | 'success' | 'warning' | 'danger';
|
|
19
|
+
/** Disables the internal button. */
|
|
20
|
+
disabled: boolean;
|
|
21
|
+
/** Phosphor icon shown when active-scheme is "dark" (clicking switches to light). */
|
|
22
|
+
iconDark: string;
|
|
23
|
+
/** Phosphor icon shown when active-scheme is "light" (clicking switches to dark). */
|
|
24
|
+
iconLight: string;
|
|
25
|
+
/** aria-label / title applied to the internal button when active-scheme is "dark". */
|
|
26
|
+
labelDark: string;
|
|
27
|
+
/** aria-label / title applied to the internal button when active-scheme is "light". */
|
|
28
|
+
labelLight: string;
|
|
29
|
+
/** Persist the user's choice to localStorage under `${storage-prefix}scheme`. */
|
|
30
|
+
persist: boolean;
|
|
31
|
+
/** Initial scheme — "auto" follows prefers-color-scheme; "light" / "dark" force. */
|
|
32
|
+
scheme: 'auto' | 'light' | 'dark';
|
|
33
|
+
/** Sizing scale forwarded to the internal <button-ui>. */
|
|
34
|
+
size: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
35
|
+
/** LocalStorage key prefix; default matches <theme-panel> for cross-element interop. */
|
|
36
|
+
storagePrefix: string;
|
|
37
|
+
/** CSS selector for the element receiving `color-scheme`. ":root" → <html>. */
|
|
38
|
+
target: string;
|
|
39
|
+
/** Visual style forwarded to the internal <button-ui>. Defaults to "ghost" (matches app practice). */
|
|
40
|
+
variant: 'default' | 'solid' | 'outline' | 'ghost' | 'primary' | 'secondary' | 'soft';
|
|
41
|
+
}
|