@adia-ai/web-components 0.4.5 → 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/README.md +63 -24
- package/USAGE.md +604 -0
- 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.d.ts +27 -0
- 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.d.ts +30 -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.d.ts +39 -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.d.ts +37 -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/index.js +1 -0
- package/components/input/class.js +773 -0
- package/components/input/input.a2ui.json +3 -0
- package/components/input/input.d.ts +61 -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.d.ts +30 -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.d.ts +25 -0
- 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.css +10 -0
- package/components/pane/pane.d.ts +31 -0
- package/components/pane/pane.js +8 -143
- 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.d.ts +28 -0
- package/components/radio/radio.js +11 -67
- package/components/range/class.js +194 -0
- package/components/range/range.d.ts +31 -0
- package/components/range/range.js +9 -176
- package/components/rating/class.js +148 -0
- package/components/rating/rating.d.ts +33 -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.d.ts +35 -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.d.ts +24 -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.d.ts +57 -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.d.ts +31 -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.d.ts +30 -0
- 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.d.ts +31 -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.a2ui.json +197 -0
- package/components/toggle-scheme/toggle-scheme.css +20 -0
- package/components/toggle-scheme/toggle-scheme.d.ts +41 -0
- package/components/toggle-scheme/toggle-scheme.js +17 -0
- package/components/toggle-scheme/toggle-scheme.yaml +173 -0
- 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.d.ts +27 -0
- package/components/upload/upload.js +11 -183
- package/core/element.d.ts +174 -0
- package/core/form.d.ts +108 -0
- package/core/index.d.ts +11 -0
- package/core/index.js +1 -0
- package/core/register.d.ts +25 -0
- package/core/register.js +58 -0
- package/core/signals.d.ts +94 -0
- package/core/template.d.ts +70 -0
- package/index.d.ts +315 -0
- package/package.json +25 -6
- package/traits/CATEGORIES.md +1 -1
|
@@ -1,256 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* field-ui —
|
|
2
|
+
* `<field-ui>` — auto-registers the tag on import.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* <span slot="trailing">Optional</span>
|
|
7
|
-
* <button-ui slot="action" icon="x" aria-label="Clear"></button-ui>
|
|
8
|
-
* </field-ui>
|
|
4
|
+
* For non-side-effect class import (test isolation, tag override), use
|
|
5
|
+
* the `class` subpath:
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
* and action regions. The host renders a real `<label for="…">` bound
|
|
12
|
-
* to the slotted control's id (auto-minted when missing) so clicking
|
|
13
|
-
* the label focuses the control — an affordance the previous
|
|
14
|
-
* `<input-ui label="…">` pattern lacked.
|
|
7
|
+
* import { UIField } from '@adia-ai/web-components/components/field/class';
|
|
15
8
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* field-ui is a CSS grid; children are placed by `[slot]` attribute:
|
|
19
|
-
*
|
|
20
|
-
* slot="label" → label cell (mounted by field-ui)
|
|
21
|
-
* slot="trailing" → row 1, right
|
|
22
|
-
* (no slot) → control cell
|
|
23
|
-
* slot="action" → adjacent to control
|
|
24
|
-
* slot="hint" → message row (mounted by field-ui)
|
|
25
|
-
* slot="error" → message row (mounted by field-ui)
|
|
26
|
-
*
|
|
27
|
-
* The template adapts (via `:has()`) to which slots are present so empty
|
|
28
|
-
* tracks don't leak column-gap. Inline mode flattens the content slots
|
|
29
|
-
* onto a single row by retuning columns; message stays below.
|
|
30
|
-
*
|
|
31
|
-
* No DOM reparenting; CSS positions children directly. A small
|
|
32
|
-
* MutationObserver watches childList so a swapped-in control gets its
|
|
33
|
-
* `for=` and `aria-describedby` rebound.
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
34
10
|
*/
|
|
35
|
-
import { UIElement } from '../../core/element.js';
|
|
36
|
-
|
|
37
|
-
class UIField extends UIElement {
|
|
38
|
-
static properties = {
|
|
39
|
-
label: { type: String, default: '', reflect: true },
|
|
40
|
-
hint: { type: String, default: '', reflect: true },
|
|
41
|
-
required: { type: Boolean, default: false, reflect: true },
|
|
42
|
-
inline: { type: Boolean, default: false, reflect: true },
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// The validation message lives on the child control (UIFormElement.error
|
|
46
|
-
// is the single source of truth — validity is a property of the value, not
|
|
47
|
-
// of the layout wrapper). field-ui mirrors the child's error string into
|
|
48
|
-
// its own [data-field-error] slot so the validation message renders below
|
|
49
|
-
// the control. See docs/specs/component-token-contract.md "Toggle state
|
|
50
|
-
// naming" / open decisions resolution log.
|
|
51
|
-
get error() {
|
|
52
|
-
const ctrl = this.#findControl();
|
|
53
|
-
return ctrl?.error ?? '';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static template = () => null;
|
|
57
|
-
|
|
58
|
-
#labelEl = null;
|
|
59
|
-
#labelMark = null;
|
|
60
|
-
#hintEl = null;
|
|
61
|
-
#errorEl = null;
|
|
62
|
-
#mo = null;
|
|
63
|
-
|
|
64
|
-
// Label click → focus the first focusable descendant of the slotted
|
|
65
|
-
// control. The native `<label for="x">` affordance focuses the host
|
|
66
|
-
// by id, which for a custom-element control falls through to body
|
|
67
|
-
// (host typically tabindex=-1).
|
|
68
|
-
#onLabelClick = (e) => {
|
|
69
|
-
const ctrl = this.#findControl();
|
|
70
|
-
if (!ctrl) return;
|
|
71
|
-
const focusable = this.#firstFocusable(ctrl);
|
|
72
|
-
if (!focusable) return;
|
|
73
|
-
e.preventDefault();
|
|
74
|
-
focusable.focus();
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
connected() {
|
|
78
|
-
this.#ensureLabelElement();
|
|
79
|
-
this.#ensureHintElement();
|
|
80
|
-
this.#ensureErrorElement();
|
|
81
|
-
this.#bindForToControl();
|
|
82
|
-
this.#bindErrorListener();
|
|
83
|
-
this.#labelEl?.addEventListener('click', this.#onLabelClick);
|
|
84
|
-
this.#mo = new MutationObserver(() => {
|
|
85
|
-
this.#bindForToControl();
|
|
86
|
-
this.#bindErrorListener();
|
|
87
|
-
this.#wireAriaDescribedBy();
|
|
88
|
-
this.#syncErrorMessage();
|
|
89
|
-
});
|
|
90
|
-
this.#mo.observe(this, { childList: true });
|
|
91
|
-
this.#syncErrorMessage();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
disconnected() {
|
|
95
|
-
this.#mo?.disconnect();
|
|
96
|
-
this.#mo = null;
|
|
97
|
-
this.#unbindErrorListener();
|
|
98
|
-
this.#labelEl?.removeEventListener('click', this.#onLabelClick);
|
|
99
|
-
this.#labelEl = null;
|
|
100
|
-
this.#labelMark = null;
|
|
101
|
-
this.#hintEl = null;
|
|
102
|
-
this.#errorEl = null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
render() {
|
|
106
|
-
if (this.#labelEl) {
|
|
107
|
-
this.#labelEl.childNodes[0] && (this.#labelEl.childNodes[0].nodeValue = this.label || '');
|
|
108
|
-
}
|
|
109
|
-
if (this.#labelMark) this.#labelMark.hidden = !this.required;
|
|
110
|
-
if (this.#hintEl) {
|
|
111
|
-
this.#hintEl.textContent = this.hint || '';
|
|
112
|
-
this.#hintEl.hidden = !this.hint || Boolean(this.error);
|
|
113
|
-
}
|
|
114
|
-
this.#syncErrorMessage();
|
|
115
|
-
this.#wireAriaDescribedBy();
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Mirror child.error → #errorEl. Called on render, MutationObserver
|
|
119
|
-
// changes, and the child's `invalid`/`change`/`input` events.
|
|
120
|
-
#syncErrorMessage() {
|
|
121
|
-
if (!this.#errorEl) return;
|
|
122
|
-
const msg = this.error;
|
|
123
|
-
this.#errorEl.textContent = msg || '';
|
|
124
|
-
this.#errorEl.hidden = !msg;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
#onChildEvent = () => {
|
|
128
|
-
this.#syncErrorMessage();
|
|
129
|
-
this.#wireAriaDescribedBy();
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
#boundErrorTarget = null;
|
|
133
|
-
|
|
134
|
-
#bindErrorListener() {
|
|
135
|
-
const ctrl = this.#findControl();
|
|
136
|
-
if (ctrl === this.#boundErrorTarget) return;
|
|
137
|
-
this.#unbindErrorListener();
|
|
138
|
-
if (!ctrl) return;
|
|
139
|
-
this.#boundErrorTarget = ctrl;
|
|
140
|
-
ctrl.addEventListener('invalid', this.#onChildEvent, true);
|
|
141
|
-
ctrl.addEventListener('change', this.#onChildEvent);
|
|
142
|
-
ctrl.addEventListener('input', this.#onChildEvent);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
#unbindErrorListener() {
|
|
146
|
-
const ctrl = this.#boundErrorTarget;
|
|
147
|
-
if (!ctrl) return;
|
|
148
|
-
ctrl.removeEventListener('invalid', this.#onChildEvent, true);
|
|
149
|
-
ctrl.removeEventListener('change', this.#onChildEvent);
|
|
150
|
-
ctrl.removeEventListener('input', this.#onChildEvent);
|
|
151
|
-
this.#boundErrorTarget = null;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ── Private ───────────────────────────────────────────────────────
|
|
155
|
-
|
|
156
|
-
#ensureLabelElement() {
|
|
157
|
-
this.#labelEl = this.querySelector(':scope > [data-field-label]');
|
|
158
|
-
if (!this.#labelEl) {
|
|
159
|
-
const el = document.createElement('label');
|
|
160
|
-
el.setAttribute('slot', 'label');
|
|
161
|
-
el.setAttribute('data-field-label', '');
|
|
162
|
-
el.appendChild(document.createTextNode(this.label || ''));
|
|
163
|
-
// Prepend so source-order matches visual order (label before
|
|
164
|
-
// control). Not strictly required since CSS uses grid-area, but
|
|
165
|
-
// it keeps DevTools / a11y tree readings sensible.
|
|
166
|
-
this.prepend(el);
|
|
167
|
-
this.#labelEl = el;
|
|
168
|
-
}
|
|
169
|
-
this.#labelMark = this.#labelEl.querySelector('[data-field-required]');
|
|
170
|
-
if (!this.#labelMark) {
|
|
171
|
-
const mark = document.createElement('span');
|
|
172
|
-
mark.setAttribute('data-field-required', '');
|
|
173
|
-
mark.setAttribute('aria-hidden', 'true');
|
|
174
|
-
mark.textContent = '*';
|
|
175
|
-
mark.hidden = true;
|
|
176
|
-
this.#labelEl.appendChild(mark);
|
|
177
|
-
this.#labelMark = mark;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
#ensureHintElement() {
|
|
182
|
-
this.#hintEl = this.querySelector(':scope > [data-field-hint]');
|
|
183
|
-
if (this.#hintEl) return;
|
|
184
|
-
const el = document.createElement('div');
|
|
185
|
-
el.setAttribute('slot', 'hint');
|
|
186
|
-
el.setAttribute('data-field-hint', '');
|
|
187
|
-
el.setAttribute('id', UIField.#nextMsgId('hint'));
|
|
188
|
-
el.hidden = true;
|
|
189
|
-
this.appendChild(el);
|
|
190
|
-
this.#hintEl = el;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
#ensureErrorElement() {
|
|
194
|
-
this.#errorEl = this.querySelector(':scope > [data-field-error]');
|
|
195
|
-
if (this.#errorEl) return;
|
|
196
|
-
const el = document.createElement('div');
|
|
197
|
-
el.setAttribute('slot', 'error');
|
|
198
|
-
el.setAttribute('data-field-error', '');
|
|
199
|
-
el.setAttribute('id', UIField.#nextMsgId('err'));
|
|
200
|
-
el.setAttribute('role', 'alert');
|
|
201
|
-
el.hidden = true;
|
|
202
|
-
this.appendChild(el);
|
|
203
|
-
this.#errorEl = el;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
#bindForToControl() {
|
|
207
|
-
if (!this.#labelEl) return;
|
|
208
|
-
const control = this.#findControl();
|
|
209
|
-
if (!control) {
|
|
210
|
-
this.#labelEl.removeAttribute('for');
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
if (!control.id) control.id = UIField.#nextId();
|
|
214
|
-
this.#labelEl.setAttribute('for', control.id);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** Wire `aria-describedby` on the slotted control to the hint/error
|
|
218
|
-
* ids. Keeps any consumer-set describedby ids; appends ours. */
|
|
219
|
-
#wireAriaDescribedBy() {
|
|
220
|
-
const ctrl = this.#findControl();
|
|
221
|
-
if (!ctrl) return;
|
|
222
|
-
const ours = new Set();
|
|
223
|
-
if (this.#hintEl && !this.#hintEl.hidden) ours.add(this.#hintEl.id);
|
|
224
|
-
if (this.#errorEl && !this.#errorEl.hidden) ours.add(this.#errorEl.id);
|
|
225
|
-
const existing = (ctrl.getAttribute('aria-describedby') || '')
|
|
226
|
-
.split(/\s+/).filter((s) => s && !s.startsWith('field-hint-') && !s.startsWith('field-err-'));
|
|
227
|
-
const merged = [...existing, ...ours].join(' ').trim();
|
|
228
|
-
if (merged) ctrl.setAttribute('aria-describedby', merged);
|
|
229
|
-
else ctrl.removeAttribute('aria-describedby');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/** The default-slot control — first child without a `slot` attribute. */
|
|
233
|
-
#findControl() {
|
|
234
|
-
for (const ch of this.children) {
|
|
235
|
-
if (!ch.hasAttribute('slot')) return ch;
|
|
236
|
-
}
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
239
11
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
* and any `[tabindex]` ≥ 0. Light DOM only. */
|
|
243
|
-
#firstFocusable(root) {
|
|
244
|
-
const SEL = 'input, textarea, select, button, [contenteditable], [tabindex]:not([tabindex="-1"])';
|
|
245
|
-
if (root.matches?.(SEL)) return root;
|
|
246
|
-
return root.querySelector?.(SEL) ?? null;
|
|
247
|
-
}
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIField } from './class.js';
|
|
248
14
|
|
|
249
|
-
|
|
250
|
-
static #nextId() { return `field-ctl-${++UIField.#idSeq}`; }
|
|
251
|
-
static #msgSeq = 0;
|
|
252
|
-
static #nextMsgId(kind) { return `field-${kind}-${++UIField.#msgSeq}`; }
|
|
253
|
-
}
|
|
15
|
+
defineIfFree('field-ui', UIField);
|
|
254
16
|
|
|
255
|
-
customElements.define('field-ui', UIField);
|
|
256
17
|
export { UIField };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-side-effect class export for `<fields-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/fields`
|
|
9
|
+
* (which imports this file + calls `defineIfFree()`).
|
|
10
|
+
*
|
|
11
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* fields-ui — Container for a group of <field-ui> children laid out
|
|
16
|
+
* on a shared grid.
|
|
17
|
+
*
|
|
18
|
+
* <fields-ui> <!-- 6-col grid -->
|
|
19
|
+
* <field-ui label="Title">…</field-ui> <!-- rows=6 (full row) -->
|
|
20
|
+
* <field-ui label="Status" rows="2">…</field-ui>
|
|
21
|
+
* <field-ui label="Priority" rows="2">…</field-ui>
|
|
22
|
+
* <field-ui label="Group" rows="2">…</field-ui>
|
|
23
|
+
* </fields-ui>
|
|
24
|
+
*
|
|
25
|
+
* <fields-ui inline> <!-- propagate inline to every child -->
|
|
26
|
+
* <field-ui label="Search">…</field-ui>
|
|
27
|
+
* <field-ui label="Kind">…</field-ui>
|
|
28
|
+
* </fields-ui>
|
|
29
|
+
*
|
|
30
|
+
* The shared grid keeps siblings on the same row aligned. The [inline]
|
|
31
|
+
* attribute is mirrored onto every direct <field-ui> child so a whole
|
|
32
|
+
* sub-form switches layout mode from one host attribute. A small
|
|
33
|
+
* MutationObserver re-syncs when children are added/removed.
|
|
34
|
+
*
|
|
35
|
+
* Per-field column span is driven by the child's [rows="1..6"]
|
|
36
|
+
* attribute — pure CSS via attribute selectors in fields.css. The
|
|
37
|
+
* default span (no attr) is the full row.
|
|
38
|
+
*/
|
|
39
|
+
import { UIElement } from '../../core/element.js';
|
|
40
|
+
|
|
41
|
+
export class UIFields extends UIElement {
|
|
42
|
+
static properties = {
|
|
43
|
+
inline: { type: Boolean, default: false, reflect: true },
|
|
44
|
+
columns: { type: Number, default: 6, reflect: true },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
static template = () => null;
|
|
48
|
+
|
|
49
|
+
/** @type {MutationObserver | null} */
|
|
50
|
+
#mo = null;
|
|
51
|
+
|
|
52
|
+
connected() {
|
|
53
|
+
this.#syncInline();
|
|
54
|
+
this.#mo = new MutationObserver((records) => {
|
|
55
|
+
// Only re-sync on childList changes that involve direct <field-ui>
|
|
56
|
+
// children — attribute mutations on grandchildren aren't ours to
|
|
57
|
+
// care about.
|
|
58
|
+
for (const r of records) {
|
|
59
|
+
if (r.type !== 'childList') continue;
|
|
60
|
+
if (this.#hasFieldChild(r.addedNodes) || this.#hasFieldChild(r.removedNodes)) {
|
|
61
|
+
this.#syncInline();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
this.#mo.observe(this, { childList: true });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
disconnected() {
|
|
70
|
+
this.#mo?.disconnect();
|
|
71
|
+
this.#mo = null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
render() {
|
|
75
|
+
// UIElement calls render() on attribute → property reflection. The
|
|
76
|
+
// inline attr's effect is propagation-to-children, not host markup.
|
|
77
|
+
this.#syncInline();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── Private ────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
#syncInline() {
|
|
83
|
+
const inline = this.hasAttribute('inline');
|
|
84
|
+
for (const child of this.children) {
|
|
85
|
+
if (child.localName !== 'field-ui') continue;
|
|
86
|
+
if (inline) {
|
|
87
|
+
if (!child.hasAttribute('inline')) child.setAttribute('inline', '');
|
|
88
|
+
} else {
|
|
89
|
+
// Only remove if WE set it. We can't tell, so we always remove —
|
|
90
|
+
// that's the documented contract: <fields-ui inline> is the
|
|
91
|
+
// single source of truth for child inline-mode within the group.
|
|
92
|
+
if (child.hasAttribute('inline')) child.removeAttribute('inline');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** @param {NodeList} nodes */
|
|
98
|
+
#hasFieldChild(nodes) {
|
|
99
|
+
for (const n of nodes) {
|
|
100
|
+
if (n.nodeType === 1 && /** @type {Element} */ (n).localName === 'field-ui') {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<fields-ui>` — Container for a group of <field-ui> children, laid out on a shared 6-column grid. Each <field-ui> spans the full row by default; opt into a narrower span via [rows="1..6"]. Setting [inline] on the host propagates the inline mode to every direct <field-ui> child so a whole sub-form can switch label-position without per-field edits. The grid alignment lets siblings on the same row line up cleanly — consistent label columns + consistent control columns — without the wrap-flex jitter of <row-ui wrap>.
|
|
3
|
+
*
|
|
4
|
+
* @see https://ui-kit.exe.xyz/site/components/fields
|
|
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 UIFields extends UIElement {
|
|
15
|
+
/** Number of grid columns the row uses. Defaults to 6 — common multiples (1/2/3/6) divide cleanly. <field-ui rows="N"> spans `N` of these columns. Override per-instance for tighter 4-column or wider 12-column compositions. */
|
|
16
|
+
columns: number;
|
|
17
|
+
/** Propagate the inline layout mode to every direct <field-ui> child. Equivalent to authoring `inline` on each child but drives the whole group from one place. Toggle is reactive — flipping the attribute on the host re-syncs all children. */
|
|
18
|
+
inline: boolean;
|
|
19
|
+
}
|
|
@@ -1,96 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* fields-ui —
|
|
3
|
-
* on a shared grid.
|
|
2
|
+
* `<fields-ui>` — auto-registers the tag on import.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* <field-ui label="Status" rows="2">…</field-ui>
|
|
8
|
-
* <field-ui label="Priority" rows="2">…</field-ui>
|
|
9
|
-
* <field-ui label="Group" rows="2">…</field-ui>
|
|
10
|
-
* </fields-ui>
|
|
4
|
+
* For non-side-effect class import (test isolation, tag override), use
|
|
5
|
+
* the `class` subpath:
|
|
11
6
|
*
|
|
12
|
-
*
|
|
13
|
-
* <field-ui label="Search">…</field-ui>
|
|
14
|
-
* <field-ui label="Kind">…</field-ui>
|
|
15
|
-
* </fields-ui>
|
|
7
|
+
* import { UIFields } from '@adia-ai/web-components/components/fields/class';
|
|
16
8
|
*
|
|
17
|
-
*
|
|
18
|
-
* attribute is mirrored onto every direct <field-ui> child so a whole
|
|
19
|
-
* sub-form switches layout mode from one host attribute. A small
|
|
20
|
-
* MutationObserver re-syncs when children are added/removed.
|
|
21
|
-
*
|
|
22
|
-
* Per-field column span is driven by the child's [rows="1..6"]
|
|
23
|
-
* attribute — pure CSS via attribute selectors in fields.css. The
|
|
24
|
-
* default span (no attr) is the full row.
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
25
10
|
*/
|
|
26
|
-
import { UIElement } from '../../core/element.js';
|
|
27
|
-
|
|
28
|
-
class UIFields extends UIElement {
|
|
29
|
-
static properties = {
|
|
30
|
-
inline: { type: Boolean, default: false, reflect: true },
|
|
31
|
-
columns: { type: Number, default: 6, reflect: true },
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
static template = () => null;
|
|
35
|
-
|
|
36
|
-
/** @type {MutationObserver | null} */
|
|
37
|
-
#mo = null;
|
|
38
|
-
|
|
39
|
-
connected() {
|
|
40
|
-
this.#syncInline();
|
|
41
|
-
this.#mo = new MutationObserver((records) => {
|
|
42
|
-
// Only re-sync on childList changes that involve direct <field-ui>
|
|
43
|
-
// children — attribute mutations on grandchildren aren't ours to
|
|
44
|
-
// care about.
|
|
45
|
-
for (const r of records) {
|
|
46
|
-
if (r.type !== 'childList') continue;
|
|
47
|
-
if (this.#hasFieldChild(r.addedNodes) || this.#hasFieldChild(r.removedNodes)) {
|
|
48
|
-
this.#syncInline();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
this.#mo.observe(this, { childList: true });
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
disconnected() {
|
|
57
|
-
this.#mo?.disconnect();
|
|
58
|
-
this.#mo = null;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
render() {
|
|
62
|
-
// UIElement calls render() on attribute → property reflection. The
|
|
63
|
-
// inline attr's effect is propagation-to-children, not host markup.
|
|
64
|
-
this.#syncInline();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ── Private ────────────────────────────────────────────────────
|
|
68
11
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
for (const child of this.children) {
|
|
72
|
-
if (child.localName !== 'field-ui') continue;
|
|
73
|
-
if (inline) {
|
|
74
|
-
if (!child.hasAttribute('inline')) child.setAttribute('inline', '');
|
|
75
|
-
} else {
|
|
76
|
-
// Only remove if WE set it. We can't tell, so we always remove —
|
|
77
|
-
// that's the documented contract: <fields-ui inline> is the
|
|
78
|
-
// single source of truth for child inline-mode within the group.
|
|
79
|
-
if (child.hasAttribute('inline')) child.removeAttribute('inline');
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIFields } from './class.js';
|
|
83
14
|
|
|
84
|
-
|
|
85
|
-
#hasFieldChild(nodes) {
|
|
86
|
-
for (const n of nodes) {
|
|
87
|
-
if (n.nodeType === 1 && /** @type {Element} */ (n).localName === 'field-ui') {
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
15
|
+
defineIfFree('fields-ui', UIFields);
|
|
94
16
|
|
|
95
|
-
customElements.define('fields-ui', UIFields);
|
|
96
17
|
export { UIFields };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-side-effect class export for `<grid-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/grid`
|
|
9
|
+
* (which imports this file + calls `defineIfFree()`).
|
|
10
|
+
*
|
|
11
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* grid-ui — CSS grid layout primitive.
|
|
16
|
+
*
|
|
17
|
+
* <grid-ui columns="3" gap="lg">...</grid-ui>
|
|
18
|
+
* <grid-ui columns="2" column-gap="2" row-gap="4">...</grid-ui>
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { UIElement } from '../../core/element.js';
|
|
22
|
+
|
|
23
|
+
export class UIGrid extends UIElement {
|
|
24
|
+
static properties = {
|
|
25
|
+
columns: { type: String, default: '3', reflect: true },
|
|
26
|
+
gap: { type: String, default: 'md', reflect: true },
|
|
27
|
+
columnGap: { type: String, default: '', reflect: true, attribute: 'column-gap' },
|
|
28
|
+
rowGap: { type: String, default: '', reflect: true, attribute: 'row-gap' },
|
|
29
|
+
};
|
|
30
|
+
static template = () => null;
|
|
31
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<grid-ui>` — CSS grid layout primitive. Supports [columns="1..6"] for equal columns, [columns="auto-fill"|"auto-fit"] for responsive density, and a per-child [span="2..6"|"full"] attribute for asymmetric layouts. Compose a 2:1 split as columns="3" + the wide child span="2"; compose a 3:2 split as columns="5" + span="3" + span="2". Never set grid-template-columns via inline style — use the span attribute on children instead.
|
|
3
|
+
*
|
|
4
|
+
* @see https://ui-kit.exe.xyz/site/components/grid
|
|
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 UIGrid extends UIElement {
|
|
15
|
+
/** Column gap override */
|
|
16
|
+
columnGap: string;
|
|
17
|
+
/** Number of columns or grid-template-columns */
|
|
18
|
+
columns: string;
|
|
19
|
+
/** Grid gap */
|
|
20
|
+
gap: string;
|
|
21
|
+
/** Row gap override */
|
|
22
|
+
rowGap: string;
|
|
23
|
+
}
|
package/components/grid/grid.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* grid-ui —
|
|
2
|
+
* `<grid-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
|
+
*
|
|
7
|
+
* import { UIGrid } from '@adia-ai/web-components/components/grid/class';
|
|
8
|
+
*
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
6
10
|
*/
|
|
7
11
|
|
|
8
|
-
import {
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIGrid } from './class.js';
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
static properties = {
|
|
12
|
-
columns: { type: String, default: '3', reflect: true },
|
|
13
|
-
gap: { type: String, default: 'md', reflect: true },
|
|
14
|
-
columnGap: { type: String, default: '', reflect: true, attribute: 'column-gap' },
|
|
15
|
-
rowGap: { type: String, default: '', reflect: true, attribute: 'row-gap' },
|
|
16
|
-
};
|
|
17
|
-
static template = () => null;
|
|
18
|
-
}
|
|
19
|
-
customElements.define('grid-ui', UIGrid);
|
|
15
|
+
defineIfFree('grid-ui', UIGrid);
|
|
20
16
|
|
|
21
17
|
export { UIGrid };
|