@adia-ai/web-components 0.8.36 → 0.8.38
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/CHANGELOG.md +29 -0
- package/MIGRATION.md +248 -45
- package/README.md +3 -3
- package/bin/doc.mjs +27 -5
- package/components/card/card.css +1 -1
- package/components/drilldown/drilldown.a2ui.json +242 -0
- package/components/drilldown/drilldown.class.js +542 -0
- package/components/drilldown/drilldown.css +305 -0
- package/components/drilldown/drilldown.d.ts +68 -0
- package/components/drilldown/drilldown.examples.md +20 -0
- package/components/drilldown/drilldown.js +17 -0
- package/components/drilldown/drilldown.yaml +271 -0
- package/components/index.js +1 -0
- package/components/inspector/inspector.class.js +1 -1
- package/components/nav/nav.class.js +11 -8
- package/components/nav-item/nav-item.class.js +9 -6
- package/components/page/page.a2ui.json +13 -1
- package/components/page/page.css +113 -0
- package/components/page/page.yaml +30 -3
- package/components/table-toolbar/table-toolbar.examples.md +3 -3
- package/core/streams-bridge.d.ts +2 -2
- package/core/streams-bridge.js +1 -1
- package/custom-elements.json +183 -26
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +103 -84
- package/dist/web-components.sheet.js +1 -1
- package/package.json +3 -3
- package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +8 -8
- package/patterns/agent-cost/agent-cost.examples.html +3 -3
- package/patterns/agent-memory/agent-memory.examples.html +4 -4
- package/patterns/agent-prompt-library/agent-prompt-library.examples.html +8 -8
- package/patterns/approvals/approvals.examples.html +2 -2
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +1 -1
- package/patterns/changelog-feed/changelog-feed.examples.html +1 -1
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +7 -7
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +4 -4
- package/patterns/diff-review/diff-review.examples.html +6 -6
- package/patterns/filter-bar/filter-bar.examples.html +5 -5
- package/patterns/inline-dialog/inline-dialog.examples.html +1 -1
- package/patterns/kanban-board/kanban-board.examples.html +12 -12
- package/patterns/layout/layout.examples.html +3 -3
- package/patterns/marketing-engagement/marketing-engagement.examples.html +13 -13
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +1 -1
- package/patterns/permissions-matrix/permissions-matrix.examples.html +1 -1
- package/patterns/permissions-role-picker/permissions-role-picker.examples.html +1 -1
- package/patterns/permissions-sharing/permissions-sharing.examples.html +3 -3
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +2 -2
- package/patterns/search-discovery/search-discovery.examples.html +15 -15
- package/styles/components.css +1 -0
- package/styles/type/scale.css +2 -1
- package/traits/view-transition/view-transition.js +7 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
@scope (drilldown-ui) {
|
|
2
|
+
:where(:scope) {
|
|
3
|
+
/* ── Layout ── */
|
|
4
|
+
--drilldown-row-height: var(--a-size, 2.25rem);
|
|
5
|
+
--drilldown-row-radius: var(--a-radius-sm);
|
|
6
|
+
--drilldown-row-px: var(--a-space-2);
|
|
7
|
+
--drilldown-row-gap: var(--a-space-2);
|
|
8
|
+
--drilldown-header-px: var(--a-space-3);
|
|
9
|
+
--drilldown-header-py: var(--a-space-2);
|
|
10
|
+
--drilldown-list-py: var(--a-space-1);
|
|
11
|
+
--drilldown-dot-size: 0.5rem;
|
|
12
|
+
--drilldown-chevron-size: var(--a-caret-size);
|
|
13
|
+
|
|
14
|
+
/* ── Typography ── */
|
|
15
|
+
--drilldown-font-size: var(--a-ui-size);
|
|
16
|
+
--drilldown-meta-font-size: var(--a-ui-xs);
|
|
17
|
+
--drilldown-title-font-size: var(--a-ui-size);
|
|
18
|
+
--drilldown-title-weight: var(--a-weight-medium);
|
|
19
|
+
|
|
20
|
+
/* ── Colors ── */
|
|
21
|
+
--drilldown-fg: var(--md-sys-color-neutral-on-surface);
|
|
22
|
+
--drilldown-fg-muted: var(--a-fg-muted);
|
|
23
|
+
--drilldown-bg-hover: var(--a-bg-hover);
|
|
24
|
+
--drilldown-bg-active: var(--a-bg-muted);
|
|
25
|
+
--drilldown-border: var(--md-sys-color-neutral-outline-variant);
|
|
26
|
+
|
|
27
|
+
/* ── Count chip (row-native — deliberately NOT badge-ui's chrome,
|
|
28
|
+
which reads oversized at this row density; gh#1285) ── */
|
|
29
|
+
--drilldown-count-chip-px: var(--a-space-1);
|
|
30
|
+
--drilldown-count-chip-py: var(--a-space-px);
|
|
31
|
+
--drilldown-count-chip-font-size: var(--a-ui-2xs, 0.6875rem);
|
|
32
|
+
--drilldown-count-chip-radius: var(--a-radius-sm);
|
|
33
|
+
--drilldown-count-chip-bg: var(--md-sys-color-neutral-container-low);
|
|
34
|
+
--drilldown-count-chip-fg: var(--a-fg-muted);
|
|
35
|
+
|
|
36
|
+
/* ── Transition ── */
|
|
37
|
+
--drilldown-duration: var(--a-duration-fast);
|
|
38
|
+
--drilldown-easing: var(--a-easing);
|
|
39
|
+
|
|
40
|
+
/* ── Focus ── */
|
|
41
|
+
--drilldown-focus-ring: var(--a-focus-ring);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:scope {
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
font-size: var(--drilldown-font-size);
|
|
49
|
+
color: var(--drilldown-fg);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* ── Header ── */
|
|
53
|
+
[slot="header"] {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
gap: var(--drilldown-row-gap);
|
|
57
|
+
padding: var(--drilldown-header-py) var(--drilldown-header-px);
|
|
58
|
+
border-bottom: 1px solid var(--drilldown-border);
|
|
59
|
+
flex-shrink: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[slot="back"] {
|
|
63
|
+
display: inline-flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: var(--a-space-1);
|
|
66
|
+
border: none;
|
|
67
|
+
background: transparent;
|
|
68
|
+
color: var(--drilldown-fg-muted);
|
|
69
|
+
font: inherit;
|
|
70
|
+
font-size: var(--drilldown-meta-font-size);
|
|
71
|
+
padding: var(--a-space-1);
|
|
72
|
+
margin-inline-start: calc(-1 * var(--a-space-1));
|
|
73
|
+
border-radius: var(--drilldown-row-radius);
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
max-width: 40%;
|
|
77
|
+
overflow: hidden;
|
|
78
|
+
}
|
|
79
|
+
[slot="back"] icon-ui {
|
|
80
|
+
--a-icon-size: var(--drilldown-chevron-size);
|
|
81
|
+
flex-shrink: 0;
|
|
82
|
+
}
|
|
83
|
+
[slot="back"] [data-back-label] {
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
text-overflow: ellipsis;
|
|
86
|
+
}
|
|
87
|
+
[slot="back"]:hover {
|
|
88
|
+
background: var(--drilldown-bg-hover);
|
|
89
|
+
color: var(--drilldown-fg);
|
|
90
|
+
}
|
|
91
|
+
[slot="back"]:focus-visible {
|
|
92
|
+
box-shadow: var(--drilldown-focus-ring);
|
|
93
|
+
outline: none;
|
|
94
|
+
}
|
|
95
|
+
[slot="back"][hidden] {
|
|
96
|
+
display: none;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
[slot="breadcrumb"]:empty {
|
|
100
|
+
display: none;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
[slot="title"] {
|
|
104
|
+
display: flex;
|
|
105
|
+
align-items: baseline;
|
|
106
|
+
gap: var(--a-space-1-5);
|
|
107
|
+
min-width: 0;
|
|
108
|
+
flex: 1;
|
|
109
|
+
}
|
|
110
|
+
[data-level-title] {
|
|
111
|
+
font-weight: var(--drilldown-title-weight);
|
|
112
|
+
font-size: var(--drilldown-title-font-size);
|
|
113
|
+
overflow: hidden;
|
|
114
|
+
text-overflow: ellipsis;
|
|
115
|
+
white-space: nowrap;
|
|
116
|
+
}
|
|
117
|
+
[data-level-title]:empty {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
[data-level-count] {
|
|
121
|
+
color: var(--drilldown-fg-muted);
|
|
122
|
+
font-size: var(--drilldown-meta-font-size);
|
|
123
|
+
font-variant-numeric: tabular-nums;
|
|
124
|
+
flex-shrink: 0;
|
|
125
|
+
}
|
|
126
|
+
[data-level-count]:empty {
|
|
127
|
+
display: none;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ── Filter ── */
|
|
131
|
+
[slot="filter"] {
|
|
132
|
+
display: flex;
|
|
133
|
+
align-items: center;
|
|
134
|
+
gap: var(--a-space-2);
|
|
135
|
+
padding: var(--a-space-2) var(--drilldown-header-px);
|
|
136
|
+
border-bottom: 1px solid var(--drilldown-border);
|
|
137
|
+
flex-shrink: 0;
|
|
138
|
+
}
|
|
139
|
+
[slot="filter"][hidden] {
|
|
140
|
+
display: none;
|
|
141
|
+
}
|
|
142
|
+
[slot="filter"] icon-ui {
|
|
143
|
+
--a-icon-size: 0.875rem;
|
|
144
|
+
color: var(--drilldown-fg-muted);
|
|
145
|
+
flex-shrink: 0;
|
|
146
|
+
}
|
|
147
|
+
[slot="filter"] input {
|
|
148
|
+
flex: 1;
|
|
149
|
+
min-width: 0;
|
|
150
|
+
border: none;
|
|
151
|
+
outline: none;
|
|
152
|
+
background: transparent;
|
|
153
|
+
color: var(--drilldown-fg);
|
|
154
|
+
font: inherit;
|
|
155
|
+
}
|
|
156
|
+
[slot="filter"] input::placeholder {
|
|
157
|
+
color: var(--drilldown-fg-muted);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ── Viewport / panel ── */
|
|
161
|
+
[slot="viewport"] {
|
|
162
|
+
flex: 1;
|
|
163
|
+
min-height: 0;
|
|
164
|
+
overflow: hidden;
|
|
165
|
+
position: relative;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
[slot="panel"] {
|
|
169
|
+
display: flex;
|
|
170
|
+
flex-direction: column;
|
|
171
|
+
gap: var(--a-space-0-5);
|
|
172
|
+
padding: var(--drilldown-list-py) var(--a-space-1);
|
|
173
|
+
height: 100%;
|
|
174
|
+
overflow-y: auto;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
[slot="panel"][data-anim="forward"] {
|
|
178
|
+
animation: drilldown-enter-forward var(--drilldown-duration) var(--drilldown-easing);
|
|
179
|
+
}
|
|
180
|
+
[slot="panel"][data-anim="backward"] {
|
|
181
|
+
animation: drilldown-enter-backward var(--drilldown-duration) var(--drilldown-easing);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@keyframes drilldown-enter-forward {
|
|
185
|
+
from { transform: translateX(var(--a-space-4)); opacity: 0; }
|
|
186
|
+
to { transform: none; opacity: 1; }
|
|
187
|
+
}
|
|
188
|
+
@keyframes drilldown-enter-backward {
|
|
189
|
+
from { transform: translateX(calc(-1 * var(--a-space-4))); opacity: 0; }
|
|
190
|
+
to { transform: none; opacity: 1; }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/* ── Rows ── */
|
|
194
|
+
[role="option"] {
|
|
195
|
+
display: flex;
|
|
196
|
+
align-items: center;
|
|
197
|
+
gap: var(--drilldown-row-gap);
|
|
198
|
+
min-height: var(--drilldown-row-height);
|
|
199
|
+
padding-inline: var(--drilldown-row-px);
|
|
200
|
+
border-radius: var(--drilldown-row-radius);
|
|
201
|
+
cursor: pointer;
|
|
202
|
+
outline: none;
|
|
203
|
+
transition: background var(--drilldown-duration) var(--drilldown-easing);
|
|
204
|
+
}
|
|
205
|
+
[role="option"]:hover {
|
|
206
|
+
background: var(--drilldown-bg-hover);
|
|
207
|
+
}
|
|
208
|
+
[role="option"]:focus-visible,
|
|
209
|
+
[role="option"][tabindex="0"] {
|
|
210
|
+
background: var(--drilldown-bg-active);
|
|
211
|
+
}
|
|
212
|
+
[role="option"]:focus-visible {
|
|
213
|
+
box-shadow: var(--drilldown-focus-ring);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
[slot="dot"] {
|
|
217
|
+
inline-size: var(--drilldown-dot-size);
|
|
218
|
+
block-size: var(--drilldown-dot-size);
|
|
219
|
+
border-radius: var(--a-radius-full);
|
|
220
|
+
flex-shrink: 0;
|
|
221
|
+
background: var(--md-sys-color-neutral);
|
|
222
|
+
}
|
|
223
|
+
[slot="dot"][data-tone="info"] { background: var(--a-info-bg); }
|
|
224
|
+
[slot="dot"][data-tone="success"] { background: var(--a-success-bg); }
|
|
225
|
+
[slot="dot"][data-tone="warning"] { background: var(--a-warning-bg); }
|
|
226
|
+
[slot="dot"][data-tone="danger"] { background: var(--a-danger-bg); }
|
|
227
|
+
[slot="dot"][data-tone="primary"] { background: var(--a-primary-bg); }
|
|
228
|
+
|
|
229
|
+
[slot="main"] {
|
|
230
|
+
display: flex;
|
|
231
|
+
flex-direction: column;
|
|
232
|
+
min-width: 0;
|
|
233
|
+
flex: 1;
|
|
234
|
+
line-height: 1.3;
|
|
235
|
+
}
|
|
236
|
+
[slot="label"] {
|
|
237
|
+
overflow: hidden;
|
|
238
|
+
text-overflow: ellipsis;
|
|
239
|
+
white-space: nowrap;
|
|
240
|
+
}
|
|
241
|
+
[slot="meta"] {
|
|
242
|
+
overflow: hidden;
|
|
243
|
+
text-overflow: ellipsis;
|
|
244
|
+
white-space: nowrap;
|
|
245
|
+
color: var(--drilldown-fg-muted);
|
|
246
|
+
font-size: var(--drilldown-meta-font-size);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
[slot="counts"] {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: center;
|
|
252
|
+
gap: var(--a-space-1);
|
|
253
|
+
flex-shrink: 0;
|
|
254
|
+
}
|
|
255
|
+
[data-count-chip] {
|
|
256
|
+
padding: var(--drilldown-count-chip-py) var(--drilldown-count-chip-px);
|
|
257
|
+
border-radius: var(--drilldown-count-chip-radius);
|
|
258
|
+
font-size: var(--drilldown-count-chip-font-size);
|
|
259
|
+
font-variant-numeric: tabular-nums;
|
|
260
|
+
line-height: 1;
|
|
261
|
+
background: var(--drilldown-count-chip-bg);
|
|
262
|
+
color: var(--drilldown-count-chip-fg);
|
|
263
|
+
white-space: nowrap;
|
|
264
|
+
}
|
|
265
|
+
[data-count-chip][data-tone="info"] { background: var(--a-info-bg); color: var(--md-sys-color-info-on-info); }
|
|
266
|
+
[data-count-chip][data-tone="success"] { background: var(--a-success-bg); color: var(--md-sys-color-success-on-success); }
|
|
267
|
+
[data-count-chip][data-tone="warning"] { background: var(--a-warning-bg); color: var(--md-sys-color-warning-on-warning); }
|
|
268
|
+
[data-count-chip][data-tone="danger"] { background: var(--a-danger-bg); color: var(--md-sys-color-danger-on-danger); }
|
|
269
|
+
[data-count-chip][data-tone="primary"] { background: var(--a-primary-bg); color: var(--md-sys-color-primary-on-primary); }
|
|
270
|
+
|
|
271
|
+
[slot="chevron"] {
|
|
272
|
+
--a-icon-size: var(--drilldown-chevron-size);
|
|
273
|
+
color: var(--drilldown-fg-muted);
|
|
274
|
+
flex-shrink: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* ── Loading / empty ── */
|
|
278
|
+
[data-drilldown-skeleton] {
|
|
279
|
+
margin: var(--a-space-0-5) var(--a-space-1);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* ── Live region (visually hidden, still announced) ── */
|
|
283
|
+
[data-visually-hidden] {
|
|
284
|
+
position: absolute;
|
|
285
|
+
width: 1px;
|
|
286
|
+
height: 1px;
|
|
287
|
+
padding: 0;
|
|
288
|
+
margin: -1px;
|
|
289
|
+
overflow: hidden;
|
|
290
|
+
clip: rect(0, 0, 0, 0);
|
|
291
|
+
white-space: nowrap;
|
|
292
|
+
border: 0;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
@media (prefers-reduced-motion: reduce) {
|
|
296
|
+
[slot="panel"][data-anim] {
|
|
297
|
+
animation: none;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/* `[static]` — explicit opt-out, same effect as prefers-reduced-motion. */
|
|
302
|
+
:scope[static] [slot="panel"][data-anim] {
|
|
303
|
+
animation: none;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<drilldown-ui>` — Single-panel, multi-level drill-in menu. One list panel slides between
|
|
3
|
+
levels (a level header with back navigation replaces stacking a column
|
|
4
|
+
per level) — for hierarchical data where miller columns don't fit the
|
|
5
|
+
viewport (>2 levels, >12 top-level entries, or narrow layouts). Rows
|
|
6
|
+
compose a leading dot/icon, primary label, optional meta line, and
|
|
7
|
+
trailing row-native count chips (not full <badge-ui>, which reads
|
|
8
|
+
oversized at row density) — plus a drill-in chevron on branch items.
|
|
9
|
+
Set `.items` to a tree of `{value, label, meta?, dot?, counts?, children?}`
|
|
10
|
+
nodes; `children` may be an array (sync) or a function returning an
|
|
11
|
+
array/Promise (lazy, fetched on drill-in — a loading level is shown via
|
|
12
|
+
<skeleton-ui> while it resolves). Distinct from <tree-ui> (inline
|
|
13
|
+
expand/collapse — right for file-tree shapes, wrong for wide/deep data
|
|
14
|
+
where the expanded tree becomes a wall of rows), <nav-ui> (flat app
|
|
15
|
+
navigation, not hierarchical drill-in), and <context-menu> (transient
|
|
16
|
+
popover submenus, not a persistent content panel).
|
|
17
|
+
|
|
18
|
+
*
|
|
19
|
+
* @see https://ui-kit.exe.xyz/site/components/drilldown
|
|
20
|
+
*
|
|
21
|
+
* Type declarations generated by scripts/build/dts-codegen.mjs from
|
|
22
|
+
* the component's `.a2ui.json` sidecar(s). Edit the source `.yaml`,
|
|
23
|
+
* run `npm run build:components`, then `npm run codegen:dts` to
|
|
24
|
+
* regenerate; or hand-author this file fully if rich event types are
|
|
25
|
+
* needed beyond what the yaml `events:` block can express.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { UIElement } from '../../core/element.js';
|
|
29
|
+
|
|
30
|
+
export interface DrilldownNavigateEventDetail {
|
|
31
|
+
/** The newly-shown level's ancestor value chain. */
|
|
32
|
+
path: string[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type DrilldownNavigateEvent = CustomEvent<DrilldownNavigateEventDetail>;
|
|
36
|
+
export interface DrilldownSelectEventDetail {
|
|
37
|
+
/** The activated node object. */
|
|
38
|
+
item: Record<string, unknown>;
|
|
39
|
+
/** Ancestor value chain the selected item lives at. */
|
|
40
|
+
path: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type DrilldownSelectEvent = CustomEvent<DrilldownSelectEventDetail>;
|
|
44
|
+
|
|
45
|
+
export class UIDrilldown extends UIElement {
|
|
46
|
+
/** Root-level array of node objects: {value, label, meta?, dot?, counts?, children?, leaf?}. `value` is the stable id used in `path` and event details. `dot` names a semantic tone (info, success, warning, danger, primary, neutral) rendered as a small leading color swatch. `counts` is an array of {variant?, value} rendered as compact trailing chips. `children` is either an array of child nodes (resolved synchronously) or a function `(item) => array | Promise<array>` for lazy per-level fetch — a loading level renders while the promise is pending. `leaf: true` forces no drill chevron even when `children` is present (rare — normally omit `children` instead). */
|
|
47
|
+
items: string;
|
|
48
|
+
/** Show a filter input pinned above the list, filtering the current level's rows by label/meta. */
|
|
49
|
+
filterable: boolean;
|
|
50
|
+
/** Current drilled-in level, as an array of ancestor item `value`s (root = `[]`). Setting `.path` restores directly to that nested level without animating through every intermediate level — the deep-link/URL-restore path. Hand-managed (not the generic `reflect:` mechanism, which can't JSON-encode arrays) — it still genuinely reflects to a JSON-encoded `path` attribute both ways (property → attribute and attribute → property), unlike most array props on this kit. */
|
|
51
|
+
path: string;
|
|
52
|
+
/** Placeholder text for the filter input (only rendered when `[filterable]`). */
|
|
53
|
+
placeholder: string;
|
|
54
|
+
/** Level-header title shown at the root level (depth 0). Empty by default (no title row). */
|
|
55
|
+
rootLabel: string;
|
|
56
|
+
/** When true, clicking/activating a branch item (one with children) BOTH fires `select` and drills into it — the Schema Manager shape, where picking a namespace is both a selection and a navigation. Default false: branch activation only drills in; only leaf activation fires `select`. */
|
|
57
|
+
selectOnDrill: boolean;
|
|
58
|
+
/** Suppress the horizontal slide transition between levels — instant swap. Also honored automatically under `prefers-reduced-motion: reduce`. */
|
|
59
|
+
static: boolean;
|
|
60
|
+
|
|
61
|
+
addEventListener(type: 'navigate', listener: (ev: DrilldownNavigateEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
62
|
+
addEventListener(type: 'select', listener: (ev: DrilldownSelectEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
63
|
+
addEventListener<K extends keyof HTMLElementEventMap>(
|
|
64
|
+
type: K,
|
|
65
|
+
listener: (this: UIDrilldown, ev: HTMLElementEventMap[K]) => unknown,
|
|
66
|
+
options?: boolean | AddEventListenerOptions,
|
|
67
|
+
): void;
|
|
68
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# drilldown — Examples
|
|
2
|
+
|
|
3
|
+
## Schema Manager — namespace → node type → detail
|
|
4
|
+
|
|
5
|
+
```html
|
|
6
|
+
<drilldown-ui id="drilldown-schema" root-label="Namespaces" style="width:22rem; height:24rem; border:1px solid var(--md-sys-color-neutral-outline); border-radius:var(--a-radius-lg);"></drilldown-ui>
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## filterable
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<drilldown-ui id="drilldown-filter" filterable placeholder="Filter namespaces…" root-label="Namespaces" style="width:22rem; height:20rem; border:1px solid var(--md-sys-color-neutral-outline); border-radius:var(--a-radius-lg);"></drilldown-ui>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## select-on-drill
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<drilldown-ui id="drilldown-select-on-drill" select-on-drill root-label="Namespaces" style="width:22rem; height:18rem; border:1px solid var(--md-sys-color-neutral-outline); border-radius:var(--a-radius-lg);"></drilldown-ui>
|
|
19
|
+
<p data-drilldown-log style="margin-top: var(--a-space-2);">Activate a namespace — it selects AND drills in.</p>
|
|
20
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<drilldown-ui>` — auto-registers the tag on import.
|
|
3
|
+
*
|
|
4
|
+
* For non-side-effect class import (test isolation, tag override), use
|
|
5
|
+
* the `class` subpath:
|
|
6
|
+
*
|
|
7
|
+
* import { UIDrilldown } from '@adia-ai/web-components/components/drilldown/class';
|
|
8
|
+
*
|
|
9
|
+
* @see ../../USAGE.md#registration--auto-vs-explicit
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { defineIfFree } from '../../core/register.js';
|
|
13
|
+
import { UIDrilldown } from './drilldown.class.js';
|
|
14
|
+
|
|
15
|
+
defineIfFree('drilldown-ui', UIDrilldown);
|
|
16
|
+
|
|
17
|
+
export { UIDrilldown };
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
$schema: ../../../../scripts/schemas/component.yaml.schema.json
|
|
2
|
+
name: UIDrilldown
|
|
3
|
+
tag: drilldown-ui
|
|
4
|
+
status: beta
|
|
5
|
+
component: Drilldown
|
|
6
|
+
category: navigation
|
|
7
|
+
version: 1
|
|
8
|
+
description: |
|
|
9
|
+
Single-panel, multi-level drill-in menu. One list panel slides between
|
|
10
|
+
levels (a level header with back navigation replaces stacking a column
|
|
11
|
+
per level) — for hierarchical data where miller columns don't fit the
|
|
12
|
+
viewport (>2 levels, >12 top-level entries, or narrow layouts). Rows
|
|
13
|
+
compose a leading dot/icon, primary label, optional meta line, and
|
|
14
|
+
trailing row-native count chips (not full <badge-ui>, which reads
|
|
15
|
+
oversized at row density) — plus a drill-in chevron on branch items.
|
|
16
|
+
Set `.items` to a tree of `{value, label, meta?, dot?, counts?, children?}`
|
|
17
|
+
nodes; `children` may be an array (sync) or a function returning an
|
|
18
|
+
array/Promise (lazy, fetched on drill-in — a loading level is shown via
|
|
19
|
+
<skeleton-ui> while it resolves). Distinct from <tree-ui> (inline
|
|
20
|
+
expand/collapse — right for file-tree shapes, wrong for wide/deep data
|
|
21
|
+
where the expanded tree becomes a wall of rows), <nav-ui> (flat app
|
|
22
|
+
navigation, not hierarchical drill-in), and <context-menu> (transient
|
|
23
|
+
popover submenus, not a persistent content panel).
|
|
24
|
+
# Per ADR-0027 — primitives that programmatically create other primitives
|
|
25
|
+
# do NOT auto-import them. Consumer (or demo shell) must explicitly import.
|
|
26
|
+
composes:
|
|
27
|
+
- icon-ui
|
|
28
|
+
- skeleton-ui
|
|
29
|
+
- empty-state-ui
|
|
30
|
+
props:
|
|
31
|
+
items:
|
|
32
|
+
description: >-
|
|
33
|
+
Root-level array of node objects: {value, label, meta?, dot?,
|
|
34
|
+
counts?, children?, leaf?}. `value` is the stable id used in `path`
|
|
35
|
+
and event details. `dot` names a semantic tone (info, success,
|
|
36
|
+
warning, danger, primary, neutral) rendered as a small leading
|
|
37
|
+
color swatch. `counts` is an array of {variant?, value} rendered as
|
|
38
|
+
compact trailing chips. `children` is either an array of child
|
|
39
|
+
nodes (resolved synchronously) or a function `(item) => array |
|
|
40
|
+
Promise<array>` for lazy per-level fetch — a loading level renders
|
|
41
|
+
while the promise is pending. `leaf: true` forces no drill chevron
|
|
42
|
+
even when `children` is present (rare — normally omit `children`
|
|
43
|
+
instead).
|
|
44
|
+
type: array
|
|
45
|
+
items:
|
|
46
|
+
type: object
|
|
47
|
+
default: []
|
|
48
|
+
dynamic: true
|
|
49
|
+
path:
|
|
50
|
+
description: >-
|
|
51
|
+
Current drilled-in level, as an array of ancestor item `value`s
|
|
52
|
+
(root = `[]`). Setting `.path` restores directly to that nested
|
|
53
|
+
level without animating through every intermediate level — the
|
|
54
|
+
deep-link/URL-restore path. Hand-managed (not the generic
|
|
55
|
+
`reflect:` mechanism, which can't JSON-encode arrays) — it still
|
|
56
|
+
genuinely reflects to a JSON-encoded `path` attribute both ways
|
|
57
|
+
(property → attribute and attribute → property), unlike most array
|
|
58
|
+
props on this kit.
|
|
59
|
+
type: array
|
|
60
|
+
items:
|
|
61
|
+
type: string
|
|
62
|
+
default: []
|
|
63
|
+
dynamic: true
|
|
64
|
+
rootLabel:
|
|
65
|
+
description: Level-header title shown at the root level (depth 0). Empty by default (no title row).
|
|
66
|
+
type: string
|
|
67
|
+
default: ""
|
|
68
|
+
reflect: true
|
|
69
|
+
filterable:
|
|
70
|
+
description: Show a filter input pinned above the list, filtering the current level's rows by label/meta.
|
|
71
|
+
type: boolean
|
|
72
|
+
default: false
|
|
73
|
+
reflect: true
|
|
74
|
+
placeholder:
|
|
75
|
+
description: Placeholder text for the filter input (only rendered when `[filterable]`).
|
|
76
|
+
type: string
|
|
77
|
+
default: "Filter…"
|
|
78
|
+
reflect: true
|
|
79
|
+
selectOnDrill:
|
|
80
|
+
description: >-
|
|
81
|
+
When true, clicking/activating a branch item (one with children)
|
|
82
|
+
BOTH fires `select` and drills into it — the Schema Manager shape,
|
|
83
|
+
where picking a namespace is both a selection and a navigation.
|
|
84
|
+
Default false: branch activation only drills in; only leaf
|
|
85
|
+
activation fires `select`.
|
|
86
|
+
type: boolean
|
|
87
|
+
default: false
|
|
88
|
+
reflect: true
|
|
89
|
+
attribute: select-on-drill
|
|
90
|
+
static:
|
|
91
|
+
description: >-
|
|
92
|
+
Suppress the horizontal slide transition between levels — instant
|
|
93
|
+
swap. Also honored automatically under `prefers-reduced-motion: reduce`.
|
|
94
|
+
type: boolean
|
|
95
|
+
default: false
|
|
96
|
+
reflect: true
|
|
97
|
+
events:
|
|
98
|
+
select:
|
|
99
|
+
description: >
|
|
100
|
+
Fired when a leaf item is activated (click/Enter), or when a branch
|
|
101
|
+
item is activated with `[select-on-drill]` set. detail: { path,
|
|
102
|
+
item }. `path` is the drilled-in level the item lives at (the
|
|
103
|
+
current `.path` at the time of activation); `item` is the raw node
|
|
104
|
+
object.
|
|
105
|
+
detail:
|
|
106
|
+
path:
|
|
107
|
+
type: array
|
|
108
|
+
items:
|
|
109
|
+
type: string
|
|
110
|
+
description: Ancestor value chain the selected item lives at.
|
|
111
|
+
item:
|
|
112
|
+
type: object
|
|
113
|
+
description: The activated node object.
|
|
114
|
+
navigate:
|
|
115
|
+
description: >
|
|
116
|
+
Fired whenever the shown level changes — drill-in, back, breadcrumb
|
|
117
|
+
jump, or a programmatic `.path` assignment. detail: { path }. Hosts
|
|
118
|
+
mirror this to the URL instead of listening to `select`.
|
|
119
|
+
detail:
|
|
120
|
+
path:
|
|
121
|
+
type: array
|
|
122
|
+
items:
|
|
123
|
+
type: string
|
|
124
|
+
description: The newly-shown level's ancestor value chain.
|
|
125
|
+
slots:
|
|
126
|
+
breadcrumb:
|
|
127
|
+
description: >-
|
|
128
|
+
Optional slot for a consumer-supplied <breadcrumb-ui> in the level
|
|
129
|
+
header, for deep hierarchies. Not managed by drilldown-ui — the
|
|
130
|
+
consumer wires jump clicks to `.path = [...]` itself.
|
|
131
|
+
header:
|
|
132
|
+
description: Auto-stamped level-header container (back affordance + breadcrumb + title/count). Structural — not consumer-overridable.
|
|
133
|
+
back:
|
|
134
|
+
description: Auto-stamped back-affordance <button> (chevron + parent-level label). Hidden at the root level.
|
|
135
|
+
title:
|
|
136
|
+
description: Auto-stamped title cluster (current-level label + item count) inside the header.
|
|
137
|
+
filter:
|
|
138
|
+
description: Auto-stamped filter-input row, shown only when `[filterable]` is set.
|
|
139
|
+
viewport:
|
|
140
|
+
description: Auto-stamped clipping container for the current level's panel (hosts the slide-transition overflow clip).
|
|
141
|
+
dot:
|
|
142
|
+
description: Auto-stamped per-row leading color swatch, rendered when the row's data item declares a `dot` tone.
|
|
143
|
+
main:
|
|
144
|
+
description: Auto-stamped per-row content column (label + optional meta line).
|
|
145
|
+
meta:
|
|
146
|
+
description: Auto-stamped per-row secondary meta line, rendered when the row's data item declares `meta`.
|
|
147
|
+
counts:
|
|
148
|
+
description: Auto-stamped per-row trailing count-chip cluster, rendered when the row's data item declares `counts`.
|
|
149
|
+
states:
|
|
150
|
+
- name: idle
|
|
151
|
+
description: Default, ready for interaction.
|
|
152
|
+
- name: loading
|
|
153
|
+
description: A lazy level's children are being resolved (async `children` function pending).
|
|
154
|
+
- name: empty
|
|
155
|
+
description: The current level has no items.
|
|
156
|
+
traits: []
|
|
157
|
+
tokens:
|
|
158
|
+
--drilldown-row-height:
|
|
159
|
+
description: Height of each row.
|
|
160
|
+
--drilldown-row-radius:
|
|
161
|
+
description: Border radius of each row.
|
|
162
|
+
--drilldown-row-px:
|
|
163
|
+
description: Inline padding of each row.
|
|
164
|
+
--drilldown-row-gap:
|
|
165
|
+
description: Gap between row elements (dot / main / counts / chevron).
|
|
166
|
+
--drilldown-bg-hover:
|
|
167
|
+
description: Row background on hover.
|
|
168
|
+
--drilldown-bg-active:
|
|
169
|
+
description: Row background when focused/active (roving tabindex).
|
|
170
|
+
--drilldown-fg:
|
|
171
|
+
description: Primary row text color.
|
|
172
|
+
--drilldown-fg-muted:
|
|
173
|
+
description: Muted text color (meta line, chevron, back affordance).
|
|
174
|
+
--drilldown-dot-size:
|
|
175
|
+
description: Diameter of the leading color dot.
|
|
176
|
+
--drilldown-count-chip-px:
|
|
177
|
+
description: Inline padding of a trailing count chip.
|
|
178
|
+
--drilldown-count-chip-font-size:
|
|
179
|
+
description: Font size of a trailing count chip.
|
|
180
|
+
--drilldown-count-chip-radius:
|
|
181
|
+
description: Border radius of a trailing count chip.
|
|
182
|
+
--drilldown-header-px:
|
|
183
|
+
description: Inline padding of the level header.
|
|
184
|
+
--drilldown-header-py:
|
|
185
|
+
description: Block padding of the level header.
|
|
186
|
+
--drilldown-duration:
|
|
187
|
+
description: Slide-transition duration.
|
|
188
|
+
--drilldown-easing:
|
|
189
|
+
description: Slide-transition easing function.
|
|
190
|
+
--drilldown-focus-ring:
|
|
191
|
+
description: Focus ring box-shadow for rows and the back button.
|
|
192
|
+
requiredIcons:
|
|
193
|
+
- caret-left
|
|
194
|
+
- caret-right
|
|
195
|
+
- magnifying-glass
|
|
196
|
+
a2ui:
|
|
197
|
+
rules:
|
|
198
|
+
- >-
|
|
199
|
+
Use <drilldown-ui> for a hierarchical namespace/category → item
|
|
200
|
+
drill-in over a SINGLE panel — the sibling shape to miller columns,
|
|
201
|
+
chosen when the viewport can't afford a column per level (>2
|
|
202
|
+
levels, or a level with more than ~12 entries). For inline
|
|
203
|
+
expand/collapse trees, use <tree-ui>. For flat app navigation, use
|
|
204
|
+
<nav-ui>. For a small non-searchable popover of actions, use
|
|
205
|
+
<menu-ui> or <context-menu>.
|
|
206
|
+
- >-
|
|
207
|
+
Set `.items` programmatically (array of node objects), NOT
|
|
208
|
+
declarative children — drilldown-ui is a content-only, data-driven
|
|
209
|
+
primitive with no children markup contract.
|
|
210
|
+
- >-
|
|
211
|
+
Listen for `select` (leaf activation, or branch activation with
|
|
212
|
+
`[select-on-drill]`) and `navigate` (any level change) — mirror
|
|
213
|
+
`navigate`'s `path` to the URL, not `select`'s.
|
|
214
|
+
- >-
|
|
215
|
+
A `path` array restores directly to a nested level (deep link)
|
|
216
|
+
without animating through intermediates — set it once on mount
|
|
217
|
+
rather than calling drill-in repeatedly.
|
|
218
|
+
anti_patterns: []
|
|
219
|
+
examples:
|
|
220
|
+
- name: basic-drilldown
|
|
221
|
+
description: Basic Drilldown usage
|
|
222
|
+
a2ui: >-
|
|
223
|
+
[
|
|
224
|
+
{
|
|
225
|
+
"id": "root",
|
|
226
|
+
"component": "Card",
|
|
227
|
+
"children": [
|
|
228
|
+
"sec"
|
|
229
|
+
]
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"id": "sec",
|
|
233
|
+
"component": "Section",
|
|
234
|
+
"children": [
|
|
235
|
+
"comp"
|
|
236
|
+
]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"id": "comp",
|
|
240
|
+
"component": "Drilldown"
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
keywords:
|
|
244
|
+
- drilldown
|
|
245
|
+
- drill-down
|
|
246
|
+
- miller
|
|
247
|
+
- miller-columns
|
|
248
|
+
- namespace
|
|
249
|
+
- hierarchy
|
|
250
|
+
- navigator
|
|
251
|
+
- catalog-browser
|
|
252
|
+
synonyms:
|
|
253
|
+
hierarchy:
|
|
254
|
+
- tree
|
|
255
|
+
- nav
|
|
256
|
+
- drilldown
|
|
257
|
+
miller:
|
|
258
|
+
- drilldown
|
|
259
|
+
- tree
|
|
260
|
+
- column
|
|
261
|
+
navigator:
|
|
262
|
+
- tree
|
|
263
|
+
- nav
|
|
264
|
+
- drilldown
|
|
265
|
+
- sidebar
|
|
266
|
+
related:
|
|
267
|
+
- Tree
|
|
268
|
+
- List
|
|
269
|
+
- Nav
|
|
270
|
+
- Breadcrumb
|
|
271
|
+
- Menu
|
package/components/index.js
CHANGED
|
@@ -34,6 +34,7 @@ export { UISegment } from './segment/segment.js';
|
|
|
34
34
|
export { UISegmented } from './segmented/segmented.js';
|
|
35
35
|
export { UIRange } from './range/range.js';
|
|
36
36
|
export { UITree, UITreeItem } from './tree/tree.js';
|
|
37
|
+
export { UIDrilldown } from './drilldown/drilldown.js';
|
|
37
38
|
export { UIPane } from './pane/pane.js';
|
|
38
39
|
export { UIPage } from './page/page.js';
|
|
39
40
|
export { UIChatInput } from './chat-thread/chat-input.js';
|