@adia-ai/web-components 0.8.21 → 0.8.23
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 +56 -0
- package/MIGRATION.md +9 -0
- package/components/agent-trace/agent-trace.js +4 -1
- package/components/alert/alert.a2ui.json +1 -1
- package/components/alert/alert.css +44 -5
- package/components/alert/alert.yaml +8 -4
- package/components/canvas/canvas.js +4 -1
- package/components/chat-thread/chat-input.js +4 -1
- package/components/code/code.css +29 -26
- package/components/combobox/combobox.a2ui.json +1 -1
- package/components/combobox/combobox.class.js +14 -4
- package/components/combobox/combobox.css +52 -4
- package/components/combobox/combobox.yaml +5 -1
- package/components/description-list/description-list.css +9 -0
- package/components/drawer/drawer.css +16 -0
- package/components/field/field.css +4 -1
- package/components/list/list.css +12 -1
- package/components/nav-group/nav-group.class.js +45 -2
- package/components/nav-group/nav-group.css +11 -2
- package/components/progress-row/progress-row.class.js +10 -2
- package/components/richtext/richtext.css +7 -0
- package/components/select/select.a2ui.json +5 -0
- package/components/select/select.class.js +39 -9
- package/components/select/select.yaml +13 -0
- package/components/stat/stat.js +4 -1
- package/components/stepper/stepper.css +25 -20
- package/components/table/table.a2ui.json +15 -1
- package/components/table/table.class.js +14 -1
- package/components/table/table.css +68 -3
- package/components/table/table.d.ts +5 -1
- package/components/table/table.yaml +34 -1
- package/components/tabs/tab.js +4 -1
- package/components/tag/tag.css +15 -9
- package/core/provider.js +5 -1
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/scale.min.css +1 -1
- package/dist/scale.sheet.js +1 -1
- package/dist/theme-provider.min.js +2 -2
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +93 -93
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/access-requests/access-requests.examples.html +12 -3
- package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +20 -5
- package/patterns/agent-cost/agent-cost.examples.html +12 -3
- package/patterns/agent-memory/agent-memory.examples.html +12 -3
- package/patterns/agent-prompt-library/agent-prompt-library.examples.html +12 -3
- package/patterns/agent-tool-call/agent-tool-call.examples.html +16 -4
- package/patterns/alert-dialog/alert-dialog.examples.html +12 -3
- package/patterns/app-nav/app-nav.examples.html +36 -9
- package/patterns/approvals/approvals.examples.html +14 -10
- package/patterns/audit-log/audit-log.examples.html +5 -2
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +210 -32
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +83 -4
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.html +68 -0
- package/patterns/changelog-feed/changelog-feed.examples.html +4 -1
- package/patterns/chart-in-card/chart-in-card.examples.html +28 -7
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +20 -5
- package/patterns/conversion-funnel/conversion-funnel.examples.html +24 -15
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +15 -6
- package/patterns/diff-review/diff-review.examples.html +12 -3
- package/patterns/export-flow/export-flow.examples.html +12 -3
- package/patterns/filter-bar/filter-bar.examples.html +13 -4
- package/patterns/form-drawer/form-drawer.examples.html +15 -6
- package/patterns/form-system/form-system.examples.html +4 -1
- package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +12 -3
- package/patterns/inline-dialog/inline-dialog.examples.html +12 -3
- package/patterns/kanban-board/kanban-board.examples.html +4 -1
- package/patterns/marketing-engagement/marketing-engagement.examples.html +24 -6
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +12 -3
- package/patterns/permissions-matrix/permissions-matrix.examples.html +9 -3
- package/patterns/permissions-role-picker/permissions-role-picker.examples.html +8 -2
- package/patterns/permissions-sharing/permissions-sharing.examples.html +12 -3
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +16 -4
- package/patterns/record-detail-drawer/record-detail-drawer.examples.html +10 -4
- package/patterns/retention-cohort/retention-cohort.examples.html +15 -6
- package/patterns/search-discovery/search-discovery.examples.html +16 -4
- package/patterns/system-banners/system-banners.examples.html +54 -48
- package/patterns/timezone-selector/timezone-selector.examples.html +8 -2
- package/patterns/timezone-selector/timezone-selector.examples.js +3 -1
- package/patterns/wizard-drawer/wizard-drawer.examples.html +25 -23
- package/patterns/wizard-drawer/wizard-drawer.examples.js +12 -1
- package/styles/foundation/radius.css +2 -2
- package/styles/scale.css +2 -2
- package/styles/type/scale.css +6 -6
|
@@ -2,60 +2,145 @@
|
|
|
2
2
|
<div>
|
|
3
3
|
<h1>Bulk Action Toolbar</h1>
|
|
4
4
|
<div data-actions>
|
|
5
|
-
<tag-ui size="sm">table-toolbar-ui</tag-ui> <tag-ui size="sm">toolbar-ui</tag-ui> <tag-ui size="sm">table-ui</tag-ui>
|
|
5
|
+
<tag-ui size="sm">table-toolbar-ui</tag-ui> <tag-ui size="sm">toolbar-ui</tag-ui> <tag-ui size="sm">table-ui</tag-ui> <tag-ui size="sm">card-ui</tag-ui>
|
|
6
6
|
</div>
|
|
7
7
|
</div>
|
|
8
|
-
<p>When a table has row selection, swap the standard <code><table-toolbar-ui></code> for a
|
|
8
|
+
<p>When a table has row selection, surface a contextual bulk-action bar. Two variants: swap the standard <code><table-toolbar-ui></code> for a bar at the same surface position, or float a card-like elevated bar at the bottom of the table's own scroll container. Selection count anchors the left, actions flow from the right, destructive action last.</p>
|
|
9
9
|
</header>
|
|
10
10
|
|
|
11
11
|
<section data-section data-property="when-to-use">
|
|
12
12
|
<h2 variant="section">When to use</h2>
|
|
13
13
|
<p data-note>
|
|
14
14
|
Any table where users act on multiple rows at once: archive, delete, export, move.
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
</p>
|
|
16
|
+
<p data-note>
|
|
17
|
+
Pick the <strong>toolbar swap</strong> for short or inline tables — everything fits in one
|
|
18
|
+
viewport, so the swapped bar at the top stays visible and "the chrome itself changes" is the
|
|
19
|
+
strongest possible affordance for selection mode.
|
|
20
|
+
</p>
|
|
21
|
+
<p data-note>
|
|
22
|
+
Pick the <strong>floating variant</strong> as the default once a table can run taller than
|
|
23
|
+
~one viewport (long lists, paginated consoles at 50+ rows). Selections made mid-scroll get no
|
|
24
|
+
feedback from a toolbar that has already scrolled out of view — the floating bar stays
|
|
25
|
+
anchored to the bottom of the table's own scroll container so it's visible at the moment of
|
|
26
|
+
use, without pinning to the browser viewport and ignoring shell chrome.
|
|
17
27
|
</p>
|
|
18
28
|
</section>
|
|
19
29
|
|
|
20
|
-
<section data-section data-property="toolbar-swap" data-chunk="bulk-action-toolbar-swap"
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
<section data-section data-property="toolbar-swap" data-chunk="bulk-action-toolbar-swap" data-chunk-kind="block"
|
|
31
|
+
data-chunk-domain="data"
|
|
32
|
+
data-chunk-description="Bulk-action toolbar over a selectable table — the default table toolbar swaps at the same height for an 'N selected' bar with Archive, Export, Move, a divider, and Delete when rows are checked."
|
|
33
|
+
data-chunk-keywords="bulk actions toolbar selection selected rows table checkbox archive export move delete swap batch multi-select bar">
|
|
34
|
+
<h2 variant="section">Toolbar swap (top-anchored)</h2>
|
|
35
|
+
<p data-note>Tick the checkboxes below — the default <code><table-toolbar-ui></code> swaps for the bulk-action bar at the same height. Untick to return. Best for short/inline tables (see When to use).</p>
|
|
23
36
|
<card-ui raw>
|
|
24
37
|
<section bleed>
|
|
25
38
|
<table-toolbar-ui id="pat-bulk-default" for="pat-bulk-table" text="Resources" count="6" no-filter no-sort no-columns></table-toolbar-ui>
|
|
26
39
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
<!-- align="space-between" pushes the trailing group right — NOT a
|
|
41
|
+
flex-grow spacer span (gh#494 audit finding: toolbar-ui's overflow
|
|
42
|
+
reflow sums each top-level child's RENDERED width to decide what
|
|
43
|
+
fits; a flex-grow spacer has already expanded to fill the free
|
|
44
|
+
space by the time it's measured, so the sum always reads "full"
|
|
45
|
+
and spuriously spills the trailing action(s) into the "more" menu
|
|
46
|
+
— Delete was silently unreachable here before this fix, even with
|
|
47
|
+
plenty of room). Grouping into two <toolbar-group-ui> atoms keeps
|
|
48
|
+
the reflow's width sum accurate; see the floating variant below
|
|
49
|
+
for the same fix applied at a smaller width. -->
|
|
50
|
+
<toolbar-ui id="pat-bulk-actions" data-bulk-bar role="toolbar" aria-label="Bulk actions" align="space-between" hidden>
|
|
51
|
+
<toolbar-group-ui>
|
|
52
|
+
<text-ui strong><span data-bulk-count>0</span> selected</text-ui>
|
|
53
|
+
</toolbar-group-ui>
|
|
54
|
+
<toolbar-group-ui>
|
|
55
|
+
<button-ui text="Archive" icon="archive" variant="ghost" size="sm" data-bulk-action="archive"></button-ui>
|
|
56
|
+
<button-ui text="Export" icon="download-simple" variant="ghost" size="sm" data-bulk-action="export"></button-ui>
|
|
57
|
+
<button-ui text="Move" icon="folder-simple" variant="ghost" size="sm" data-bulk-action="move"></button-ui>
|
|
58
|
+
<divider-ui vertical></divider-ui>
|
|
59
|
+
<button-ui text="Delete" icon="trash" variant="ghost" size="sm" data-bulk-action="delete"></button-ui>
|
|
60
|
+
</toolbar-group-ui>
|
|
35
61
|
</toolbar-ui>
|
|
36
62
|
|
|
37
|
-
<table-ui id="pat-bulk-table" selectable sortable striped></table-ui>
|
|
63
|
+
<table-ui frameless id="pat-bulk-table" selectable sortable striped></table-ui>
|
|
64
|
+
</section>
|
|
65
|
+
</card-ui>
|
|
66
|
+
</section>
|
|
67
|
+
|
|
68
|
+
<section data-section data-property="floating-variant" data-chunk="bulk-action-toolbar-floating" data-chunk-kind="block"
|
|
69
|
+
data-chunk-domain="data"
|
|
70
|
+
data-chunk-description="Floating bottom-anchored bulk-action bar — a card-like elevated toolbar (elevation 3) that appears sticky to the bottom of a table's own scroll container (not the browser viewport) when rows are selected, with selection count, an optional per-flow controls slot, actions with destructive last, and an explicit Clear button. Composes table-ui's select event with card-ui + toolbar-ui; no focus steal on appearance, Escape clears selection when the bar owns focus, count is aria-live=polite."
|
|
71
|
+
data-chunk-keywords="floating bulk action bar bottom anchored sticky selection toolbar card elevated table scroll container escape clear aria-live gmail linear notion">
|
|
72
|
+
<h2 variant="section">Floating (bottom-anchored)</h2>
|
|
73
|
+
<p data-note>
|
|
74
|
+
Tick the checkboxes below — a card-like elevated bar rises from the bottom of the table's own
|
|
75
|
+
scroll container (scroll the table, the bar tracks it, not the page). Press
|
|
76
|
+
<code>Escape</code> while the bar has focus, or use the explicit Clear button, to release
|
|
77
|
+
the selection.
|
|
78
|
+
</p>
|
|
79
|
+
<card-ui raw>
|
|
80
|
+
<section bleed>
|
|
81
|
+
<table-toolbar-ui id="pat-bulk-float-default" for="pat-bulk-float-table" text="Resources" count="12" no-filter no-sort no-columns></table-toolbar-ui>
|
|
82
|
+
|
|
83
|
+
<div data-table-scroll>
|
|
84
|
+
<table-ui frameless id="pat-bulk-float-table" selectable sortable striped></table-ui>
|
|
85
|
+
|
|
86
|
+
<card-ui id="pat-bulk-float-bar" elevation="3" data-bulk-bar-floating>
|
|
87
|
+
<section>
|
|
88
|
+
<!-- align="space-between" pushes the trailing group right —
|
|
89
|
+
NOT a flex-grow spacer span or an auto margin on a content
|
|
90
|
+
item. toolbar-ui's overflow reflow sums each top-level
|
|
91
|
+
child's RENDERED width to decide what fits; any child that
|
|
92
|
+
absorbs free space (flex-grow, or an auto margin resolved
|
|
93
|
+
to real pixels post-layout) has already expanded to fill
|
|
94
|
+
that space by the time it's measured, so the sum always
|
|
95
|
+
reads "full" and spuriously spills content. `justify-content`
|
|
96
|
+
only repositions flex items — it doesn't touch their
|
|
97
|
+
individual widths (toolbar-ui's own CSS pins every direct
|
|
98
|
+
child at `flex: 0 0 auto`) — so grouping into two
|
|
99
|
+
`<toolbar-group-ui>` atoms and letting `align="space-between"`
|
|
100
|
+
do the pushing keeps the reflow's width sum accurate. -->
|
|
101
|
+
<toolbar-ui role="toolbar" aria-label="Bulk actions" align="space-between">
|
|
102
|
+
<toolbar-group-ui>
|
|
103
|
+
<text-ui strong aria-live="polite"><span data-bulk-float-count>0</span> selected</text-ui>
|
|
104
|
+
<span data-bulk-controls></span>
|
|
105
|
+
</toolbar-group-ui>
|
|
106
|
+
<toolbar-group-ui>
|
|
107
|
+
<button-ui icon="archive" icon-only aria-label="Archive" variant="ghost" size="sm" data-bulk-action="archive"></button-ui>
|
|
108
|
+
<button-ui icon="download-simple" icon-only aria-label="Export" variant="ghost" size="sm" data-bulk-action="export"></button-ui>
|
|
109
|
+
<button-ui icon="folder-simple" icon-only aria-label="Move" variant="ghost" size="sm" data-bulk-action="move"></button-ui>
|
|
110
|
+
<divider-ui vertical></divider-ui>
|
|
111
|
+
<button-ui icon="trash" icon-only aria-label="Delete" variant="ghost" size="sm" data-bulk-action="delete"></button-ui>
|
|
112
|
+
<divider-ui vertical></divider-ui>
|
|
113
|
+
<button-ui text="Clear" variant="ghost" size="sm" data-bulk-clear></button-ui>
|
|
114
|
+
</toolbar-group-ui>
|
|
115
|
+
</toolbar-ui>
|
|
116
|
+
</section>
|
|
117
|
+
</card-ui>
|
|
118
|
+
</div>
|
|
38
119
|
</section>
|
|
39
120
|
</card-ui>
|
|
40
121
|
</section>
|
|
41
122
|
|
|
42
123
|
<section data-section data-property="anatomy">
|
|
43
|
-
<h2 variant="section">Anatomy</h2>
|
|
124
|
+
<h2 variant="section">Anatomy — toolbar swap</h2>
|
|
44
125
|
<p data-note>Both toolbars sit inside the same <code><section bleed></code> so they share one surface. Toggle visibility on the <code>select</code> event from the table.</p>
|
|
45
126
|
<code-ui language="html"><card-ui>
|
|
46
127
|
<section bleed>
|
|
47
128
|
<!-- Default state — modern foundation -->
|
|
48
129
|
<table-toolbar-ui for="resources" text="Resources" count="6"></table-toolbar-ui>
|
|
49
130
|
|
|
50
|
-
<!-- Bulk action bar — swaps in when rows are selected
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
<
|
|
57
|
-
|
|
58
|
-
|
|
131
|
+
<!-- Bulk action bar — swaps in when rows are selected. align="space-between"
|
|
132
|
+
(not a flex-grow spacer — see Rules) pushes the action group right. -->
|
|
133
|
+
<toolbar-ui data-bulk-bar hidden role="toolbar" aria-label="Bulk actions" align="space-between">
|
|
134
|
+
<toolbar-group-ui>
|
|
135
|
+
<text-ui strong><span data-bulk-count>0</span> selected</text-ui>
|
|
136
|
+
</toolbar-group-ui>
|
|
137
|
+
<toolbar-group-ui>
|
|
138
|
+
<button-ui text="Archive" icon="archive" variant="ghost" size="sm"></button-ui>
|
|
139
|
+
<button-ui text="Export" icon="download-simple" variant="ghost" size="sm"></button-ui>
|
|
140
|
+
<button-ui text="Move" icon="folder-simple" variant="ghost" size="sm"></button-ui>
|
|
141
|
+
<divider-ui vertical></divider-ui>
|
|
142
|
+
<button-ui text="Delete" icon="trash" variant="ghost" size="sm"></button-ui>
|
|
143
|
+
</toolbar-group-ui>
|
|
59
144
|
</toolbar-ui>
|
|
60
145
|
|
|
61
146
|
<table-ui id="resources" selectable sortable></table-ui>
|
|
@@ -75,15 +160,108 @@ table.addEventListener('select', (e) => {
|
|
|
75
160
|
});</code-ui>
|
|
76
161
|
</section>
|
|
77
162
|
|
|
163
|
+
<section data-section data-property="anatomy-floating">
|
|
164
|
+
<h2 variant="section">Anatomy — floating (bottom-anchored)</h2>
|
|
165
|
+
<p data-note>
|
|
166
|
+
<code>[data-table-scroll]</code> wraps the table and IS its scroll container (bounded height +
|
|
167
|
+
<code>overflow: auto</code>); the floating bar is a sibling of <code><table-ui></code>
|
|
168
|
+
inside it, positioned with <code>position: sticky</code> so it pins to that box's bottom edge
|
|
169
|
+
— never the browser viewport, and never a child of <code><table-ui></code> (it owns its
|
|
170
|
+
own light DOM). The bar is a <code><card-ui elevation="3"></code> for the card-like
|
|
171
|
+
elevated container, holding a standard <code><toolbar-ui></code>.
|
|
172
|
+
</p>
|
|
173
|
+
<code-ui language="html"><section bleed>
|
|
174
|
+
<table-toolbar-ui for="resources" text="Resources" count="12"></table-toolbar-ui>
|
|
175
|
+
|
|
176
|
+
<div data-table-scroll> <!-- position: relative; overflow: auto; max-height: … -->
|
|
177
|
+
<table-ui id="resources" selectable sortable></table-ui>
|
|
178
|
+
|
|
179
|
+
<!-- Floating bar — position: sticky; bottom: … in the pattern's CSS.
|
|
180
|
+
No [hidden]/display:none toggle — see the pattern's CSS comment
|
|
181
|
+
on why (toolbar-ui's overflow measurement gets stuck at 0px). -->
|
|
182
|
+
<card-ui elevation="3" data-bulk-bar-floating>
|
|
183
|
+
<section>
|
|
184
|
+
<!-- align="space-between" pushes the action group right — NOT a
|
|
185
|
+
flex-grow spacer span or an auto margin on a content item.
|
|
186
|
+
toolbar-ui's overflow reflow sums each top-level child's
|
|
187
|
+
RENDERED width to decide what fits; anything that absorbs free
|
|
188
|
+
space has already expanded to fill it by the time it's
|
|
189
|
+
measured, so the sum always reads "full" and spuriously spills
|
|
190
|
+
content. Two <toolbar-group-ui> atoms + align="space-between"
|
|
191
|
+
keeps the width sum accurate (see Rules). -->
|
|
192
|
+
<toolbar-ui role="toolbar" aria-label="Bulk actions" align="space-between">
|
|
193
|
+
<toolbar-group-ui>
|
|
194
|
+
<text-ui strong aria-live="polite"><span data-bulk-count>0</span> selected</text-ui>
|
|
195
|
+
<span data-bulk-controls></span> <!-- optional per-flow controls, e.g. a shared-rationale input -->
|
|
196
|
+
</toolbar-group-ui>
|
|
197
|
+
<toolbar-group-ui>
|
|
198
|
+
<!-- Icon-only (icon-only + aria-label) — a compact floating
|
|
199
|
+
pill has less width to spend than the full-width top-swap
|
|
200
|
+
bar. -->
|
|
201
|
+
<button-ui icon="archive" icon-only aria-label="Archive" variant="ghost" size="sm"></button-ui>
|
|
202
|
+
<button-ui icon="download-simple" icon-only aria-label="Export" variant="ghost" size="sm"></button-ui>
|
|
203
|
+
<button-ui icon="folder-simple" icon-only aria-label="Move" variant="ghost" size="sm"></button-ui>
|
|
204
|
+
<divider-ui vertical></divider-ui>
|
|
205
|
+
<button-ui icon="trash" icon-only aria-label="Delete" variant="ghost" size="sm"></button-ui>
|
|
206
|
+
<divider-ui vertical></divider-ui>
|
|
207
|
+
<button-ui text="Clear" variant="ghost" size="sm" data-bulk-clear></button-ui>
|
|
208
|
+
</toolbar-group-ui>
|
|
209
|
+
</toolbar-ui>
|
|
210
|
+
</section>
|
|
211
|
+
</card-ui>
|
|
212
|
+
</div>
|
|
213
|
+
</section></code-ui>
|
|
214
|
+
<code-ui language="javascript">// Enter/exit toggles [data-open]/[data-closing]; the CSS does the rest —
|
|
215
|
+
// including the delayed `visibility: hidden` on close (see the pattern's
|
|
216
|
+
// own <style> block). No [hidden]/display:none toggle: toolbar-ui's
|
|
217
|
+
// spillover system measures its own width via ResizeObserver on first
|
|
218
|
+
// connect, and a display:none ancestor at that moment gives it a 0px
|
|
219
|
+
// reading it does not reliably re-measure later — items it moved to the
|
|
220
|
+
// "more" overflow menu at that 0px reading stay stuck there even once the
|
|
221
|
+
// bar has real width. `visibility` keeps the box laid out (real width,
|
|
222
|
+
// always measurable) while still pulling it out of the a11y tree, tab
|
|
223
|
+
// order, and click target when closed.
|
|
224
|
+
|
|
225
|
+
function showBar(bar) {
|
|
226
|
+
bar.removeAttribute('data-closing');
|
|
227
|
+
bar.setAttribute('data-open', ''); // no .focus() — never steal focus on appearance
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function hideBar(bar) {
|
|
231
|
+
bar.setAttribute('data-closing', '');
|
|
232
|
+
bar.removeAttribute('data-open');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
table.addEventListener('select', (e) => {
|
|
236
|
+
const n = e.detail?.selected?.length ?? 0;
|
|
237
|
+
countEl.textContent = String(n);
|
|
238
|
+
n > 0 ? showBar(bar) : hideBar(bar);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Escape clears selection ONLY when the bar owns focus (listener lives
|
|
242
|
+
// on the bar itself, so it only fires while focus is inside it).
|
|
243
|
+
bar.addEventListener('keydown', (e) => {
|
|
244
|
+
if (e.key === 'Escape') { e.stopPropagation(); table.clearSelection(); }
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
bar.addEventListener('press', (e) => {
|
|
248
|
+
if (e.target?.closest?.('[data-bulk-clear], [data-bulk-action]')) {
|
|
249
|
+
table.clearSelection();
|
|
250
|
+
}
|
|
251
|
+
});</code-ui>
|
|
252
|
+
</section>
|
|
253
|
+
|
|
78
254
|
<section data-section data-property="rules">
|
|
79
255
|
<h2 variant="section">Rules</h2>
|
|
80
256
|
<ul>
|
|
81
|
-
<li>
|
|
82
|
-
<li>
|
|
83
|
-
<li>
|
|
84
|
-
<li>
|
|
85
|
-
<li>
|
|
257
|
+
<li>Pick one variant per table — see When to use. Both stay valid; don't run both at once on the same table.</li>
|
|
258
|
+
<li>Default state uses <code><table-toolbar-ui></code> — the modern foundation. It already wires Filter / Sort / Columns / Search to the table via <code>[for]</code>; don't hand-roll those. The floating variant keeps it visible at all times (it doesn't swap).</li>
|
|
259
|
+
<li>Every bulk bar uses <code><toolbar-ui></code> with <code>role="toolbar"</code> and <code>aria-label="Bulk actions"</code>.</li>
|
|
260
|
+
<li><strong>Toolbar swap:</strong> match its <code>--toolbar-py</code> / <code>--toolbar-px</code> to <code>--table-toolbar-py</code> / <code>--table-toolbar-px</code> so the swap is seamless; both toolbars sit inside the same <code><section bleed></code> as the table, flush with the first table cell.</li>
|
|
261
|
+
<li><strong>Floating:</strong> wrap the bar in <code><card-ui elevation="3"></code> for the card-like elevated surface (tokens only — <code>--a-shadow-*</code> via <code>[elevation]</code>, never a raw color/shadow); position it with <code>position: sticky</code> inside a <code>[data-table-scroll]</code> wrapper that IS the table's own scroll container (bounded height + <code>overflow: auto</code>) — never <code>position: fixed</code> to the viewport, and never a child of <code><table-ui></code> itself (it owns its own light DOM).</li>
|
|
262
|
+
<li>Selection count leads every bar. Group the count (+ optional controls) and the action buttons into two <code><toolbar-group-ui></code> atoms and set <code><toolbar-ui align="space-between"></code> to push the action group right — <strong>not</strong> a flex-grow <code><span></code> spacer or an auto margin on a content item. <code><toolbar-ui></code>'s overflow reflow sums each top-level child's rendered width to decide what fits; anything that absorbs free space (flex-grow, or an auto margin resolved to real pixels post-layout) has already expanded to fill that space by the time it's measured, so the sum always reads "full" and spuriously spills the trailing action(s) into an unreachable "more" menu — this is a real, previously-shipped bug in this pattern's own swap-variant demo (Delete was silently unreachable), fixed alongside the floating variant (gh#494 audit finding). <code>justify-content</code> only repositions flex items, never their widths, so it doesn't trip the same measurement. On the floating bar the count sits in an <code>aria-live="polite"</code> element so screen readers hear the running total; an optional <code><span data-bulk-controls></code> slot follows it for per-flow controls (e.g. a shared-rationale input) — empty by default.</li>
|
|
263
|
+
<li>Destructive actions go last and are visually separated with a <code><divider-ui vertical></code>. The floating bar additionally ends with an explicit Clear button (its own divider before it) — don't make "untick every row" the only way to dismiss it.</li>
|
|
86
264
|
<li>Keep bulk actions to 3–5; overflow belongs in a <code><popover-ui></code> "More" menu trailing the divider.</li>
|
|
87
|
-
<li>Drive
|
|
265
|
+
<li>Drive both variants from the table's <code>select</code> event (<code>detail.selected: number[]</code>) — don't unmount. The toolbar swap toggles <code>hidden</code>. The floating bar toggles <code>[data-open]</code>/<code>[data-closing]</code> instead — never <code>[hidden]</code>/<code>display:none</code>, which resets <code><toolbar-ui></code>'s overflow measurement to 0px and strands items in its "more" menu even once the bar has real width again. The floating bar additionally: never calls <code>.focus()</code> on appearance (no focus steal), and its <code>keydown</code> listener lives on the bar itself so Escape only clears selection while the bar owns focus.</li>
|
|
88
266
|
</ul>
|
|
89
267
|
</section>
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bulk action toolbar — populates the demo
|
|
3
|
-
* selection-driven toolbar swap
|
|
2
|
+
* Bulk action toolbar — populates the demo tables and wires both
|
|
3
|
+
* selection-driven variants: the top-anchored toolbar swap, and the
|
|
4
|
+
* bottom-anchored floating bar (gh#494).
|
|
4
5
|
*
|
|
5
6
|
* Default state shows <table-toolbar-ui> (Filter/Sort/Columns/Search,
|
|
6
|
-
* wired via [for]). When rows are selected
|
|
7
|
-
*
|
|
7
|
+
* wired via [for]). When rows are selected: the swap variant hides it
|
|
8
|
+
* for <toolbar-ui data-bulk-bar>; the floating variant leaves it
|
|
9
|
+
* visible and rises a <card-ui elevation="3"> bar from the bottom of
|
|
10
|
+
* the table's own scroll container.
|
|
8
11
|
*/
|
|
9
12
|
|
|
10
13
|
const columns = [
|
|
@@ -26,7 +29,25 @@ const data = [
|
|
|
26
29
|
{ name: 'Hiring plan', owner: 'Sarah Miller', status: 'Draft', updated: '2 weeks ago' },
|
|
27
30
|
];
|
|
28
31
|
|
|
32
|
+
// Floating-variant demo needs more rows than fit in the bounded
|
|
33
|
+
// [data-table-scroll] height, so the scroll behavior (bar tracks the
|
|
34
|
+
// table's own scroll box, not the page) is actually exercisable.
|
|
35
|
+
const floatData = [
|
|
36
|
+
...data,
|
|
37
|
+
{ name: 'Vendor contracts', owner: 'James Park', status: 'Active', updated: '3 weeks ago' },
|
|
38
|
+
{ name: 'Onboarding kit', owner: 'Maria Lopez', status: 'Draft', updated: '1 month ago' },
|
|
39
|
+
{ name: 'Security review', owner: 'Alex Chen', status: 'Active', updated: '1 month ago' },
|
|
40
|
+
{ name: 'Retro notes', owner: 'Sarah Miller', status: 'Archived', updated: '2 months ago' },
|
|
41
|
+
{ name: 'Budget draft', owner: 'James Park', status: 'Draft', updated: '2 months ago' },
|
|
42
|
+
{ name: 'Partner deck', owner: 'Maria Lopez', status: 'Active', updated: '3 months ago' },
|
|
43
|
+
];
|
|
44
|
+
|
|
29
45
|
export default function setup(router) {
|
|
46
|
+
setupSwap(router);
|
|
47
|
+
setupFloating(router);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function setupSwap(router) {
|
|
30
51
|
const table = router.querySelector('#pat-bulk-table');
|
|
31
52
|
const tbar = router.querySelector('#pat-bulk-default');
|
|
32
53
|
const bulk = router.querySelector('#pat-bulk-actions');
|
|
@@ -67,3 +88,61 @@ export default function setup(router) {
|
|
|
67
88
|
table.clearSelection();
|
|
68
89
|
});
|
|
69
90
|
}
|
|
91
|
+
|
|
92
|
+
function setupFloating(router) {
|
|
93
|
+
const table = router.querySelector('#pat-bulk-float-table');
|
|
94
|
+
const tbar = router.querySelector('#pat-bulk-float-default');
|
|
95
|
+
const bar = router.querySelector('#pat-bulk-float-bar');
|
|
96
|
+
const countEl = bar?.querySelector('[data-bulk-float-count]');
|
|
97
|
+
if (!table || !tbar || !bar) return;
|
|
98
|
+
|
|
99
|
+
table.columns = columns;
|
|
100
|
+
table.data = floatData;
|
|
101
|
+
|
|
102
|
+
// Enter/exit toggles [data-open]/[data-closing]; the CSS does the rest
|
|
103
|
+
// (packages/web-components/patterns/bulk-action-toolbar/bulk-action-toolbar.html),
|
|
104
|
+
// including the delayed `visibility: hidden` on close. Deliberately NOT
|
|
105
|
+
// [hidden]/display:none: toolbar-ui's spillover system measures its own
|
|
106
|
+
// width via ResizeObserver on first connect, and a display:none ancestor
|
|
107
|
+
// at that moment gives it a 0px reading it does not reliably re-measure
|
|
108
|
+
// later — items it moves to the "more" overflow menu at that 0px reading
|
|
109
|
+
// stay stuck there even once the bar has real width (found composing
|
|
110
|
+
// this pattern; not a toolbar-ui fix in scope here). `visibility` keeps
|
|
111
|
+
// the box laid out (real, measurable width) while still pulling it out
|
|
112
|
+
// of the a11y tree, tab order, and click target when closed. No
|
|
113
|
+
// .focus() call anywhere — appearance never steals focus.
|
|
114
|
+
function showBar() {
|
|
115
|
+
bar.removeAttribute('data-closing');
|
|
116
|
+
bar.setAttribute('data-open', '');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function hideBar() {
|
|
120
|
+
bar.setAttribute('data-closing', '');
|
|
121
|
+
bar.removeAttribute('data-open');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
table.addEventListener('select', (e) => {
|
|
125
|
+
const n = e.detail?.selected?.length ?? 0;
|
|
126
|
+
if (countEl) countEl.textContent = String(n);
|
|
127
|
+
if (n > 0) showBar(); else hideBar();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Escape clears selection ONLY when the bar owns focus — the listener
|
|
131
|
+
// lives on the bar itself so it only fires while focus is inside it,
|
|
132
|
+
// never as a page-wide Escape trap.
|
|
133
|
+
bar.addEventListener('keydown', (e) => {
|
|
134
|
+
if (e.key === 'Escape') {
|
|
135
|
+
e.stopPropagation();
|
|
136
|
+
table.clearSelection();
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Demo-only: both bulk-action buttons and the explicit Clear button
|
|
141
|
+
// release the selection so the floating bar's exit transition is
|
|
142
|
+
// exercisable from either affordance.
|
|
143
|
+
bar.addEventListener('press', (e) => {
|
|
144
|
+
const target = e.target?.closest?.('[data-bulk-clear], [data-bulk-action]');
|
|
145
|
+
if (!target) return;
|
|
146
|
+
table.clearSelection();
|
|
147
|
+
});
|
|
148
|
+
}
|
|
@@ -10,10 +10,13 @@
|
|
|
10
10
|
<link rel="stylesheet" href="../../styles/tokens.css">
|
|
11
11
|
|
|
12
12
|
<!-- Component CSS — primitives this pattern composes -->
|
|
13
|
+
<link rel="stylesheet" href="../../components/badge/badge.css">
|
|
13
14
|
<link rel="stylesheet" href="../../components/button/button.css">
|
|
14
15
|
<link rel="stylesheet" href="../../components/card/card.css">
|
|
16
|
+
<link rel="stylesheet" href="../../components/check/check.css">
|
|
15
17
|
<link rel="stylesheet" href="../../components/code/code.css">
|
|
16
18
|
<link rel="stylesheet" href="../../components/divider/divider.css">
|
|
19
|
+
<link rel="stylesheet" href="../../components/icon/icon.css">
|
|
17
20
|
<link rel="stylesheet" href="../../components/table/table.css">
|
|
18
21
|
<link rel="stylesheet" href="../../components/table-toolbar/table-toolbar.css">
|
|
19
22
|
<link rel="stylesheet" href="../../components/tag/tag.css">
|
|
@@ -21,19 +24,84 @@
|
|
|
21
24
|
<link rel="stylesheet" href="../../components/toolbar/toolbar.css">
|
|
22
25
|
|
|
23
26
|
<!-- Component JS -->
|
|
27
|
+
<script type="module" src="../../components/badge/badge.js"></script>
|
|
24
28
|
<script type="module" src="../../components/button/button.js"></script>
|
|
25
29
|
<script type="module" src="../../components/card/card.js"></script>
|
|
30
|
+
<script type="module" src="../../components/check/check.js"></script>
|
|
26
31
|
<script type="module" src="../../components/code/code.js"></script>
|
|
27
32
|
<script type="module" src="../../components/divider/divider.js"></script>
|
|
33
|
+
<script type="module" src="../../components/icon/icon.js"></script>
|
|
28
34
|
<script type="module" src="../../components/table/table.js"></script>
|
|
29
35
|
<script type="module" src="../../components/table-toolbar/table-toolbar.js"></script>
|
|
30
36
|
<script type="module" src="../../components/tag/tag.js"></script>
|
|
31
37
|
<script type="module" src="../../components/text/text.js"></script>
|
|
32
38
|
<script type="module" src="../../components/toolbar/toolbar.js"></script>
|
|
33
39
|
|
|
40
|
+
<script type="module" src="../../core/icons-phosphor.js"></script>
|
|
41
|
+
|
|
34
42
|
<style>
|
|
35
43
|
:where(html, body) { margin: 0; min-height: 100vh; background: var(--md-sys-color-neutral-background); color: var(--md-sys-color-neutral-on-surface); font-family: var(--a-font-family); }
|
|
36
44
|
main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
|
|
45
|
+
|
|
46
|
+
/* ── Floating bulk-action bar (gh#494) ──
|
|
47
|
+
[data-table-scroll] IS the table's scroll container — bounded
|
|
48
|
+
height + overflow: auto — so `position: sticky` on the floating
|
|
49
|
+
bar pins it to THAT box's bottom edge, never the browser viewport.
|
|
50
|
+
This is the compose-from-primitives shape gh#495's anchored-surface
|
|
51
|
+
primitive would eventually own; card-ui + toolbar-ui + sticky
|
|
52
|
+
positioning gets there without it. */
|
|
53
|
+
[data-table-scroll] {
|
|
54
|
+
position: relative;
|
|
55
|
+
overflow: auto;
|
|
56
|
+
max-height: 16rem;
|
|
57
|
+
}
|
|
58
|
+
/* `width: fit-content` here would create a circular sizing trap:
|
|
59
|
+
toolbar-ui's own overflow reflow measures ITS available width from
|
|
60
|
+
this box, but this box's fit-content size would in turn be derived
|
|
61
|
+
from the toolbar's (possibly already-collapsed) rendered content —
|
|
62
|
+
a self-reinforcing collapse the first time reflow ever runs while
|
|
63
|
+
hidden (0 available width) spills items into the overflow popover.
|
|
64
|
+
A fixed `max-width` breaks the loop: the box's width is deterministic
|
|
65
|
+
(bounded by the scroll container, capped at 40rem), independent of
|
|
66
|
+
the toolbar's own spillover state. */
|
|
67
|
+
[data-bulk-bar-floating] {
|
|
68
|
+
position: sticky;
|
|
69
|
+
bottom: var(--a-space-3);
|
|
70
|
+
z-index: 1;
|
|
71
|
+
margin-inline: auto;
|
|
72
|
+
width: 100%;
|
|
73
|
+
max-width: min(46rem, calc(100% - var(--a-space-6)));
|
|
74
|
+
opacity: 0;
|
|
75
|
+
transform: translateY(0.75rem);
|
|
76
|
+
transition: opacity var(--a-duration) var(--a-easing-out),
|
|
77
|
+
transform var(--a-duration) var(--a-easing-out),
|
|
78
|
+
visibility 0s linear var(--a-duration);
|
|
79
|
+
/* `visibility`, not `[hidden]`/`display:none` — closed state still
|
|
80
|
+
has box + layout, kept out of the a11y tree + tab order + click
|
|
81
|
+
target instead. toolbar-ui's spillover system measures its own
|
|
82
|
+
width via ResizeObserver on first connect; a `display:none`
|
|
83
|
+
ancestor at that moment gives it a 0px reading it never reliably
|
|
84
|
+
re-measures after unhiding (observed empirically: items it moved
|
|
85
|
+
to the "more" overflow menu at that 0px reading stayed stuck
|
|
86
|
+
there even once the bar had 700px+ to work with). Never toggling
|
|
87
|
+
display avoids the trap entirely — no toolbar-ui change needed. */
|
|
88
|
+
visibility: hidden;
|
|
89
|
+
}
|
|
90
|
+
[data-bulk-bar-floating][data-open] {
|
|
91
|
+
opacity: 1;
|
|
92
|
+
transform: translateY(0);
|
|
93
|
+
visibility: visible;
|
|
94
|
+
transition: opacity var(--a-duration) var(--a-easing-out),
|
|
95
|
+
transform var(--a-duration) var(--a-easing-out);
|
|
96
|
+
}
|
|
97
|
+
[data-bulk-bar-floating][data-closing] {
|
|
98
|
+
opacity: 0;
|
|
99
|
+
transform: translateY(0.75rem);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@media (prefers-reduced-motion: reduce) {
|
|
103
|
+
[data-bulk-bar-floating] { transition: none; }
|
|
104
|
+
}
|
|
37
105
|
</style>
|
|
38
106
|
</head>
|
|
39
107
|
<body>
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
<p data-note>Section-grouped layout (GitHub / Linear convention): each release carries a version + date header, then per-section eyebrows (Added / Changed / Fixed / Deprecated / Removed) followed by bulleted prose. Sections are <em>grouped</em>, not tagged per row — variable tag widths break left-edge alignment of prose; eyebrow + bullets keep one consistent reading column.</p>
|
|
19
19
|
<div data-artifact-container>
|
|
20
20
|
<div data-artifact-item data-artifact-label="changelog feed — 3 releases">
|
|
21
|
-
<card-ui data-chunk="changelog-feed-basic"
|
|
21
|
+
<card-ui data-chunk="changelog-feed-basic" data-chunk-kind="block"
|
|
22
|
+
data-chunk-domain="content"
|
|
23
|
+
data-chunk-description="Changelog feed card — 'What's new' releases in reverse order, each with version number, Latest tag, date, and categorized change entries (features, fixes) as text rows."
|
|
24
|
+
data-chunk-keywords="changelog whats-new releases feed version latest date features fixes updates notes product announcements" style="max-width: 640px;">
|
|
22
25
|
<header>
|
|
23
26
|
<span slot="heading" variant="section">What's new</span>
|
|
24
27
|
<text-ui slot="description" color="subtle">3 releases in the last 30 days</text-ui>
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
<p data-note>KPI + trend shape. Used in overview rows to show 4–6 metrics side-by-side.</p>
|
|
23
23
|
<div data-artifact-container>
|
|
24
24
|
<div data-artifact-item data-artifact-label="sparkline tile">
|
|
25
|
-
<card-ui data-chunk="chart-in-card-sparkline-tile"
|
|
25
|
+
<card-ui data-chunk="chart-in-card-sparkline-tile" data-chunk-kind="block"
|
|
26
|
+
data-chunk-domain="dashboard"
|
|
27
|
+
data-chunk-description="Sparkline metric tile — compact card with metric name, big current value (Page Views 84,232), and an edge-to-edge sparkline chart bleeding below."
|
|
28
|
+
data-chunk-keywords="sparkline tile metric card page-views value chart compact dashboard kpi trend mini analytics" style="max-width:320px;">
|
|
26
29
|
<header>
|
|
27
30
|
<span slot="heading"><h2>Page Views</h2></span>
|
|
28
31
|
<text-ui slot="description" variant="title">84,232</text-ui>
|
|
@@ -40,7 +43,10 @@
|
|
|
40
43
|
<p data-note>Chart as primary content. Header names the metric; footer adds a supporting action.</p>
|
|
41
44
|
<div data-artifact-container>
|
|
42
45
|
<div data-artifact-item data-artifact-label="full chart">
|
|
43
|
-
<card-ui data-chunk="chart-in-card-full-chart"
|
|
46
|
+
<card-ui data-chunk="chart-in-card-full-chart" data-chunk-kind="block"
|
|
47
|
+
data-chunk-domain="dashboard"
|
|
48
|
+
data-chunk-description="Full chart card — Revenue bar chart over the last 12 months with title and range description in the header and a stretch View-report footer button."
|
|
49
|
+
data-chunk-keywords="chart card bar revenue months report full analytics dashboard footer button range" style="max-width:520px;">
|
|
44
50
|
<header>
|
|
45
51
|
<span slot="heading"><h3>Revenue</h3></span>
|
|
46
52
|
<text-ui slot="description" color="subtle">Last 12 months</text-ui>
|
|
@@ -61,7 +67,10 @@
|
|
|
61
67
|
<p data-note>Stat in header pairs with the chart so the current value is legible before the chart renders.</p>
|
|
62
68
|
<div data-artifact-container>
|
|
63
69
|
<div data-artifact-item data-artifact-label="chart plus stat">
|
|
64
|
-
<card-ui data-chunk="chart-in-card-chart-plus-stat"
|
|
70
|
+
<card-ui data-chunk="chart-in-card-chart-plus-stat" data-chunk-kind="block"
|
|
71
|
+
data-chunk-domain="dashboard"
|
|
72
|
+
data-chunk-description="Stat-headed chart card — an MRR stat with change delta and trend arrow as the card header, over a smooth line chart of the metric's history."
|
|
73
|
+
data-chunk-keywords="chart stat card mrr line smooth trend delta header metric history dashboard analytics revenue" style="max-width:520px;">
|
|
65
74
|
<header>
|
|
66
75
|
<span slot="heading">
|
|
67
76
|
<stat-ui label="MRR" value="$48,290" change="+12.4%" trend="up"></stat-ui>
|
|
@@ -80,7 +89,10 @@
|
|
|
80
89
|
<p data-note>Chart shows aggregate; breakdown beneath gives the composition. Most SaaS "Overview" tiles follow this shape.</p>
|
|
81
90
|
<div data-artifact-container>
|
|
82
91
|
<div data-artifact-item data-artifact-label="chart plus breakdown">
|
|
83
|
-
<card-ui data-chunk="chart-in-card-chart-plus-breakdown"
|
|
92
|
+
<card-ui data-chunk="chart-in-card-chart-plus-breakdown" data-chunk-kind="block"
|
|
93
|
+
data-chunk-domain="dashboard"
|
|
94
|
+
data-chunk-description="Chart with breakdown card — Sessions bar chart for the week over a 3-up grid of stat tiles decomposing the total by segment (Desktop / Mobile / Tablet)."
|
|
95
|
+
data-chunk-keywords="chart breakdown card sessions bar stats grid desktop mobile tablet segments decomposition dashboard analytics" style="max-width:520px;">
|
|
84
96
|
<header>
|
|
85
97
|
<span slot="heading"><h3>Sessions</h3></span>
|
|
86
98
|
<text-ui slot="description" color="subtle">This week</text-ui>
|
|
@@ -105,7 +117,10 @@
|
|
|
105
117
|
<p data-note>Footer carries trend narrative + period caption using the new footer <code>heading</code> / <code>description</code> slot routing (symmetric with header). Shadcn-style revenue card translated to AdiaUI primitives.</p>
|
|
106
118
|
<div data-artifact-container>
|
|
107
119
|
<div data-artifact-item data-artifact-label="area chart + trend footer">
|
|
108
|
-
<card-ui data-chunk="chart-in-card-trend-footer"
|
|
120
|
+
<card-ui data-chunk="chart-in-card-trend-footer" data-chunk-kind="block"
|
|
121
|
+
data-chunk-domain="dashboard"
|
|
122
|
+
data-chunk-description="Area chart card with trend footer — Revenue area chart for a date range, footer states the takeaway ('Trending up by 5.2% this month') with a data-scope caption."
|
|
123
|
+
data-chunk-keywords="chart area card trend footer takeaway revenue range summary insight dashboard analytics" style="max-width:520px;">
|
|
109
124
|
<header>
|
|
110
125
|
<span slot="heading"><h3>Revenue</h3></span>
|
|
111
126
|
<text-ui slot="description" color="subtle">January – March 2024</text-ui>
|
|
@@ -127,7 +142,10 @@
|
|
|
127
142
|
<p data-note>Stat-ui's <code>chart</code> slot positions a sparkline to the right of the hero number — KPI and its trajectory as one visual unit.</p>
|
|
128
143
|
<div data-artifact-container>
|
|
129
144
|
<div data-artifact-item data-artifact-label="stat with sparkline slot">
|
|
130
|
-
<card-ui data-chunk="chart-in-card-stat-with-sparkline"
|
|
145
|
+
<card-ui data-chunk="chart-in-card-stat-with-sparkline" data-chunk-kind="block"
|
|
146
|
+
data-chunk-domain="dashboard"
|
|
147
|
+
data-chunk-description="Stat with inline sparkline — a single stat (Revenue $48.2k, +12.5% up) carrying a sparkline in its chart slot; the smallest chart-bearing KPI tile."
|
|
148
|
+
data-chunk-keywords="stat sparkline kpi tile revenue change trend inline chart slot compact dashboard metric" style="max-width:320px;">
|
|
131
149
|
<section>
|
|
132
150
|
<stat-ui label="Revenue" value="$48.2k" change="+12.5%" trend="up">
|
|
133
151
|
<chart-ui id="pat-stat-spark" slot="chart" type="sparkline" x="month" y="value"></chart-ui>
|
|
@@ -143,7 +161,10 @@
|
|
|
143
161
|
<p data-note>A <code>segmented-ui</code> in the header's <code>action</code> slot drives a time-range selection. Wire its <code>value</code> to refetch / slice the chart's <code>.data</code> via a controller.</p>
|
|
144
162
|
<div data-artifact-container>
|
|
145
163
|
<div data-artifact-item data-artifact-label="chart with 1w / 2w / 1m / 3m pills">
|
|
146
|
-
<card-ui data-chunk="chart-in-card-chart-with-filter-pills"
|
|
164
|
+
<card-ui data-chunk="chart-in-card-chart-with-filter-pills" data-chunk-kind="block"
|
|
165
|
+
data-chunk-domain="dashboard"
|
|
166
|
+
data-chunk-description="Chart card with range picker — Sessions chart whose header action is a segmented control of time ranges (1w / 2w / 1m / 3m) that filters the plotted window."
|
|
167
|
+
data-chunk-keywords="chart card segmented range picker filter pills time window sessions week month dashboard analytics toggle" style="max-width:520px;">
|
|
147
168
|
<header>
|
|
148
169
|
<span slot="heading"><h3>Sessions</h3></span>
|
|
149
170
|
<segmented-ui slot="action" value="1m">
|