@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
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-side-effect class export for `<rating-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/rating`
|
|
9
|
+
* (which imports this file + calls `defineIfFree()`).
|
|
10
|
+
*
|
|
11
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* <rating-ui> — Discrete pictorial rating (stars by default).
|
|
16
|
+
*
|
|
17
|
+
* Supports keyboard (arrows), mouse hover preview, and 0.5-step precision.
|
|
18
|
+
* The host is role=slider per ARIA APG for custom rating widgets.
|
|
19
|
+
*
|
|
20
|
+
* <rating-ui value="3.5" max="5" allow-half name="review"></rating-ui>
|
|
21
|
+
* <rating-ui value="4" icon="heart" variant="accent"></rating-ui>
|
|
22
|
+
* <rating-ui value="5" readonly></rating-ui>
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { UIFormElement } from '../../core/form.js';
|
|
26
|
+
|
|
27
|
+
export class UIRating extends UIFormElement {
|
|
28
|
+
static properties = {
|
|
29
|
+
...UIFormElement.properties,
|
|
30
|
+
/** value: Number — overrides UIFormElement.value (String); syncs as string on form submit. */
|
|
31
|
+
value: { type: Number, default: 0, reflect: true },
|
|
32
|
+
max: { type: Number, default: 5, reflect: true },
|
|
33
|
+
icon: { type: String, default: 'star', reflect: true },
|
|
34
|
+
readonly: { type: Boolean, default: false, reflect: true },
|
|
35
|
+
allowHalf: { type: Boolean, default: false, reflect: true, attribute: 'allow-half' },
|
|
36
|
+
size: { type: String, default: 'md', reflect: true },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
static template = () => null;
|
|
40
|
+
|
|
41
|
+
#hoverValue = null;
|
|
42
|
+
|
|
43
|
+
connected() {
|
|
44
|
+
super.connected();
|
|
45
|
+
this.setAttribute('role', 'slider');
|
|
46
|
+
this.setAttribute('aria-orientation', 'horizontal');
|
|
47
|
+
this.setAttribute('aria-valuemin', '0');
|
|
48
|
+
if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', this.readonly ? '-1' : '0');
|
|
49
|
+
this.addEventListener('pointermove', this.#onPointer);
|
|
50
|
+
this.addEventListener('pointerleave', this.#onLeave);
|
|
51
|
+
this.addEventListener('click', this.#onClick);
|
|
52
|
+
this.addEventListener('keydown', this.#onKey);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
render() {
|
|
56
|
+
const max = Number(this.max) || 5;
|
|
57
|
+
const display = this.#hoverValue ?? (Number(this.value) || 0);
|
|
58
|
+
|
|
59
|
+
const symbols = Array.from({ length: max }, (_, i) => {
|
|
60
|
+
const slotValue = i + 1;
|
|
61
|
+
const fill =
|
|
62
|
+
display >= slotValue ? 'full' :
|
|
63
|
+
display >= slotValue - 0.5 ? 'half' :
|
|
64
|
+
'empty';
|
|
65
|
+
return `
|
|
66
|
+
<span data-rating-symbol data-fill="${fill}" aria-hidden="true">
|
|
67
|
+
<icon-ui name="${this.icon}" data-rating-symbol-bg></icon-ui>
|
|
68
|
+
<icon-ui name="${this.icon}" weight="fill" data-rating-symbol-fg></icon-ui>
|
|
69
|
+
</span>
|
|
70
|
+
`;
|
|
71
|
+
}).join('');
|
|
72
|
+
|
|
73
|
+
this.innerHTML = symbols;
|
|
74
|
+
this.setAttribute('aria-valuemax', String(max));
|
|
75
|
+
this.setAttribute('aria-valuenow', String(Number(this.value) || 0));
|
|
76
|
+
this.setAttribute('aria-valuetext', `${Number(this.value) || 0} out of ${max}`);
|
|
77
|
+
if (this.readonly) this.setAttribute('aria-readonly', 'true');
|
|
78
|
+
else this.removeAttribute('aria-readonly');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#valueFromEvent(e) {
|
|
82
|
+
const symbols = [...this.querySelectorAll('[data-rating-symbol]')];
|
|
83
|
+
const target = symbols.find(s => s.contains(e.target));
|
|
84
|
+
if (!target) return null;
|
|
85
|
+
const idx = symbols.indexOf(target);
|
|
86
|
+
if (idx === -1) return null;
|
|
87
|
+
if (this.allowHalf) {
|
|
88
|
+
const rect = target.getBoundingClientRect();
|
|
89
|
+
const isHalf = (e.clientX - rect.left) < rect.width / 2;
|
|
90
|
+
return idx + (isHalf ? 0.5 : 1);
|
|
91
|
+
}
|
|
92
|
+
return idx + 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#onPointer = (e) => {
|
|
96
|
+
if (this.readonly || this.disabled) return;
|
|
97
|
+
const v = this.#valueFromEvent(e);
|
|
98
|
+
if (v == null) return;
|
|
99
|
+
if (v !== this.#hoverValue) {
|
|
100
|
+
this.#hoverValue = v;
|
|
101
|
+
this.render();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
#onLeave = () => {
|
|
106
|
+
if (this.#hoverValue == null) return;
|
|
107
|
+
this.#hoverValue = null;
|
|
108
|
+
this.render();
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
#onClick = (e) => {
|
|
112
|
+
if (this.readonly || this.disabled) return;
|
|
113
|
+
const v = this.#valueFromEvent(e);
|
|
114
|
+
if (v == null) return;
|
|
115
|
+
this.#commit(v);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
#onKey = (e) => {
|
|
119
|
+
if (this.readonly || this.disabled) return;
|
|
120
|
+
const step = this.allowHalf ? 0.5 : 1;
|
|
121
|
+
const max = Number(this.max) || 5;
|
|
122
|
+
const v = Number(this.value) || 0;
|
|
123
|
+
let next = v;
|
|
124
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { next = Math.min(max, v + step); }
|
|
125
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { next = Math.max(0, v - step); }
|
|
126
|
+
else if (e.key === 'Home') next = 0;
|
|
127
|
+
else if (e.key === 'End') next = max;
|
|
128
|
+
else return;
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
this.#commit(next);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
#commit(v) {
|
|
134
|
+
this.value = v;
|
|
135
|
+
this.#hoverValue = null;
|
|
136
|
+
this.syncValue(String(v));
|
|
137
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
138
|
+
this.render();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
disconnected() {
|
|
142
|
+
super.disconnected();
|
|
143
|
+
this.removeEventListener('pointermove', this.#onPointer);
|
|
144
|
+
this.removeEventListener('pointerleave', this.#onLeave);
|
|
145
|
+
this.removeEventListener('click', this.#onClick);
|
|
146
|
+
this.removeEventListener('keydown', this.#onKey);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -1,138 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* `<rating-ui>` — auto-registers the tag on import.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* For non-side-effect class import (test isolation, tag override), use
|
|
5
|
+
* the `class` subpath:
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* import { UIRating } from '@adia-ai/web-components/components/rating/class';
|
|
8
|
+
*
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
class UIRating extends UIFormElement {
|
|
15
|
-
static properties = {
|
|
16
|
-
...UIFormElement.properties,
|
|
17
|
-
/** value: Number — overrides UIFormElement.value (String); syncs as string on form submit. */
|
|
18
|
-
value: { type: Number, default: 0, reflect: true },
|
|
19
|
-
max: { type: Number, default: 5, reflect: true },
|
|
20
|
-
icon: { type: String, default: 'star', reflect: true },
|
|
21
|
-
readonly: { type: Boolean, default: false, reflect: true },
|
|
22
|
-
allowHalf: { type: Boolean, default: false, reflect: true, attribute: 'allow-half' },
|
|
23
|
-
size: { type: String, default: 'md', reflect: true },
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
static template = () => null;
|
|
27
|
-
|
|
28
|
-
#hoverValue = null;
|
|
29
|
-
|
|
30
|
-
connected() {
|
|
31
|
-
super.connected();
|
|
32
|
-
this.setAttribute('role', 'slider');
|
|
33
|
-
this.setAttribute('aria-orientation', 'horizontal');
|
|
34
|
-
this.setAttribute('aria-valuemin', '0');
|
|
35
|
-
if (!this.hasAttribute('tabindex')) this.setAttribute('tabindex', this.readonly ? '-1' : '0');
|
|
36
|
-
this.addEventListener('pointermove', this.#onPointer);
|
|
37
|
-
this.addEventListener('pointerleave', this.#onLeave);
|
|
38
|
-
this.addEventListener('click', this.#onClick);
|
|
39
|
-
this.addEventListener('keydown', this.#onKey);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
render() {
|
|
43
|
-
const max = Number(this.max) || 5;
|
|
44
|
-
const display = this.#hoverValue ?? (Number(this.value) || 0);
|
|
45
|
-
|
|
46
|
-
const symbols = Array.from({ length: max }, (_, i) => {
|
|
47
|
-
const slotValue = i + 1;
|
|
48
|
-
const fill =
|
|
49
|
-
display >= slotValue ? 'full' :
|
|
50
|
-
display >= slotValue - 0.5 ? 'half' :
|
|
51
|
-
'empty';
|
|
52
|
-
return `
|
|
53
|
-
<span data-rating-symbol data-fill="${fill}" aria-hidden="true">
|
|
54
|
-
<icon-ui name="${this.icon}" data-rating-symbol-bg></icon-ui>
|
|
55
|
-
<icon-ui name="${this.icon}" weight="fill" data-rating-symbol-fg></icon-ui>
|
|
56
|
-
</span>
|
|
57
|
-
`;
|
|
58
|
-
}).join('');
|
|
59
|
-
|
|
60
|
-
this.innerHTML = symbols;
|
|
61
|
-
this.setAttribute('aria-valuemax', String(max));
|
|
62
|
-
this.setAttribute('aria-valuenow', String(Number(this.value) || 0));
|
|
63
|
-
this.setAttribute('aria-valuetext', `${Number(this.value) || 0} out of ${max}`);
|
|
64
|
-
if (this.readonly) this.setAttribute('aria-readonly', 'true');
|
|
65
|
-
else this.removeAttribute('aria-readonly');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
#valueFromEvent(e) {
|
|
69
|
-
const symbols = [...this.querySelectorAll('[data-rating-symbol]')];
|
|
70
|
-
const target = symbols.find(s => s.contains(e.target));
|
|
71
|
-
if (!target) return null;
|
|
72
|
-
const idx = symbols.indexOf(target);
|
|
73
|
-
if (idx === -1) return null;
|
|
74
|
-
if (this.allowHalf) {
|
|
75
|
-
const rect = target.getBoundingClientRect();
|
|
76
|
-
const isHalf = (e.clientX - rect.left) < rect.width / 2;
|
|
77
|
-
return idx + (isHalf ? 0.5 : 1);
|
|
78
|
-
}
|
|
79
|
-
return idx + 1;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
#onPointer = (e) => {
|
|
83
|
-
if (this.readonly || this.disabled) return;
|
|
84
|
-
const v = this.#valueFromEvent(e);
|
|
85
|
-
if (v == null) return;
|
|
86
|
-
if (v !== this.#hoverValue) {
|
|
87
|
-
this.#hoverValue = v;
|
|
88
|
-
this.render();
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
#onLeave = () => {
|
|
93
|
-
if (this.#hoverValue == null) return;
|
|
94
|
-
this.#hoverValue = null;
|
|
95
|
-
this.render();
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
#onClick = (e) => {
|
|
99
|
-
if (this.readonly || this.disabled) return;
|
|
100
|
-
const v = this.#valueFromEvent(e);
|
|
101
|
-
if (v == null) return;
|
|
102
|
-
this.#commit(v);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
#onKey = (e) => {
|
|
106
|
-
if (this.readonly || this.disabled) return;
|
|
107
|
-
const step = this.allowHalf ? 0.5 : 1;
|
|
108
|
-
const max = Number(this.max) || 5;
|
|
109
|
-
const v = Number(this.value) || 0;
|
|
110
|
-
let next = v;
|
|
111
|
-
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') { next = Math.min(max, v + step); }
|
|
112
|
-
else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') { next = Math.max(0, v - step); }
|
|
113
|
-
else if (e.key === 'Home') next = 0;
|
|
114
|
-
else if (e.key === 'End') next = max;
|
|
115
|
-
else return;
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
this.#commit(next);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
#commit(v) {
|
|
121
|
-
this.value = v;
|
|
122
|
-
this.#hoverValue = null;
|
|
123
|
-
this.syncValue(String(v));
|
|
124
|
-
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
125
|
-
this.render();
|
|
126
|
-
}
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIRating } from './class.js';
|
|
127
14
|
|
|
128
|
-
|
|
129
|
-
super.disconnected();
|
|
130
|
-
this.removeEventListener('pointermove', this.#onPointer);
|
|
131
|
-
this.removeEventListener('pointerleave', this.#onLeave);
|
|
132
|
-
this.removeEventListener('click', this.#onClick);
|
|
133
|
-
this.removeEventListener('keydown', this.#onKey);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
15
|
+
defineIfFree('rating-ui', UIRating);
|
|
136
16
|
|
|
137
|
-
customElements.define('rating-ui', UIRating);
|
|
138
17
|
export { UIRating };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-side-effect class export for `<richtext-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/richtext`
|
|
9
|
+
* (which imports this file + calls `defineIfFree()`).
|
|
10
|
+
*
|
|
11
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { UIElement } from '../../core/element.js';
|
|
15
|
+
import { renderMarkdown } from '../../core/markdown.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* <richtext-ui> — Renders markdown to styled HTML.
|
|
19
|
+
*
|
|
20
|
+
* Takes markdown as a `src` URL (fetched) or `markdown` property (inline),
|
|
21
|
+
* converts it to HTML, and displays it with prose-appropriate typography.
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* <richtext-ui src="/docs/readme.md"></richtext-ui>
|
|
25
|
+
* <richtext-ui markdown="# Hello\nSome **bold** text."></richtext-ui>
|
|
26
|
+
*
|
|
27
|
+
* Programmatic:
|
|
28
|
+
* const el = document.querySelector('richtext-ui');
|
|
29
|
+
* el.markdown = '# Title\nParagraph text.';
|
|
30
|
+
*/
|
|
31
|
+
export class UIRichText extends UIElement {
|
|
32
|
+
static properties = {
|
|
33
|
+
src: { type: String, default: '', reflect: true },
|
|
34
|
+
// Markdown bodies can be arbitrarily large; reflecting to the attribute
|
|
35
|
+
// would bloat the DOM (and break parsing on multi-line content with
|
|
36
|
+
// unescaped quotes). The property is the source of truth.
|
|
37
|
+
markdown: { type: String, default: '', reflect: false },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
static template = () => null;
|
|
41
|
+
|
|
42
|
+
#bodyEl = null;
|
|
43
|
+
#lastSrc = '';
|
|
44
|
+
#lastMd = '';
|
|
45
|
+
|
|
46
|
+
connected() {
|
|
47
|
+
if (!this.#bodyEl) {
|
|
48
|
+
this.#bodyEl = document.createElement('div');
|
|
49
|
+
this.#bodyEl.setAttribute('data-richtext-body', '');
|
|
50
|
+
this.appendChild(this.#bodyEl);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
render() {
|
|
55
|
+
// Fetch from URL
|
|
56
|
+
if (this.src && this.src !== this.#lastSrc) {
|
|
57
|
+
this.#lastSrc = this.src;
|
|
58
|
+
this.#lastMd = '';
|
|
59
|
+
this.#load();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Inline markdown
|
|
64
|
+
if (this.markdown && this.markdown !== this.#lastMd) {
|
|
65
|
+
this.#lastMd = this.markdown;
|
|
66
|
+
this.#lastSrc = '';
|
|
67
|
+
this.#bodyEl.innerHTML = renderMarkdown(this.markdown);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async #load() {
|
|
72
|
+
try {
|
|
73
|
+
const res = await fetch(this.src);
|
|
74
|
+
if (!this.isConnected) return;
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
this.#bodyEl.innerHTML = `<p>Failed to load: ${this.src}</p>`;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const md = await res.text();
|
|
80
|
+
if (!this.isConnected) return;
|
|
81
|
+
this.#bodyEl.innerHTML = renderMarkdown(md);
|
|
82
|
+
} catch (e) {
|
|
83
|
+
if (!this.isConnected) return;
|
|
84
|
+
this.#bodyEl.innerHTML = `<p>Error: ${e.message}</p>`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<richtext-ui>` — Renders markdown to styled HTML.
|
|
3
|
+
*
|
|
4
|
+
* @see https://ui-kit.exe.xyz/site/components/richtext
|
|
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 UIRichtext extends UIElement {
|
|
15
|
+
/** Component property: markdown. */
|
|
16
|
+
markdown: string;
|
|
17
|
+
/** Source URL (image, iframe, etc.). */
|
|
18
|
+
src: string;
|
|
19
|
+
}
|
|
@@ -1,77 +1,17 @@
|
|
|
1
|
-
import { UIElement } from '../../core/element.js';
|
|
2
|
-
import { renderMarkdown } from '../../core/markdown.js';
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
|
-
*
|
|
2
|
+
* `<richtext-ui>` — auto-registers the tag on import.
|
|
6
3
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* For non-side-effect class import (test isolation, tag override), use
|
|
5
|
+
* the `class` subpath:
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
* <richtext-ui src="/docs/readme.md"></richtext-ui>
|
|
12
|
-
* <richtext-ui markdown="# Hello\nSome **bold** text."></richtext-ui>
|
|
7
|
+
* import { UIRichText } from '@adia-ai/web-components/components/richtext/class';
|
|
13
8
|
*
|
|
14
|
-
*
|
|
15
|
-
* const el = document.querySelector('richtext-ui');
|
|
16
|
-
* el.markdown = '# Title\nParagraph text.';
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
17
10
|
*/
|
|
18
|
-
class UIRichText extends UIElement {
|
|
19
|
-
static properties = {
|
|
20
|
-
src: { type: String, default: '', reflect: true },
|
|
21
|
-
// Markdown bodies can be arbitrarily large; reflecting to the attribute
|
|
22
|
-
// would bloat the DOM (and break parsing on multi-line content with
|
|
23
|
-
// unescaped quotes). The property is the source of truth.
|
|
24
|
-
markdown: { type: String, default: '', reflect: false },
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
static template = () => null;
|
|
28
|
-
|
|
29
|
-
#bodyEl = null;
|
|
30
|
-
#lastSrc = '';
|
|
31
|
-
#lastMd = '';
|
|
32
|
-
|
|
33
|
-
connected() {
|
|
34
|
-
if (!this.#bodyEl) {
|
|
35
|
-
this.#bodyEl = document.createElement('div');
|
|
36
|
-
this.#bodyEl.setAttribute('data-richtext-body', '');
|
|
37
|
-
this.appendChild(this.#bodyEl);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
render() {
|
|
42
|
-
// Fetch from URL
|
|
43
|
-
if (this.src && this.src !== this.#lastSrc) {
|
|
44
|
-
this.#lastSrc = this.src;
|
|
45
|
-
this.#lastMd = '';
|
|
46
|
-
this.#load();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
11
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.#lastMd = this.markdown;
|
|
53
|
-
this.#lastSrc = '';
|
|
54
|
-
this.#bodyEl.innerHTML = renderMarkdown(this.markdown);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIRichText } from './class.js';
|
|
57
14
|
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
const res = await fetch(this.src);
|
|
61
|
-
if (!this.isConnected) return;
|
|
62
|
-
if (!res.ok) {
|
|
63
|
-
this.#bodyEl.innerHTML = `<p>Failed to load: ${this.src}</p>`;
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const md = await res.text();
|
|
67
|
-
if (!this.isConnected) return;
|
|
68
|
-
this.#bodyEl.innerHTML = renderMarkdown(md);
|
|
69
|
-
} catch (e) {
|
|
70
|
-
if (!this.isConnected) return;
|
|
71
|
-
this.#bodyEl.innerHTML = `<p>Error: ${e.message}</p>`;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
15
|
+
defineIfFree('richtext-ui', UIRichText);
|
|
75
16
|
|
|
76
|
-
customElements.define('richtext-ui', UIRichText);
|
|
77
17
|
export { UIRichText };
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# Generated by scripts/migrate-yamls-to-v1.mjs — migrated to v1 contract.
|
|
2
|
-
# Edit this file; run `npm run build:components` to regenerate a2ui.json.
|
|
3
1
|
$schema: ../../../../scripts/schemas/component.yaml.schema.json
|
|
4
2
|
name: UIRichtext
|
|
5
3
|
tag: richtext-ui
|
|
@@ -9,81 +7,48 @@ version: 1
|
|
|
9
7
|
description: Renders markdown to styled HTML.
|
|
10
8
|
props:
|
|
11
9
|
markdown:
|
|
12
|
-
description:
|
|
10
|
+
description: 'Component property: markdown.'
|
|
13
11
|
type: string
|
|
14
|
-
default:
|
|
12
|
+
default: ''
|
|
15
13
|
src:
|
|
16
|
-
description:
|
|
14
|
+
description: Source URL (image, iframe, etc.).
|
|
17
15
|
type: string
|
|
18
|
-
default:
|
|
16
|
+
default: ''
|
|
19
17
|
events: {}
|
|
20
18
|
slots:
|
|
21
19
|
default:
|
|
22
|
-
description:
|
|
20
|
+
description: Default slot — primary child content.
|
|
23
21
|
states:
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
- name: idle
|
|
23
|
+
description: Default, ready for interaction.
|
|
26
24
|
traits: []
|
|
27
25
|
tokens: {}
|
|
28
26
|
a2ui:
|
|
29
27
|
rules: []
|
|
30
28
|
anti_patterns: []
|
|
31
29
|
examples:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
"id": "comp",
|
|
52
|
-
"component": "Richtext",
|
|
53
|
-
"src": "/images/example.jpg"
|
|
54
|
-
}
|
|
55
|
-
]
|
|
56
|
-
- name: markdown
|
|
57
|
-
description: Inline markdown text rendered to styled HTML via the markdown attribute.
|
|
58
|
-
a2ui: >-
|
|
59
|
-
[
|
|
60
|
-
{
|
|
61
|
-
"id": "root",
|
|
62
|
-
"component": "Richtext",
|
|
63
|
-
"markdown": "# Hello world\n\nWelcome to **AdiaUI**. This paragraph was parsed from markdown:\n\n- Lists\n- Render\n- Cleanly\n\n`inline code` and [links](https://example.com) work too."
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
- name: src
|
|
67
|
-
description: Fetch a remote markdown file via src and render it; useful for docs pages.
|
|
68
|
-
a2ui: >-
|
|
69
|
-
[
|
|
70
|
-
{
|
|
71
|
-
"id": "root",
|
|
72
|
-
"component": "Richtext",
|
|
73
|
-
"src": "/README.md"
|
|
74
|
-
}
|
|
75
|
-
]
|
|
76
|
-
- name: code-blocks
|
|
77
|
-
description: Richtext with fenced code blocks; whitespace preserved and monospace styling applied.
|
|
78
|
-
a2ui: >-
|
|
79
|
-
[
|
|
80
|
-
{
|
|
81
|
-
"id": "root",
|
|
82
|
-
"component": "Richtext",
|
|
83
|
-
"markdown": "## Example\n\n```js\nfunction greet(name) {\n return `Hello, ${name}!`;\n}\n```\n\nInline `code` also works."
|
|
84
|
-
}
|
|
85
|
-
]
|
|
30
|
+
- name: basic-richtext
|
|
31
|
+
description: Basic Richtext usage
|
|
32
|
+
a2ui: "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\"\n ]\n },\n {\n\
|
|
33
|
+
\ \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"comp\"\n ]\n },\n {\n \"\
|
|
34
|
+
id\": \"comp\",\n \"component\": \"Richtext\",\n \"src\": \"/images/example.jpg\"\n }\n]"
|
|
35
|
+
- name: markdown
|
|
36
|
+
description: Inline markdown text rendered to styled HTML via the markdown attribute.
|
|
37
|
+
a2ui: "[\n {\n \"id\": \"root\",\n \"component\": \"Richtext\",\n \"markdown\": \"# Hello world\\n\\nWelcome to\
|
|
38
|
+
\ **AdiaUI**. This paragraph was parsed from markdown:\\n\\n- Lists\\n- Render\\n- Cleanly\\n\\n`inline code` and [links](https://example.com)\
|
|
39
|
+
\ work too.\"\n }\n]"
|
|
40
|
+
- name: src
|
|
41
|
+
description: Fetch a remote markdown file via src and render it; useful for docs pages.
|
|
42
|
+
a2ui: "[\n {\n \"id\": \"root\",\n \"component\": \"Richtext\",\n \"src\": \"/README.md\"\n }\n]"
|
|
43
|
+
- name: code-blocks
|
|
44
|
+
description: Richtext with fenced code blocks; whitespace preserved and monospace styling applied.
|
|
45
|
+
a2ui: "[\n {\n \"id\": \"root\",\n \"component\": \"Richtext\",\n \"markdown\": \"## Example\\n\\n```js\\nfunction\
|
|
46
|
+
\ greet(name) {\\n return `Hello, ${name}!`;\\n}\\n```\\n\\nInline `code` also works.\"\n }\n]"
|
|
86
47
|
keywords:
|
|
87
|
-
|
|
88
|
-
synonyms:
|
|
48
|
+
- richtext
|
|
49
|
+
synonyms:
|
|
50
|
+
tags:
|
|
51
|
+
- markdown
|
|
52
|
+
- md-render
|
|
53
|
+
- rich-text
|
|
89
54
|
related: []
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-side-effect class export for `<row-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/row`
|
|
9
|
+
* (which imports this file + calls `defineIfFree()`).
|
|
10
|
+
*
|
|
11
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* row-ui — Flex row layout primitive.
|
|
16
|
+
*
|
|
17
|
+
* <row-ui gap="sm" justify="space-between" wrap>...</row-ui>
|
|
18
|
+
* <row-ui draggable>...</row-ui> wires the draggable trait, emits drag-end
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { UIElement } from '../../core/element.js';
|
|
22
|
+
import { draggable } from '../../traits/draggable/draggable.js';
|
|
23
|
+
|
|
24
|
+
export class UIRow extends UIElement {
|
|
25
|
+
static properties = {
|
|
26
|
+
justify: { type: String, default: 'start', reflect: true },
|
|
27
|
+
align: { type: String, default: 'center', reflect: true },
|
|
28
|
+
gap: { type: String, default: 'md', reflect: true },
|
|
29
|
+
grow: { type: Boolean, default: false, reflect: true },
|
|
30
|
+
wrap: { type: Boolean, default: false, reflect: true },
|
|
31
|
+
draggable: { type: Boolean, default: false, reflect: true },
|
|
32
|
+
};
|
|
33
|
+
static template = () => null;
|
|
34
|
+
|
|
35
|
+
#dragAttached = false;
|
|
36
|
+
|
|
37
|
+
connected() {
|
|
38
|
+
if (this.draggable && !this.#dragAttached) {
|
|
39
|
+
this.addTrait(draggable);
|
|
40
|
+
this.#dragAttached = true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
updated(changed) {
|
|
45
|
+
if (changed.has('draggable') && this.draggable && !this.#dragAttached) {
|
|
46
|
+
this.addTrait(draggable);
|
|
47
|
+
this.#dragAttached = true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|