@adia-ai/web-components 0.8.43 → 0.8.45
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 +54 -0
- package/components/avatar/avatar.class.js +12 -1
- package/components/button/button.d.ts +4 -0
- package/components/chart/chart.a2ui.json +26 -0
- package/components/chart/chart.class.js +1304 -222
- package/components/chart/chart.css +151 -1
- package/components/chart/chart.d.ts +6 -0
- package/components/chart/chart.yaml +57 -0
- package/components/chart-legend/chart-legend.a2ui.json +17 -2
- package/components/chart-legend/chart-legend.class.js +69 -4
- package/components/chart-legend/chart-legend.css +65 -1
- package/components/chart-legend/chart-legend.d.ts +4 -2
- package/components/chart-legend/chart-legend.examples.md +4 -4
- package/components/chart-legend/chart-legend.yaml +43 -3
- package/components/combobox/combobox.a2ui.json +3 -0
- package/components/combobox/combobox.class.js +9 -8
- package/components/combobox/combobox.css +25 -4
- package/components/combobox/combobox.yaml +6 -0
- package/components/command/command.css +17 -1
- package/components/context-menu/context-menu.a2ui.json +8 -3
- package/components/context-menu/context-menu.class.js +46 -5
- package/components/context-menu/context-menu.d.ts +8 -3
- package/components/context-menu/context-menu.examples.md +2 -2
- package/components/context-menu/context-menu.yaml +22 -5
- package/components/heatmap/heatmap.a2ui.json +5 -0
- package/components/heatmap/heatmap.d.ts +2 -0
- package/components/heatmap/heatmap.yaml +8 -0
- package/components/input/input.a2ui.json +2 -2
- package/components/input/input.class.js +12 -7
- package/components/input/input.yaml +6 -5
- package/components/integration-card/integration-card.d.ts +2 -0
- package/components/nav/nav.a2ui.json +2 -2
- package/components/nav/nav.css +1 -1
- package/components/nav/nav.d.ts +1 -1
- package/components/nav/nav.yaml +14 -3
- package/components/nav-group/nav-group.css +37 -3
- package/components/noodles/noodles.a2ui.json +0 -15
- package/components/noodles/noodles.yaml +0 -12
- package/components/number-format/number-format.class.js +10 -0
- package/components/pagination/pagination.class.js +140 -26
- package/components/popover/popover.d.ts +2 -0
- package/components/progress/progress.class.js +11 -6
- package/components/range/range.class.js +9 -1
- package/components/search/search.class.js +39 -5
- package/components/select/select.a2ui.json +10 -1
- package/components/select/select.class.js +34 -14
- package/components/select/select.css +39 -1
- package/components/select/select.d.ts +2 -0
- package/components/select/select.yaml +19 -1
- package/components/stream/stream.d.ts +2 -0
- package/components/table/cell-types.js +9 -0
- package/components/table/table.a2ui.json +6 -1
- package/components/table/table.class.js +265 -34
- package/components/table/table.css +38 -10
- package/components/table/table.d.ts +3 -1
- package/components/table/table.examples.md +2 -2
- package/components/table/table.yaml +15 -2
- package/components/table-toolbar/table-toolbar.a2ui.json +43 -4
- package/components/table-toolbar/table-toolbar.class.js +407 -28
- package/components/table-toolbar/table-toolbar.css +299 -0
- package/components/table-toolbar/table-toolbar.d.ts +15 -1
- package/components/table-toolbar/table-toolbar.yaml +162 -15
- package/components/tag/tag.class.js +13 -1
- package/components/text/text.a2ui.json +3 -3
- package/components/text/text.d.ts +5 -3
- package/components/text/text.yaml +3 -3
- package/components/textarea/textarea.class.js +9 -1
- package/components/tour/tour.d.ts +10 -0
- package/core/a11y.d.ts +22 -0
- package/core/a11y.js +64 -0
- package/core/anchor.js +9 -5
- package/core/data-stream.js +37 -2
- package/core/element.js +1 -1
- package/core/index.d.ts +1 -0
- package/core/index.js +1 -0
- package/core/provider.d.ts +9 -13
- package/core/provider.js +9 -113
- package/core/store.d.ts +46 -0
- package/core/store.js +89 -0
- package/custom-elements.json +127 -33
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +119 -119
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/access-requests/access-requests.examples.html +1 -1
- package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +7 -7
- package/patterns/agent-cost/agent-cost.examples.html +6 -6
- package/patterns/agent-memory/agent-memory.examples.html +3 -3
- package/patterns/agent-prompt-library/agent-prompt-library.examples.html +8 -8
- package/patterns/agent-tool-call/agent-tool-call.examples.html +1 -1
- package/patterns/approvals/approvals.examples.html +6 -6
- package/patterns/audit-log/audit-log.examples.html +1 -1
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +4 -4
- package/patterns/chart-in-card/chart-in-card.examples.html +114 -0
- package/patterns/chart-in-card/chart-in-card.examples.js +37 -0
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +5 -5
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +2 -2
- package/patterns/diff-review/diff-review.examples.html +6 -6
- package/patterns/export-flow/export-flow.examples.html +2 -2
- package/patterns/filter-bar/filter-bar.examples.html +2 -2
- package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +2 -2
- package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
- package/patterns/marketing-engagement/marketing-engagement.examples.html +4 -4
- 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-sharing/permissions-sharing.examples.html +2 -2
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +4 -4
- package/patterns/search-discovery/search-discovery.examples.html +2 -2
- package/styles/api/sizing.css +46 -0
- package/styles/type/roles.css +29 -9
|
@@ -26,6 +26,30 @@
|
|
|
26
26
|
--table-toolbar-search-min: 14rem;
|
|
27
27
|
--table-toolbar-search-max: 22rem;
|
|
28
28
|
|
|
29
|
+
/* ── Search-tight stage (ADR-0076, REQ-S-002) ──
|
|
30
|
+
Stepped-down search field extents applied under the
|
|
31
|
+
search-tight/icon-only/overflow @container query below (or the
|
|
32
|
+
matching [stage] pin). Public so a consumer can retune the
|
|
33
|
+
compacted width without forking component CSS, same posture as
|
|
34
|
+
every other --table-toolbar-* token. */
|
|
35
|
+
--table-toolbar-search-tight-min: 9rem;
|
|
36
|
+
--table-toolbar-search-tight-max: 14rem;
|
|
37
|
+
|
|
38
|
+
/* ── Compaction breakpoints (ADR-0076, REQ-M-006) ──
|
|
39
|
+
Normative default pixel widths, token-indirected so a consumer can
|
|
40
|
+
retune without forking component CSS. Boundaries are inclusive on
|
|
41
|
+
the narrower side (max-width semantics) — a container at exactly
|
|
42
|
+
the boundary width renders the narrower of the two adjacent
|
|
43
|
+
stages. MUST stay monotonically decreasing
|
|
44
|
+
(bp-search-tight > bp-icon-only > bp-overflow); no stage-specific
|
|
45
|
+
@container rules exist yet (step 1 lands only this substrate —
|
|
46
|
+
steps 2/3/5 land each stage's own CSS). Same three thresholds
|
|
47
|
+
data-stage-resolved's ResizeObserver (step 7) will classify
|
|
48
|
+
against — one source of truth, never a second hardcoded copy. */
|
|
49
|
+
--table-toolbar-bp-search-tight: 56rem;
|
|
50
|
+
--table-toolbar-bp-icon-only: 40rem;
|
|
51
|
+
--table-toolbar-bp-overflow: 26rem;
|
|
52
|
+
|
|
29
53
|
/* Popover tokens removed — popover escapes to top layer and
|
|
30
54
|
cannot inherit @scope tokens. Raw --a-* tokens are used
|
|
31
55
|
directly in the unscoped popover rules below (see comment
|
|
@@ -38,6 +62,185 @@
|
|
|
38
62
|
box-sizing: border-box;
|
|
39
63
|
display: block;
|
|
40
64
|
color: var(--md-sys-color-neutral-on-surface);
|
|
65
|
+
/* Width-only compaction measurement substrate (ADR-0076, REQ-M-001).
|
|
66
|
+
inline-size containment only — never `size` — per chart.css's own
|
|
67
|
+
documented size-containment trap (container-type: size forces
|
|
68
|
+
block-size containment, collapsing any height-less element; chart
|
|
69
|
+
needs it only because it queries aspect-ratio, table-toolbar's axis
|
|
70
|
+
is width alone). Steps 3/5 land icon-only/overflow's own CSS
|
|
71
|
+
against this same container. */
|
|
72
|
+
container-type: inline-size;
|
|
73
|
+
container-name: table-toolbar;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ═══════ Search-tight stage ═══════ (ADR-0076, REQ-S-002/REQ-O-001, step 2)
|
|
77
|
+
Auto-snap: the container query fires the step-down once the toolbar's
|
|
78
|
+
own inline-size crosses --table-toolbar-bp-search-tight (56rem
|
|
79
|
+
default). `max-width` is inclusive-on-the-narrower-side by construction
|
|
80
|
+
(REQ-M-006) — a container at exactly the boundary width already renders
|
|
81
|
+
search-tight. `:not([stage])`/`[stage=""]` together cover "no pin" —
|
|
82
|
+
an explicit [stage="full"] pin must NOT auto-snap even inside a narrow
|
|
83
|
+
container (REQ-O-001, the pin wins), so the auto-snap selector
|
|
84
|
+
excludes every OTHER pinned value too.
|
|
85
|
+
|
|
86
|
+
BUG (caught in review, CodeRabbit on PR #1672, verified live in a real
|
|
87
|
+
browser before fixing): the token reassignment below targets
|
|
88
|
+
`[data-toolbar]`, a DESCENDANT of `:scope` — never `:scope` itself. A
|
|
89
|
+
container query only matches elements whose NEAREST ANCESTOR
|
|
90
|
+
establishes the named container; the container element is never its
|
|
91
|
+
own ancestor, so `@container table-toolbar (...) { :scope { ... } }`
|
|
92
|
+
can never match the host that declared `container-type` in the first
|
|
93
|
+
place — it's permanently-dead CSS, regardless of the container's
|
|
94
|
+
actual width. The custom properties still cascade correctly from
|
|
95
|
+
`[data-toolbar]` down to `[data-search]` (a further descendant), so
|
|
96
|
+
targeting the wrapper one level down is both the fix and the reason
|
|
97
|
+
it works: normal inheritance, no container-query involvement needed
|
|
98
|
+
for the property to reach its consumer.
|
|
99
|
+
|
|
100
|
+
CSS custom properties cannot be referenced inside an `@container` size
|
|
101
|
+
query's condition (only `style()` container queries read custom
|
|
102
|
+
properties, and those query computed values, not literal breakpoints)
|
|
103
|
+
— so the boundary below is the literal `56rem`, bound in this comment
|
|
104
|
+
to --table-toolbar-bp-search-tight's own default one line above; the
|
|
105
|
+
table-toolbar.test.js source-assertion suite pins the two values equal
|
|
106
|
+
so this literal can never silently drift from the token. */
|
|
107
|
+
@container table-toolbar (max-width: 56rem) {
|
|
108
|
+
:scope:is(:not([stage]), [stage=""]) > [data-toolbar] {
|
|
109
|
+
--table-toolbar-search-min: var(--table-toolbar-search-tight-min);
|
|
110
|
+
--table-toolbar-search-max: var(--table-toolbar-search-tight-max);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Explicit pin (REQ-O-001) — forces the search-tight extents regardless
|
|
115
|
+
of the container's actual measured width. Also applies at
|
|
116
|
+
[stage="icon-only"]/[stage="overflow"] (steps 3/5's own, MORE compact
|
|
117
|
+
pins): each later stage is strictly more compact than the last
|
|
118
|
+
(REQ-S), so the search field never widens back out just because a
|
|
119
|
+
tighter stage hasn't landed its own CSS yet. */
|
|
120
|
+
:scope:is([stage="search-tight"], [stage="icon-only"], [stage="overflow"]) {
|
|
121
|
+
--table-toolbar-search-min: var(--table-toolbar-search-tight-min);
|
|
122
|
+
--table-toolbar-search-max: var(--table-toolbar-search-tight-max);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* ═══════ Icon-only stage ═══════ (ADR-0076, REQ-S-003/REQ-M-003/REQ-M-004,
|
|
126
|
+
step 3) — [data-controls] buttons drop their rendered label; the range
|
|
127
|
+
summary's own compaction/hide (REQ-S-003, step 4) rides the SAME
|
|
128
|
+
breakpoint just below, since both are decided by the same container
|
|
129
|
+
crossing --table-toolbar-bp-icon-only.
|
|
130
|
+
|
|
131
|
+
::after content:none overrides button.css's own `:scope[text]::after {
|
|
132
|
+
content: attr(text) }` generated-content rule (REQ-M-003) — aria-label
|
|
133
|
+
is untouched (button-ui stamps it from [text] unconditionally in its
|
|
134
|
+
own render(), REQ-X-001), so the accessible name survives regardless of
|
|
135
|
+
the CSS-hidden visual label. The selector below is deliberately more
|
|
136
|
+
specific than button.css's own (adds the `:scope` ancestor + `[text]`)
|
|
137
|
+
so it wins the cascade outright rather than relying on scope-proximity
|
|
138
|
+
tie-breaking, which would resolve in button.css's OWN favor at equal
|
|
139
|
+
specificity (its rule is proximity-0 to its own host). Geometry mirrors
|
|
140
|
+
button-ui's own [data-icon-only] treatment exactly (REQ-M-004) —
|
|
141
|
+
--button-px/width are button-ui's own exposed tokens, set here from the
|
|
142
|
+
table-toolbar side the same way [data-sort-row][data-active] overrides
|
|
143
|
+
menu-item-ui's tokens above. Literal `40rem` bound to
|
|
144
|
+
--table-toolbar-bp-icon-only's default (same duplication rationale +
|
|
145
|
+
source-assertion test as the search-tight boundary above). */
|
|
146
|
+
@container table-toolbar (max-width: 40rem) {
|
|
147
|
+
:scope:is(:not([stage]), [stage=""]) [data-toolbar-btn][text]::after {
|
|
148
|
+
content: none;
|
|
149
|
+
}
|
|
150
|
+
:scope:is(:not([stage]), [stage=""]) [data-toolbar-btn] {
|
|
151
|
+
--button-px: 0;
|
|
152
|
+
|
|
153
|
+
width: var(--button-height);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
:scope:is([stage="icon-only"], [stage="overflow"]) [data-toolbar-btn][text]::after {
|
|
158
|
+
content: none;
|
|
159
|
+
}
|
|
160
|
+
:scope:is([stage="icon-only"], [stage="overflow"]) [data-toolbar-btn] {
|
|
161
|
+
--button-px: 0;
|
|
162
|
+
|
|
163
|
+
width: var(--button-height);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* ═══════ Actions-leading icon-only reduction ═══════ (gh#1748) — extends
|
|
167
|
+
the SAME icon-only collapse above to a plain <button-ui> a consumer
|
|
168
|
+
slots into [slot="actions-leading"] (gh#1649, e.g. the app-owned
|
|
169
|
+
Filter/Columns triggers on the ratified adiav2 row), so it reads as
|
|
170
|
+
part of the same toolbar affordance cluster rather than staying
|
|
171
|
+
full-width while its native siblings compact. A separate rule block
|
|
172
|
+
(rather than folding into [data-toolbar-btn]'s own selector list above)
|
|
173
|
+
keeps that block's literal text byte-identical for its own
|
|
174
|
+
source-assertion tests. Same breakpoint/pin pair, same
|
|
175
|
+
aria-label-survives guarantee (button-ui's own REQ-X-001 stamp,
|
|
176
|
+
unaffected here) — light-DOM real insertion point (no shadow
|
|
177
|
+
boundary), so a plain descendant tag selector reaches it directly, no
|
|
178
|
+
`::slotted()` needed. Literal `40rem` bound to
|
|
179
|
+
--table-toolbar-bp-icon-only's default, same as the native block. */
|
|
180
|
+
@container table-toolbar (max-width: 40rem) {
|
|
181
|
+
:scope:is(:not([stage]), [stage=""]) [data-actions-leading] button-ui[text]::after {
|
|
182
|
+
content: none;
|
|
183
|
+
}
|
|
184
|
+
:scope:is(:not([stage]), [stage=""]) [data-actions-leading] button-ui {
|
|
185
|
+
--button-px: 0;
|
|
186
|
+
|
|
187
|
+
width: var(--button-height);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
:scope:is([stage="icon-only"], [stage="overflow"]) [data-actions-leading] button-ui[text]::after {
|
|
192
|
+
content: none;
|
|
193
|
+
}
|
|
194
|
+
:scope:is([stage="icon-only"], [stage="overflow"]) [data-actions-leading] button-ui {
|
|
195
|
+
--button-px: 0;
|
|
196
|
+
|
|
197
|
+
width: var(--button-height);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/* ═══════ Range-summary conditional compact/hide ═══════ (ADR-0076
|
|
201
|
+
REQ-S-003, step 4) — at the SAME icon-only breakpoint as above:
|
|
202
|
+
- [data-page-size] present AND visible (no [hidden]) → its own
|
|
203
|
+
pagination context already carries the range info, so [data-summary]
|
|
204
|
+
hides entirely (its info is genuinely redundant here).
|
|
205
|
+
- [data-page-size] absent/hidden → [data-summary] is the toolbar's
|
|
206
|
+
ONLY visible range context, so it never fully disappears; instead
|
|
207
|
+
it swaps its full text for the short form (see [data-summary-compact]
|
|
208
|
+
below, "1–25/320" vs "Showing 1–25 of 320").
|
|
209
|
+
Which branch applies is a pure :has()/:not() container-width read — no
|
|
210
|
+
JS drives this (REQ-M-002); #updateSummary() populates BOTH
|
|
211
|
+
[data-summary-text] and [data-summary-compact] together whenever a
|
|
212
|
+
valid range exists, and CSS alone decides which one paints. */
|
|
213
|
+
@container table-toolbar (max-width: 40rem) {
|
|
214
|
+
:scope:is(:not([stage]), [stage=""]):has([data-page-size]:not([hidden])) [data-summary] {
|
|
215
|
+
display: none;
|
|
216
|
+
}
|
|
217
|
+
:scope:is(:not([stage]), [stage=""]):not(:has([data-page-size]:not([hidden]))) [data-summary-text] {
|
|
218
|
+
display: none;
|
|
219
|
+
}
|
|
220
|
+
/* :not([hidden]) — reviewer finding on PR #1674: without it, this
|
|
221
|
+
author-origin `display: inline` OUTRANKS the UA-origin
|
|
222
|
+
`[hidden] { display: none }` rule regardless of specificity (origin
|
|
223
|
+
comes before specificity in the cascade), so a JS-hidden
|
|
224
|
+
[data-summary-compact] (#updateSummary()'s empty-slot/loading
|
|
225
|
+
branches, which set compact.hidden = true) would still paint —
|
|
226
|
+
stale compact text alongside the empty-state content after a
|
|
227
|
+
positive range transitions to range-total="0" in icon-only mode.
|
|
228
|
+
Same class of gotcha this file already reinforces explicitly for
|
|
229
|
+
every other JS-toggled node ([data-toolbar-btn][hidden],
|
|
230
|
+
[data-search][hidden], [data-toolbar-overflow][hidden], etc). */
|
|
231
|
+
:scope:is(:not([stage]), [stage=""]):not(:has([data-page-size]:not([hidden]))) [data-summary-compact]:not([hidden]) {
|
|
232
|
+
display: inline;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
:scope:is([stage="icon-only"], [stage="overflow"]):has([data-page-size]:not([hidden])) [data-summary] {
|
|
237
|
+
display: none;
|
|
238
|
+
}
|
|
239
|
+
:scope:is([stage="icon-only"], [stage="overflow"]):not(:has([data-page-size]:not([hidden]))) [data-summary-text] {
|
|
240
|
+
display: none;
|
|
241
|
+
}
|
|
242
|
+
:scope:is([stage="icon-only"], [stage="overflow"]):not(:has([data-page-size]:not([hidden]))) [data-summary-compact]:not([hidden]) {
|
|
243
|
+
display: inline;
|
|
41
244
|
}
|
|
42
245
|
|
|
43
246
|
[data-toolbar] {
|
|
@@ -116,6 +319,26 @@
|
|
|
116
319
|
line-height: var(--a-font-leading-snug);
|
|
117
320
|
}
|
|
118
321
|
|
|
322
|
+
/* Short-form compact text ("1–25/320", ADR-0076 REQ-S-003) — hidden by
|
|
323
|
+
default (`display: none`, not just [hidden]) since it only ever paints
|
|
324
|
+
inside the icon-only-without-page-size branch above; that branch is the
|
|
325
|
+
ONLY place this flips to `display: inline`. Same typography as
|
|
326
|
+
[data-summary-text] — it's the same information, just terser. */
|
|
327
|
+
[data-summary-compact] {
|
|
328
|
+
display: none;
|
|
329
|
+
font-size: var(--table-toolbar-summary-size);
|
|
330
|
+
color: var(--table-toolbar-summary-fg);
|
|
331
|
+
line-height: var(--a-font-leading-snug);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/* ═══════ Empty-state slot ═══════ (ADR-0076 REQ-E — renders in
|
|
335
|
+
[data-summary]'s own position, alongside [data-summary-text]; only one
|
|
336
|
+
of the two is ever visible at a time, per #updateSummary(). Plain
|
|
337
|
+
author-supplied markup (REQ-E-003) — no forced typography here, unlike
|
|
338
|
+
[data-summary-text] above, which styles OUR OWN generated text. */
|
|
339
|
+
|
|
340
|
+
[data-summary-empty][hidden] { display: none; }
|
|
341
|
+
|
|
119
342
|
/* ═══════ Controls cluster ═══════ */
|
|
120
343
|
|
|
121
344
|
[data-controls] {
|
|
@@ -125,8 +348,63 @@
|
|
|
125
348
|
flex: 0 0 auto;
|
|
126
349
|
}
|
|
127
350
|
|
|
351
|
+
/* ADR-0076 REQ-C-003 — with [chrome-only] set, all three buttons carry
|
|
352
|
+
[hidden] (see #updateControlVisibility()); this collapses the cluster
|
|
353
|
+
to zero footprint via the same :empty{display:none} shape [data-scope]/
|
|
354
|
+
[data-actions]/[data-actions-leading] already use above, defensively
|
|
355
|
+
covering the case where no button children are stamped at all. */
|
|
356
|
+
[data-controls]:empty { display: none; }
|
|
357
|
+
|
|
128
358
|
[data-toolbar-btn][hidden] { display: none; }
|
|
129
359
|
|
|
360
|
+
/* ═══════ Overflow stage ═══════ (ADR-0076 REQ-S-004/REQ-X-003/004,
|
|
361
|
+
PLAN step 5) — collapses Filter/Sort/Columns into one "More" trigger
|
|
362
|
+
at the tightest breakpoint. The three granular buttons STAY in the
|
|
363
|
+
DOM (never created/destroyed across a stage transition — the simplest
|
|
364
|
+
way to keep REQ-X-004's tab-order guarantee correct); CSS alone
|
|
365
|
+
decides which cluster paints (REQ-M-002). [data-toolbar-overflow] is
|
|
366
|
+
the <menu-ui> wrapper stamped by #mkOverflowTrigger() — hiding/showing
|
|
367
|
+
it hides/shows its [slot="trigger"] button together with its (closed)
|
|
368
|
+
menu-item-ui children in one rule, matching how every other stage
|
|
369
|
+
toggle in this file targets one wrapper element rather than each
|
|
370
|
+
child individually. Literal `26rem` bound to
|
|
371
|
+
--table-toolbar-bp-overflow's own default (same duplication +
|
|
372
|
+
source-assertion discipline as the search-tight/icon-only boundaries
|
|
373
|
+
above). */
|
|
374
|
+
[data-toolbar-overflow] { display: none; }
|
|
375
|
+
|
|
376
|
+
@container table-toolbar (max-width: 26rem) {
|
|
377
|
+
:scope:is(:not([stage]), [stage=""]) [data-toolbar-btn] {
|
|
378
|
+
display: none;
|
|
379
|
+
}
|
|
380
|
+
:scope:is(:not([stage]), [stage=""]) [data-toolbar-overflow] {
|
|
381
|
+
display: inline-flex;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
:scope[stage="overflow"] [data-toolbar-btn] {
|
|
386
|
+
display: none;
|
|
387
|
+
}
|
|
388
|
+
:scope[stage="overflow"] [data-toolbar-overflow] {
|
|
389
|
+
display: inline-flex;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* [hidden] (per-kind chrome-only/no-* suppression, #updateControlVisibility())
|
|
393
|
+
must win over the stage-driven `display: inline-flex` rules above —
|
|
394
|
+
both for the reason `[data-toolbar-btn][hidden]`/`[data-search][hidden]`
|
|
395
|
+
etc reinforce it above (the browser's own UA-origin `[hidden]{display:
|
|
396
|
+
none}` rule is LOWER origin priority than any author rule, so an
|
|
397
|
+
unreinforced [hidden] would lose to author CSS) AND because this
|
|
398
|
+
selector must match or exceed the (0,3,0) specificity of the
|
|
399
|
+
`:scope … [data-toolbar-overflow]` show-rules above to win the tie —
|
|
400
|
+
`:scope [data-toolbar-overflow][hidden]` (0,3,0), placed after both in
|
|
401
|
+
source order, satisfies that. This covers the whole-trigger-suppressed
|
|
402
|
+
case (chrome-only, or all three no-* set) — the per-menu-item-ui
|
|
403
|
+
hidden state inside the (closed) menu needs no CSS help since
|
|
404
|
+
[hidden]'s UA default applies cleanly to a plain child with no
|
|
405
|
+
conflicting author rule. */
|
|
406
|
+
:scope [data-toolbar-overflow][hidden] { display: none; }
|
|
407
|
+
|
|
130
408
|
/* ═══════ Search ═══════ */
|
|
131
409
|
|
|
132
410
|
[data-search] {
|
|
@@ -140,6 +418,27 @@
|
|
|
140
418
|
|
|
141
419
|
[data-search][hidden] { display: none; }
|
|
142
420
|
|
|
421
|
+
/* ═══════ Actions-leading slot ═══════ (gh#1649 — app-owned triggers, e.g.
|
|
422
|
+
custom Filter/Columns buttons, that land BEFORE the page-size select)
|
|
423
|
+
Carries the SAME margin-inline-start:auto as [data-search]/[data-page-size]
|
|
424
|
+
so the trailing group still pushes to the far edge even when EVERY
|
|
425
|
+
native affordance ahead of it is dropped ([no-search] + [no-filter]/
|
|
426
|
+
[no-sort]/[no-columns], the adiav2 shape) and this slot becomes the
|
|
427
|
+
first visible member of the trailing cluster. Multiple auto-margin
|
|
428
|
+
siblings in one flex row is safe — only the first one with unclaimed
|
|
429
|
+
free space to its left actually receives it (same note as [data-page-size]
|
|
430
|
+
below). */
|
|
431
|
+
|
|
432
|
+
[data-actions-leading] {
|
|
433
|
+
display: inline-flex;
|
|
434
|
+
align-items: center;
|
|
435
|
+
gap: var(--table-toolbar-cluster-gap);
|
|
436
|
+
flex: 0 0 auto;
|
|
437
|
+
margin-inline-start: auto;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
[data-actions-leading]:empty { display: none; }
|
|
441
|
+
|
|
143
442
|
/* ═══════ Page-size select ═══════ (gh#1615)
|
|
144
443
|
Carries the SAME margin-inline-start:auto as [data-search] so the
|
|
145
444
|
trailing group (controls/search/page-size/actions) still pushes to the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `<table-toolbar-ui>` — Header / companion bar for a sibling table-ui. Renders an optional leading [slot="scope"] region, title + count badge, an optional "Showing X–Y of N" range summary, filter / sort / columns popovers, a search input, an optional page-size select, and a trailing [slot="actions"] region — all wired to the target table via an [for] id-ref. Modeled on chart-legend-ui's [for] binding pattern. Drop next to (or above) any table-ui to add the standard data-grid toolbar without re-implementing search, filter, sort, column visibility, or pagination summary/page-size. Filter rows auto-pick a primitive per column: ≤ 50 distinct values → multi-select (searchable when ≥ 12 options), id-like keys → free-text contains. The column descriptor's `filter` field overrides the auto-detect: `'select'` forces multi-select even on high-cardinality columns; `'text'` forces a contains input even on small enums.
|
|
2
|
+
* `<table-toolbar-ui>` — Header / companion bar for a sibling table-ui. Renders an optional leading [slot="scope"] region, title + count badge, an optional "Showing X–Y of N" range summary, filter / sort / columns popovers, a search input, an optional [slot="actions-leading"] region, an optional page-size select, and a trailing [slot="actions"] region — all wired to the target table via an [for] id-ref. Modeled on chart-legend-ui's [for] binding pattern. Drop next to (or above) any table-ui to add the standard data-grid toolbar without re-implementing search, filter, sort, column visibility, or pagination summary/page-size. Filter rows auto-pick a primitive per column: ≤ 50 distinct values → multi-select (searchable when ≥ 12 options), id-like keys → free-text contains. The column descriptor's `filter` field overrides the auto-detect: `'select'` forces multi-select even on high-cardinality columns; `'text'` forces a contains input even on small enums.
|
|
3
3
|
*
|
|
4
4
|
* @see https://ui-kit.exe.xyz/site/components/table-toolbar
|
|
5
5
|
*
|
|
@@ -17,8 +17,15 @@ export type TableToolbarFilterChangeEvent = CustomEvent<unknown>;
|
|
|
17
17
|
export type TableToolbarPageSizeChangeEvent = CustomEvent<unknown>;
|
|
18
18
|
export type TableToolbarSearchEvent = CustomEvent<unknown>;
|
|
19
19
|
export type TableToolbarSortChangeEvent = CustomEvent<unknown>;
|
|
20
|
+
export type TableToolbarToolbarColumnsSetEvent = CustomEvent<unknown>;
|
|
21
|
+
export type TableToolbarToolbarFilterClearEvent = CustomEvent<unknown>;
|
|
22
|
+
export type TableToolbarToolbarFilterSetEvent = CustomEvent<unknown>;
|
|
23
|
+
export type TableToolbarToolbarPaginateEvent = CustomEvent<unknown>;
|
|
24
|
+
export type TableToolbarToolbarSearchEvent = CustomEvent<unknown>;
|
|
20
25
|
|
|
21
26
|
export class UITableToolbar extends UIElement {
|
|
27
|
+
/** Suppress all four native controls/search at once (filter, sort, columns, search) as additive sugar over noFilter/noSort/noColumns/ noSearch (ADR-0076, ADIA2-9123). Precedence is pure, absolute OR — while set, all four stay off regardless of any individual no-* attribute's own value, with no partial re-enable path; to re-enable one control, remove chrome-only entirely and set the other three no-* attributes explicitly instead. The four granular attributes are not deprecated or removed — they remain the independently-addressable shipped API; chrome-only never replaces them, it's a convenience preset on top. */
|
|
28
|
+
chromeOnly: boolean;
|
|
22
29
|
/** Optional count badge value shown next to the title. When unset, falls back to the row count of the bound table. */
|
|
23
30
|
count: string;
|
|
24
31
|
/** id-ref of the table-ui to control. Falls back to the first sibling table-ui within the same parent when omitted. */
|
|
@@ -43,6 +50,8 @@ export class UITableToolbar extends UIElement {
|
|
|
43
50
|
rangeStart: number;
|
|
44
51
|
/** Total row count across all pages, for the range summary (e.g. `320` in "Showing 1–25 of 320"). Distinct from pagination-ui's `total` (total PAGES) — this is total ROWS; deliberately not spelled `total` to avoid that cross-sibling name collision (ADR-0063 B5). See rangeStart. */
|
|
45
52
|
rangeTotal: number;
|
|
53
|
+
/** Explicit compaction-stage override (ADR-0076). Unset (the default, empty string) means auto-snap: the toolbar's own inline-size container query picks the nearest stage from its live width against the three --table-toolbar-bp-* breakpoints, snapping discretely, never interpolating. Setting stage explicitly pins that stage's rendering regardless of the container's actual width — overriding the container query, mirroring chart-ui's ratio override shape. Primary use: visual-eval fixtures that need a deterministic stage without resizing a real container, and a consumer embedding the toolbar inside a known-narrow panel who wants to skip auto-detection entirely. All four stages' CSS is now live (ADR-0076): search-tight steps the search field down (step 2); icon-only drops control labels and compacts/hides the range summary (steps 3+4); overflow collapses Filter/Sort/Columns into one "More" trigger routed through the same menu-ui/menu-item-ui pattern used elsewhere in the corpus (step 5). The resolved stage — the pin if set, otherwise the live width classification — also reflects onto the host as `data-stage-resolved` (step 7, informational only, mirrors chart-ui's `data-ratio-resolved` convention — never drives table-toolbar's own rendering, which stays 100% CSS-driven). */
|
|
54
|
+
stage: '' | 'full' | 'search-tight' | 'icon-only' | 'overflow';
|
|
46
55
|
/** Title text shown on the left. */
|
|
47
56
|
text: string;
|
|
48
57
|
/** Toolbar visual variant. `default` renders bare on parent surface; `card` adds the same chrome as a card-ui header. */
|
|
@@ -53,6 +62,11 @@ export class UITableToolbar extends UIElement {
|
|
|
53
62
|
addEventListener(type: 'page-size-change', listener: (ev: TableToolbarPageSizeChangeEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
54
63
|
addEventListener(type: 'search', listener: (ev: TableToolbarSearchEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
55
64
|
addEventListener(type: 'sort-change', listener: (ev: TableToolbarSortChangeEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
65
|
+
addEventListener(type: 'toolbar-columns-set', listener: (ev: TableToolbarToolbarColumnsSetEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
66
|
+
addEventListener(type: 'toolbar-filter-clear', listener: (ev: TableToolbarToolbarFilterClearEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
67
|
+
addEventListener(type: 'toolbar-filter-set', listener: (ev: TableToolbarToolbarFilterSetEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
68
|
+
addEventListener(type: 'toolbar-paginate', listener: (ev: TableToolbarToolbarPaginateEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
69
|
+
addEventListener(type: 'toolbar-search', listener: (ev: TableToolbarToolbarSearchEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
56
70
|
addEventListener<K extends keyof HTMLElementEventMap>(
|
|
57
71
|
type: K,
|
|
58
72
|
listener: (this: UITableToolbar, ev: HTMLElementEventMap[K]) => unknown,
|
|
@@ -9,16 +9,17 @@ description: >-
|
|
|
9
9
|
Header / companion bar for a sibling table-ui. Renders an optional leading
|
|
10
10
|
[slot="scope"] region, title + count badge, an optional "Showing X–Y of N"
|
|
11
11
|
range summary, filter / sort / columns popovers, a search input, an
|
|
12
|
-
optional
|
|
13
|
-
wired to the target table via
|
|
14
|
-
[for]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
input even on
|
|
12
|
+
optional [slot="actions-leading"] region, an optional page-size select,
|
|
13
|
+
and a trailing [slot="actions"] region — all wired to the target table via
|
|
14
|
+
an [for] id-ref. Modeled on chart-legend-ui's [for] binding pattern. Drop
|
|
15
|
+
next to (or above) any table-ui to add the standard data-grid toolbar
|
|
16
|
+
without re-implementing search, filter, sort, column visibility, or
|
|
17
|
+
pagination summary/page-size. Filter rows auto-pick a primitive per
|
|
18
|
+
column: ≤ 50 distinct values → multi-select (searchable when ≥ 12
|
|
19
|
+
options), id-like keys → free-text contains. The column descriptor's
|
|
20
|
+
`filter` field overrides the auto-detect: `'select'` forces multi-select
|
|
21
|
+
even on high-cardinality columns; `'text'` forces a contains input even on
|
|
22
|
+
small enums.
|
|
22
23
|
# Per ADR-0027 — primitives that programmatically create other primitives
|
|
23
24
|
# do NOT auto-import them. Consumer (or demo shell) must explicitly import.
|
|
24
25
|
composes:
|
|
@@ -29,6 +30,7 @@ composes:
|
|
|
29
30
|
- field-ui
|
|
30
31
|
- select-ui
|
|
31
32
|
- input-ui
|
|
33
|
+
- menu-ui
|
|
32
34
|
- menu-item-ui
|
|
33
35
|
- icon-ui
|
|
34
36
|
- check-ui
|
|
@@ -127,6 +129,53 @@ props:
|
|
|
127
129
|
default: false
|
|
128
130
|
reflect: true
|
|
129
131
|
attribute: no-search
|
|
132
|
+
stage:
|
|
133
|
+
description: >-
|
|
134
|
+
Explicit compaction-stage override (ADR-0076). Unset (the default,
|
|
135
|
+
empty string) means auto-snap: the toolbar's own inline-size
|
|
136
|
+
container query picks the nearest stage from its live width against
|
|
137
|
+
the three --table-toolbar-bp-* breakpoints, snapping discretely,
|
|
138
|
+
never interpolating. Setting stage explicitly pins that stage's
|
|
139
|
+
rendering regardless of the container's actual width — overriding
|
|
140
|
+
the container query, mirroring chart-ui's ratio override shape.
|
|
141
|
+
Primary use: visual-eval fixtures that need a deterministic stage
|
|
142
|
+
without resizing a real container, and a consumer embedding the
|
|
143
|
+
toolbar inside a known-narrow panel who wants to skip auto-detection
|
|
144
|
+
entirely. All four stages' CSS is now live (ADR-0076): search-tight
|
|
145
|
+
steps the search field down (step 2); icon-only drops control labels
|
|
146
|
+
and compacts/hides the range summary (steps 3+4); overflow collapses
|
|
147
|
+
Filter/Sort/Columns into one "More" trigger routed through the same
|
|
148
|
+
menu-ui/menu-item-ui pattern used elsewhere in the corpus (step 5).
|
|
149
|
+
The resolved stage — the pin if set, otherwise the live width
|
|
150
|
+
classification — also reflects onto the host as
|
|
151
|
+
`data-stage-resolved` (step 7, informational only, mirrors chart-ui's
|
|
152
|
+
`data-ratio-resolved` convention — never drives table-toolbar's own
|
|
153
|
+
rendering, which stays 100% CSS-driven).
|
|
154
|
+
type: string
|
|
155
|
+
default: ""
|
|
156
|
+
enum:
|
|
157
|
+
- ""
|
|
158
|
+
- full
|
|
159
|
+
- search-tight
|
|
160
|
+
- icon-only
|
|
161
|
+
- overflow
|
|
162
|
+
reflect: true
|
|
163
|
+
chromeOnly:
|
|
164
|
+
description: >-
|
|
165
|
+
Suppress all four native controls/search at once (filter, sort,
|
|
166
|
+
columns, search) as additive sugar over noFilter/noSort/noColumns/
|
|
167
|
+
noSearch (ADR-0076, ADIA2-9123). Precedence is pure, absolute OR —
|
|
168
|
+
while set, all four stay off regardless of any individual no-*
|
|
169
|
+
attribute's own value, with no partial re-enable path; to
|
|
170
|
+
re-enable one control, remove chrome-only entirely and set the
|
|
171
|
+
other three no-* attributes explicitly instead. The four granular
|
|
172
|
+
attributes are not deprecated or removed — they remain the
|
|
173
|
+
independently-addressable shipped API; chrome-only never replaces
|
|
174
|
+
them, it's a convenience preset on top.
|
|
175
|
+
type: boolean
|
|
176
|
+
default: false
|
|
177
|
+
reflect: true
|
|
178
|
+
attribute: chrome-only
|
|
130
179
|
placeholder:
|
|
131
180
|
description: Placeholder text for the search input.
|
|
132
181
|
type: string
|
|
@@ -150,11 +199,63 @@ events:
|
|
|
150
199
|
description: "Column visibility changed. Detail: { hiddenColumns }."
|
|
151
200
|
page-size-change:
|
|
152
201
|
description: "Page-size select changed. Detail: { pageSize }."
|
|
202
|
+
toolbar-search:
|
|
203
|
+
description: >-
|
|
204
|
+
gh#1764/#1780, ADR-0079 (events-only interaction contract) — dispatched
|
|
205
|
+
directly at the resolved [for] target (not bubbled from this element)
|
|
206
|
+
in place of the pre-#1780 direct `.search =` write. table-ui listens
|
|
207
|
+
for this on itself. Detail: { value }.
|
|
208
|
+
toolbar-filter-set:
|
|
209
|
+
description: >-
|
|
210
|
+
gh#1764/#1780, ADR-0079 — dispatched directly at the resolved [for]
|
|
211
|
+
target in place of the pre-#1780 direct `target.setFilter()` call.
|
|
212
|
+
table-ui listens for this on itself. Detail: { key, value, op }; a
|
|
213
|
+
null `value` clears that one column's filter.
|
|
214
|
+
toolbar-filter-clear:
|
|
215
|
+
description: >-
|
|
216
|
+
gh#1764/#1780, ADR-0079 — dispatched directly at the resolved [for]
|
|
217
|
+
target in place of the pre-#1780 direct `target.clearFilters()` call.
|
|
218
|
+
table-ui listens for this on itself. No detail.
|
|
219
|
+
toolbar-columns-set:
|
|
220
|
+
description: >-
|
|
221
|
+
gh#1764/#1780, ADR-0079 — dispatched directly at the resolved [for]
|
|
222
|
+
target in place of the pre-#1780 direct `target.columns =` write.
|
|
223
|
+
table-ui listens for this on itself. Detail: { columns }.
|
|
224
|
+
toolbar-paginate:
|
|
225
|
+
description: >-
|
|
226
|
+
gh#1764/#1780, ADR-0079 — dispatched directly at the resolved [for]
|
|
227
|
+
target in place of the pre-#1780 direct `target.paginate =` write.
|
|
228
|
+
table-ui listens for this on itself. Detail: { pageSize }.
|
|
153
229
|
slots:
|
|
154
230
|
scope:
|
|
155
231
|
description: Leading region rendered BEFORE the [text]/[count] title cluster — e.g. a scope/view-switcher menu (an org's teams, a saved view). Positioning is CSS by DOM order, mirroring how [slot="actions"] is a real, author-fillable insertion point rather than template-stamped content.
|
|
232
|
+
empty:
|
|
233
|
+
description: >-
|
|
234
|
+
Renders in place of the range-summary text — the same [data-summary]
|
|
235
|
+
region — when [range-total] is EXPLICITLY present and equal to "0"
|
|
236
|
+
(checked via hasAttribute, never the computed value alone, so an
|
|
237
|
+
unset range-total during loading never flashes this content;
|
|
238
|
+
ADR-0076, REQ-E-001). Mutually exclusive with a positive
|
|
239
|
+
[range-total]: the normal "Showing X-Y of N" text always wins
|
|
240
|
+
whenever range-total is a positive number. Empty (the default)
|
|
241
|
+
preserves today's exact behavior — [data-summary] hides on a
|
|
242
|
+
confirmed range-total="0" exactly as before this slot existed.
|
|
243
|
+
Plain author-supplied markup (text, an empty-state-ui composite, an
|
|
244
|
+
icon+text pair) — table-toolbar does not template or constrain its
|
|
245
|
+
shape. Naming matches chart-ui's own existing `empty` slot
|
|
246
|
+
convention.
|
|
247
|
+
actions-leading:
|
|
248
|
+
description: >-
|
|
249
|
+
Region rendered AFTER the search input and BEFORE the native
|
|
250
|
+
page-size select (gh#1649) — for app-owned trigger buttons (e.g.
|
|
251
|
+
custom Filter / Columns triggers that open the consumer's own
|
|
252
|
+
drawer instead of the native filter/columns popovers) that must
|
|
253
|
+
land ahead of the page-size select rather than after it, unlike
|
|
254
|
+
[slot="actions"]. Same real-insertion-point pattern as [slot="scope"]
|
|
255
|
+
/ [slot="actions"] — positioning is CSS by DOM order, not a template
|
|
256
|
+
stamp. Empty (the default) has zero footprint on existing consumers.
|
|
156
257
|
actions:
|
|
157
|
-
description: Trailing action area — primary buttons (e.g. "New row") rendered after the search input.
|
|
258
|
+
description: Trailing action area — primary buttons (e.g. "New row") rendered after the search input, [slot="actions-leading"], and the page-size select.
|
|
158
259
|
states:
|
|
159
260
|
- name: idle
|
|
160
261
|
description: Default, ready for interaction.
|
|
@@ -186,6 +287,7 @@ requiredIcons:
|
|
|
186
287
|
- arrow-up
|
|
187
288
|
- arrow-down
|
|
188
289
|
- caret-up-down
|
|
290
|
+
- dots-three-vertical
|
|
189
291
|
a2ui:
|
|
190
292
|
rules:
|
|
191
293
|
- >-
|
|
@@ -223,6 +325,44 @@ a2ui:
|
|
|
223
325
|
+ [page-size-options] for a rows-per-page select; it applies
|
|
224
326
|
directly to the bound table's [paginate] prop the same way
|
|
225
327
|
filter/sort/columns changes apply directly to the target.
|
|
328
|
+
- >-
|
|
329
|
+
Use [slot="actions-leading"] (gh#1649) for app-owned trigger
|
|
330
|
+
buttons that must land BEFORE the page-size select — e.g. custom
|
|
331
|
+
Filter / Columns triggers that open the consumer's own drawer
|
|
332
|
+
instead of the native filter/columns popovers (drop [no-filter]
|
|
333
|
+
[no-columns] to hide the native ones when doing this). [slot="actions"]
|
|
334
|
+
stays the trailing region AFTER the page-size select, for a
|
|
335
|
+
primary CTA.
|
|
336
|
+
- >-
|
|
337
|
+
Use [chrome-only] (ADR-0076, ADIA2-9123) instead of stacking
|
|
338
|
+
[no-filter] [no-sort] [no-columns] [no-search] individually when an
|
|
339
|
+
app owns ALL FOUR affordances itself (its own drawer/menu). Pure OR,
|
|
340
|
+
absolute while set — clearing an individual no-* attribute does NOT
|
|
341
|
+
re-enable that one control; drop [chrome-only] entirely and set the
|
|
342
|
+
three you still want off explicitly instead. Combine with
|
|
343
|
+
[slot="actions-leading"] for the app's own Filter/Columns triggers.
|
|
344
|
+
- >-
|
|
345
|
+
Use <span slot="empty"> (or any markup) inside a table-toolbar-ui
|
|
346
|
+
that also sets [range-total="0"] to show a "no results" message in
|
|
347
|
+
the range-summary's own position, without a layout shift versus the
|
|
348
|
+
normal "Showing X-Y of N" text (ADR-0076, REQ-E). Only fires on an
|
|
349
|
+
EXPLICIT range-total="0" — omitting range-* entirely (loading) never
|
|
350
|
+
shows it.
|
|
351
|
+
- >-
|
|
352
|
+
A plain <button-ui> slotted into [slot="actions-leading"] (e.g. the
|
|
353
|
+
app-owned Filter/Columns triggers above) already collapses to
|
|
354
|
+
icon-only at the SAME breakpoint as the native Filter/Sort/Columns
|
|
355
|
+
buttons (gh#1748) — no consumer JS/CSS required. Read the host's
|
|
356
|
+
[data-stage-resolved] attribute (ADR-0076 REQ-M-005, ADIA2-9123
|
|
357
|
+
S4-ii) only for compaction BEYOND plain icon-only reduction — e.g.
|
|
358
|
+
hiding a slotted button entirely at the overflow stage, or reacting
|
|
359
|
+
to the stage in a consumer's own drawer/menu — without re-deriving
|
|
360
|
+
the same breakpoints yourself. Informational only — mirrors the
|
|
361
|
+
CSS-decided compaction stage (full | search-tight | icon-only |
|
|
362
|
+
overflow), never drives table-toolbar's own rendering. Reports the
|
|
363
|
+
pinned [stage] value when set, the live width classification
|
|
364
|
+
otherwise; updates on both a live resize and a [stage] attribute
|
|
365
|
+
change.
|
|
226
366
|
anti_patterns: []
|
|
227
367
|
examples:
|
|
228
368
|
- name: members-toolbar
|
|
@@ -237,13 +377,20 @@ examples:
|
|
|
237
377
|
]
|
|
238
378
|
- name: adiav2-list-page-toolbar-row
|
|
239
379
|
description: >-
|
|
240
|
-
The ratified adiav2 list-page toolbar row (ADIA2-9123): scope
|
|
241
|
-
range summary,
|
|
242
|
-
|
|
380
|
+
The ratified adiav2 list-page toolbar row (ADIA2-9123, gh#1649): scope
|
|
381
|
+
menu, range summary, app-owned Filter/Columns triggers (their own
|
|
382
|
+
filter drawer, not the native popovers — [no-filter]/[no-columns]/
|
|
383
|
+
[no-sort]/[no-search] drop the native affordances), page-size select,
|
|
384
|
+
and a primary CTA — [slot="actions-leading"] carries the Filter/Columns
|
|
385
|
+
triggers so they land BEFORE the page-size select, while [slot="actions"]
|
|
386
|
+
carries the CTA so it lands after.
|
|
243
387
|
a2ui: >-
|
|
244
388
|
[
|
|
245
389
|
{"id": "root", "component": "Column", "gap": "3", "children": ["bar", "card"]},
|
|
246
|
-
{"id": "bar", "component": "TableToolbar", "for": "accounts", "no-sort": true, "no-search": true, "range-start": 1, "range-end": 25, "range-total": 320, "page-size": 25, "page-size-options": [10, 25, 50, 100]},
|
|
390
|
+
{"id": "bar", "component": "TableToolbar", "for": "accounts", "no-filter": true, "no-sort": true, "no-columns": true, "no-search": true, "range-start": 1, "range-end": 25, "range-total": 320, "page-size": 25, "page-size-options": [10, 25, 50, 100], "children": ["btn-filter", "btn-columns", "btn-new"]},
|
|
391
|
+
{"id": "btn-filter", "component": "Button", "text": "Filter", "variant": "ghost", "slot": "actions-leading"},
|
|
392
|
+
{"id": "btn-columns", "component": "Button", "text": "Columns", "variant": "ghost", "slot": "actions-leading"},
|
|
393
|
+
{"id": "btn-new", "component": "Button", "text": "New account", "variant": "primary", "slot": "actions"},
|
|
247
394
|
{"id": "card", "component": "Card", "children": ["sec"]},
|
|
248
395
|
{"id": "sec", "component": "Section", "bleed": true, "children": ["tbl"]},
|
|
249
396
|
{"id": "tbl", "component": "Table", "id": "accounts", "sortable": true, "raw": true}
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import { UIElement } from '../../core/element.js';
|
|
28
|
+
import { syncAutoAriaLabel } from '../../core/a11y.js';
|
|
28
29
|
|
|
29
30
|
export class UITag extends UIElement {
|
|
30
31
|
// §154 (v0.5.3): Phosphor icons this primitive auto-stamps (without
|
|
@@ -75,6 +76,17 @@ export class UITag extends UIElement {
|
|
|
75
76
|
|
|
76
77
|
static template = () => null;
|
|
77
78
|
|
|
79
|
+
// gh#1644: tracks the aria-label VALUE this element itself last derived
|
|
80
|
+
// from `text` (undefined when none), so re-renders refresh/clear OUR
|
|
81
|
+
// name without ever clobbering a consumer's own aria-label. The
|
|
82
|
+
// compare-against-what-we-last-wrote guard lives in core/a11y.js's
|
|
83
|
+
// `syncAutoAriaLabel` (gh#1647 / gh#1651); this field is its state.
|
|
84
|
+
#lastAutoAriaLabel = undefined;
|
|
85
|
+
|
|
86
|
+
#syncAccessibleName() {
|
|
87
|
+
this.#lastAutoAriaLabel = syncAutoAriaLabel(this, this.#lastAutoAriaLabel, this.text || '');
|
|
88
|
+
}
|
|
89
|
+
|
|
78
90
|
#onClick = (e) => {
|
|
79
91
|
if (this.disabled) return;
|
|
80
92
|
if (e.target.closest('[slot="dismiss"]')) {
|
|
@@ -112,7 +124,7 @@ export class UITag extends UIElement {
|
|
|
112
124
|
}
|
|
113
125
|
|
|
114
126
|
render() {
|
|
115
|
-
|
|
127
|
+
this.#syncAccessibleName();
|
|
116
128
|
|
|
117
129
|
if (this.disabled) {
|
|
118
130
|
this.setAttribute('aria-disabled', 'true');
|