@adia-ai/web-components 0.8.24 → 0.8.26
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 +25 -0
- package/components/anchor-bar/anchor-bar.a2ui.json +139 -0
- package/components/anchor-bar/anchor-bar.class.js +124 -0
- package/components/anchor-bar/anchor-bar.css +140 -0
- package/components/anchor-bar/anchor-bar.d.ts +35 -0
- package/components/anchor-bar/anchor-bar.examples.md +32 -0
- package/components/anchor-bar/anchor-bar.js +17 -0
- package/components/anchor-bar/anchor-bar.yaml +167 -0
- package/components/chart/chart.a2ui.json +16 -0
- package/components/chart/chart.class.js +105 -27
- package/components/chart/chart.css +27 -0
- package/components/chart/chart.d.ts +4 -0
- package/components/chart/chart.yaml +28 -0
- package/components/index.js +1 -0
- package/components/richtext/richtext.css +7 -2
- package/components/stat/stat.a2ui.json +8 -0
- package/components/stat/stat.css +39 -0
- package/components/stat/stat.d.ts +2 -0
- package/components/stat/stat.js +5 -0
- package/components/stat/stat.yaml +11 -0
- package/components/tooltip/tooltip.class.js +17 -11
- package/dist/host.min.css +1 -1
- package/dist/host.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 +113 -113
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +81 -93
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +12 -25
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.html +8 -52
- package/styles/api/parametric-scope.css +81 -0
- package/styles/components.css +1 -0
- package/styles/tokens.css +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.26",
|
|
4
4
|
"description": "AdiaUI web components \u2014 vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -2,7 +2,7 @@
|
|
|
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> <tag-ui size="sm">card-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> <tag-ui size="sm">anchor-bar-ui</tag-ui>
|
|
6
6
|
</div>
|
|
7
7
|
</div>
|
|
8
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>
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
|
|
68
68
|
<section data-section data-property="floating-variant" data-chunk="bulk-action-toolbar-floating" data-chunk-kind="block"
|
|
69
69
|
data-chunk-domain="data"
|
|
70
|
-
data-chunk-description="Floating bottom-anchored bulk-action bar —
|
|
70
|
+
data-chunk-description="Floating bottom-anchored bulk-action bar — an anchor-bar-ui elevated toolbar 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 anchor-bar-ui + toolbar-ui; no focus steal on appearance, Escape clears selection when the bar owns focus, count is aria-live=polite."
|
|
71
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
72
|
<h2 variant="section">Floating (bottom-anchored)</h2>
|
|
73
73
|
<p data-note>
|
|
@@ -83,38 +83,36 @@
|
|
|
83
83
|
<div data-table-scroll>
|
|
84
84
|
<table-ui frameless id="pat-bulk-float-table" selectable sortable striped></table-ui>
|
|
85
85
|
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<toolbar-ui
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
</section>
|
|
117
|
-
</card-ui>
|
|
86
|
+
<anchor-bar-ui id="pat-bulk-float-bar" anchor="bottom">
|
|
87
|
+
<!-- align="space-between" pushes the trailing group right —
|
|
88
|
+
NOT a flex-grow spacer span or an auto margin on a content
|
|
89
|
+
item. toolbar-ui's overflow reflow sums each top-level
|
|
90
|
+
child's RENDERED width to decide what fits; any child that
|
|
91
|
+
absorbs free space (flex-grow, or an auto margin resolved
|
|
92
|
+
to real pixels post-layout) has already expanded to fill
|
|
93
|
+
that space by the time it's measured, so the sum always
|
|
94
|
+
reads "full" and spuriously spills content. `justify-content`
|
|
95
|
+
only repositions flex items — it doesn't touch their
|
|
96
|
+
individual widths (toolbar-ui's own CSS pins every direct
|
|
97
|
+
child at `flex: 0 0 auto`) — so grouping into two
|
|
98
|
+
`<toolbar-group-ui>` atoms and letting `align="space-between"`
|
|
99
|
+
do the pushing keeps the reflow's width sum accurate. -->
|
|
100
|
+
<toolbar-ui role="toolbar" aria-label="Bulk actions" align="space-between">
|
|
101
|
+
<toolbar-group-ui>
|
|
102
|
+
<text-ui strong aria-live="polite"><span data-bulk-float-count>0</span> selected</text-ui>
|
|
103
|
+
<span data-bulk-controls></span>
|
|
104
|
+
</toolbar-group-ui>
|
|
105
|
+
<toolbar-group-ui>
|
|
106
|
+
<button-ui icon="archive" icon-only aria-label="Archive" variant="ghost" size="sm" data-bulk-action="archive"></button-ui>
|
|
107
|
+
<button-ui icon="download-simple" icon-only aria-label="Export" variant="ghost" size="sm" data-bulk-action="export"></button-ui>
|
|
108
|
+
<button-ui icon="folder-simple" icon-only aria-label="Move" variant="ghost" size="sm" data-bulk-action="move"></button-ui>
|
|
109
|
+
<divider-ui vertical></divider-ui>
|
|
110
|
+
<button-ui icon="trash" icon-only aria-label="Delete" variant="ghost" size="sm" data-bulk-action="delete"></button-ui>
|
|
111
|
+
<divider-ui vertical></divider-ui>
|
|
112
|
+
<button-ui text="Clear" variant="ghost" size="sm" data-bulk-clear></button-ui>
|
|
113
|
+
</toolbar-group-ui>
|
|
114
|
+
</toolbar-ui>
|
|
115
|
+
</anchor-bar-ui>
|
|
118
116
|
</div>
|
|
119
117
|
</section>
|
|
120
118
|
</card-ui>
|
|
@@ -165,10 +163,12 @@ table.addEventListener('select', (e) => {
|
|
|
165
163
|
<p data-note>
|
|
166
164
|
<code>[data-table-scroll]</code> wraps the table and IS its scroll container (bounded height +
|
|
167
165
|
<code>overflow: auto</code>); the floating bar is a sibling of <code><table-ui></code>
|
|
168
|
-
inside it
|
|
166
|
+
inside it. The bar is an <code><anchor-bar-ui anchor="bottom"></code> (gh#495) — its
|
|
167
|
+
default mode positions with <code>position: sticky</code> so it pins to that box's bottom edge
|
|
169
168
|
— never the browser viewport, and never a child of <code><table-ui></code> (it owns its
|
|
170
|
-
own light DOM)
|
|
171
|
-
elevated
|
|
169
|
+
own light DOM) — holding a standard <code><toolbar-ui></code>. <code>anchor-bar-ui</code>
|
|
170
|
+
owns the elevated-surface chrome (bg/border/radius/shadow) directly; no wrapping
|
|
171
|
+
<code><card-ui></code> needed.
|
|
172
172
|
</p>
|
|
173
173
|
<code-ui language="html"><section bleed>
|
|
174
174
|
<table-toolbar-ui for="resources" text="Resources" count="12"></table-toolbar-ui>
|
|
@@ -176,66 +176,54 @@ table.addEventListener('select', (e) => {
|
|
|
176
176
|
<div data-table-scroll> <!-- position: relative; overflow: auto; max-height: … -->
|
|
177
177
|
<table-ui id="resources" selectable sortable></table-ui>
|
|
178
178
|
|
|
179
|
-
<!-- Floating bar —
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
</
|
|
209
|
-
</toolbar-ui>
|
|
210
|
-
</
|
|
211
|
-
</
|
|
179
|
+
<!-- Floating bar — anchor-bar-ui's default mode is position:sticky
|
|
180
|
+
within the nearest scroll container. [open] controls visibility
|
|
181
|
+
via opacity/visibility, never [hidden]/display:none — see the
|
|
182
|
+
pattern's CSS comment on why (toolbar-ui's overflow measurement
|
|
183
|
+
gets stuck at 0px). -->
|
|
184
|
+
<anchor-bar-ui anchor="bottom">
|
|
185
|
+
<!-- align="space-between" pushes the action group right — NOT a
|
|
186
|
+
flex-grow spacer span or an auto margin on a content item.
|
|
187
|
+
toolbar-ui's overflow reflow sums each top-level child's
|
|
188
|
+
RENDERED width to decide what fits; anything that absorbs free
|
|
189
|
+
space has already expanded to fill it by the time it's
|
|
190
|
+
measured, so the sum always reads "full" and spuriously spills
|
|
191
|
+
content. Two <toolbar-group-ui> atoms + align="space-between"
|
|
192
|
+
keeps the width sum accurate (see Rules). -->
|
|
193
|
+
<toolbar-ui role="toolbar" aria-label="Bulk actions" align="space-between">
|
|
194
|
+
<toolbar-group-ui>
|
|
195
|
+
<text-ui strong aria-live="polite"><span data-bulk-count>0</span> selected</text-ui>
|
|
196
|
+
<span data-bulk-controls></span> <!-- optional per-flow controls, e.g. a shared-rationale input -->
|
|
197
|
+
</toolbar-group-ui>
|
|
198
|
+
<toolbar-group-ui>
|
|
199
|
+
<!-- Icon-only (icon-only + aria-label) — a compact floating
|
|
200
|
+
pill has less width to spend than the full-width top-swap
|
|
201
|
+
bar. -->
|
|
202
|
+
<button-ui icon="archive" icon-only aria-label="Archive" variant="ghost" size="sm"></button-ui>
|
|
203
|
+
<button-ui icon="download-simple" icon-only aria-label="Export" variant="ghost" size="sm"></button-ui>
|
|
204
|
+
<button-ui icon="folder-simple" icon-only aria-label="Move" variant="ghost" size="sm"></button-ui>
|
|
205
|
+
<divider-ui vertical></divider-ui>
|
|
206
|
+
<button-ui icon="trash" icon-only aria-label="Delete" variant="ghost" size="sm"></button-ui>
|
|
207
|
+
<divider-ui vertical></divider-ui>
|
|
208
|
+
<button-ui text="Clear" variant="ghost" size="sm" data-bulk-clear></button-ui>
|
|
209
|
+
</toolbar-group-ui>
|
|
210
|
+
</toolbar-ui>
|
|
211
|
+
</anchor-bar-ui>
|
|
212
212
|
</div>
|
|
213
213
|
</section></code-ui>
|
|
214
|
-
<code-ui language="javascript">//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
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
|
-
}
|
|
214
|
+
<code-ui language="javascript">// anchor-bar-ui's [open] IS the visibility state — no [hidden]/display:none
|
|
215
|
+
// toggle: toolbar-ui's spillover system measures its own width via
|
|
216
|
+
// ResizeObserver on first connect, and a display:none ancestor at that
|
|
217
|
+
// moment gives it a 0px reading it does not reliably re-measure later —
|
|
218
|
+
// items it moved to the "more" overflow menu at that 0px reading stay
|
|
219
|
+
// stuck there even once the bar has real width. anchor-bar-ui's own CSS
|
|
220
|
+
// handles the enter/exit opacity/visibility transition; no .focus() call
|
|
221
|
+
// anywhere — appearance never steals focus.
|
|
234
222
|
|
|
235
223
|
table.addEventListener('select', (e) => {
|
|
236
224
|
const n = e.detail?.selected?.length ?? 0;
|
|
237
225
|
countEl.textContent = String(n);
|
|
238
|
-
n > 0
|
|
226
|
+
bar.open = n > 0;
|
|
239
227
|
});
|
|
240
228
|
|
|
241
229
|
// Escape clears selection ONLY when the bar owns focus (listener lives
|
|
@@ -258,10 +246,10 @@ bar.addEventListener('press', (e) => {
|
|
|
258
246
|
<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
247
|
<li>Every bulk bar uses <code><toolbar-ui></code> with <code>role="toolbar"</code> and <code>aria-label="Bulk actions"</code>.</li>
|
|
260
248
|
<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>
|
|
249
|
+
<li><strong>Floating:</strong> use <code><anchor-bar-ui anchor="bottom"></code> (gh#495) for the elevated-surface chrome — its default mode is <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 a child of <code><table-ui></code> itself (it owns its own light DOM). Don't set <code>[viewport]</code> here — that opts into <code>position: fixed</code> to the browser viewport, which this pattern deliberately avoids.</li>
|
|
262
250
|
<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
251
|
<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>
|
|
264
252
|
<li>Keep bulk actions to 3–5; overflow belongs in a <code><popover-ui></code> "More" menu trailing the divider.</li>
|
|
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
|
|
253
|
+
<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 sets <code>anchor-bar-ui</code>'s <code>[open]</code> property 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 — <code>anchor-bar-ui</code> doesn't either), and its <code>keydown</code> listener lives on the bar itself so Escape only clears selection while the bar owns focus.</li>
|
|
266
254
|
</ul>
|
|
267
255
|
</section>
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* Default state shows <table-toolbar-ui> (Filter/Sort/Columns/Search,
|
|
7
7
|
* wired via [for]). When rows are selected: the swap variant hides it
|
|
8
8
|
* for <toolbar-ui data-bulk-bar>; the floating variant leaves it
|
|
9
|
-
* visible and rises
|
|
10
|
-
* the table's own scroll container.
|
|
9
|
+
* visible and rises an <anchor-bar-ui anchor="bottom"> (gh#495) from the
|
|
10
|
+
* bottom of the table's own scroll container.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
const columns = [
|
|
@@ -99,32 +99,19 @@ function setupFloating(router) {
|
|
|
99
99
|
table.columns = columns;
|
|
100
100
|
table.data = floatData;
|
|
101
101
|
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
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
|
-
|
|
102
|
+
// anchor-bar-ui's [open] property IS the visibility state (gh#495) — its
|
|
103
|
+
// own CSS handles the opacity/visibility enter/exit transition.
|
|
104
|
+
// Deliberately never [hidden]/display:none: toolbar-ui's spillover
|
|
105
|
+
// system measures its own width via ResizeObserver on first connect,
|
|
106
|
+
// and a display:none ancestor at that moment gives it a 0px reading it
|
|
107
|
+
// does not reliably re-measure later — items it moves to the "more"
|
|
108
|
+
// overflow menu at that 0px reading stay stuck there even once the bar
|
|
109
|
+
// has real width (found composing this pattern; not a toolbar-ui fix in
|
|
110
|
+
// scope here). No .focus() call anywhere — appearance never steals focus.
|
|
124
111
|
table.addEventListener('select', (e) => {
|
|
125
112
|
const n = e.detail?.selected?.length ?? 0;
|
|
126
113
|
if (countEl) countEl.textContent = String(n);
|
|
127
|
-
|
|
114
|
+
bar.open = n > 0;
|
|
128
115
|
});
|
|
129
116
|
|
|
130
117
|
// Escape clears selection ONLY when the bar owns focus — the listener
|
|
@@ -10,6 +10,7 @@
|
|
|
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/anchor-bar/anchor-bar.css">
|
|
13
14
|
<link rel="stylesheet" href="../../components/badge/badge.css">
|
|
14
15
|
<link rel="stylesheet" href="../../components/button/button.css">
|
|
15
16
|
<link rel="stylesheet" href="../../components/card/card.css">
|
|
@@ -24,6 +25,7 @@
|
|
|
24
25
|
<link rel="stylesheet" href="../../components/toolbar/toolbar.css">
|
|
25
26
|
|
|
26
27
|
<!-- Component JS -->
|
|
28
|
+
<script type="module" src="../../components/anchor-bar/anchor-bar.js"></script>
|
|
27
29
|
<script type="module" src="../../components/badge/badge.js"></script>
|
|
28
30
|
<script type="module" src="../../components/button/button.js"></script>
|
|
29
31
|
<script type="module" src="../../components/card/card.js"></script>
|
|
@@ -45,63 +47,17 @@
|
|
|
45
47
|
|
|
46
48
|
/* ── Floating bulk-action bar (gh#494) ──
|
|
47
49
|
[data-table-scroll] IS the table's scroll container — bounded
|
|
48
|
-
height + overflow: auto — so
|
|
49
|
-
|
|
50
|
-
This
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
height + overflow: auto — so anchor-bar-ui's default (non-
|
|
51
|
+
[viewport]) `position: sticky` pins it to THAT box's bottom edge,
|
|
52
|
+
never the browser viewport. This used to be a hand-rolled
|
|
53
|
+
card-ui + position:sticky recipe; gh#495 promoted it to
|
|
54
|
+
<anchor-bar-ui>'s own default mode (see anchor-bar.css) — this
|
|
55
|
+
pattern is now that primitive's canonical consumer. */
|
|
53
56
|
[data-table-scroll] {
|
|
54
57
|
position: relative;
|
|
55
58
|
overflow: auto;
|
|
56
59
|
max-height: 16rem;
|
|
57
60
|
}
|
|
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
|
-
}
|
|
105
61
|
</style>
|
|
106
62
|
</head>
|
|
107
63
|
<body>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/* adia:attribute-api/parametric-scope — [data-parametric-scope] re-derivation.
|
|
2
|
+
gh#570: custom properties resolve their calc()/clamp() formula at the
|
|
3
|
+
DECLARING element's own cascade, then inherit the already-resolved value
|
|
4
|
+
down. The primitive layer (foundation/{radius,space,size}.css) declares
|
|
5
|
+
every --a-radius-, --a-space-, and --a-size- formula exactly once, on
|
|
6
|
+
:root — so a descendant overriding --a-density/--a-radius-k (e.g. a
|
|
7
|
+
theme-panel[parametric target="#some-scoped-element"]) never causes
|
|
8
|
+
those derived tokens to re-resolve for its own subtree; it only affects
|
|
9
|
+
what --a-density/--a-radius-k itself reads as, everywhere DOWNSTREAM
|
|
10
|
+
formulas are declared (which is nowhere but :root).
|
|
11
|
+
|
|
12
|
+
[data-parametric-scope] is set by theme-panel.js on a non-root [target]
|
|
13
|
+
when [parametric] is active (never authored by hand) and mirrors these
|
|
14
|
+
SAME formula bodies verbatim so that scoped subtree gets its own working
|
|
15
|
+
copy of the derivation chain. This is the established codebase pattern,
|
|
16
|
+
not a new one — [size="sm"] below in this same file already duplicates
|
|
17
|
+
--a-size-sm's calc() rather than only pointing at it, for the identical
|
|
18
|
+
reason (a scoped attribute needs its OWN resolved value, not :root's).
|
|
19
|
+
|
|
20
|
+
Layer position: imported into layer(utilities), same as the rest of this
|
|
21
|
+
file — wins over foundation/'s layer(tokens) by layer order, though for
|
|
22
|
+
a non-root element that never mattered (no competing :root rule exists
|
|
23
|
+
there to begin with). */
|
|
24
|
+
|
|
25
|
+
[data-parametric-scope] {
|
|
26
|
+
/* ── Radius (foundation/radius.css) ── */
|
|
27
|
+
--a-radius-xs: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-xs-k)), var(--a-radius-max));
|
|
28
|
+
--a-radius-sm: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-sm-k)), var(--a-radius-max));
|
|
29
|
+
--a-radius-md: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-md-k)), var(--a-radius-max));
|
|
30
|
+
--a-radius-lg: clamp(var(--a-radius-min), calc(var(--a-radius-k) * var(--a-radius-max) * var(--a-radius-lg-k)), var(--a-radius-max));
|
|
31
|
+
--a-radius: var(--a-radius-md);
|
|
32
|
+
|
|
33
|
+
/* ── Spacing (foundation/space.css) ── */
|
|
34
|
+
--a-space-0-5: calc(var(--a-density) * 0.125rem);
|
|
35
|
+
--a-space-1: calc(var(--a-density) * 0.25rem);
|
|
36
|
+
--a-space-1-5: calc(var(--a-density) * 0.375rem);
|
|
37
|
+
--a-space-2: calc(var(--a-density) * 0.5rem);
|
|
38
|
+
--a-space-2-5: calc(var(--a-density) * 0.625rem);
|
|
39
|
+
--a-space-3: calc(var(--a-density) * 0.75rem);
|
|
40
|
+
--a-space-3-5: calc(var(--a-density) * 0.875rem);
|
|
41
|
+
--a-space-4: calc(var(--a-density) * 1rem);
|
|
42
|
+
--a-space-4-5: calc(var(--a-density) * 1.125rem);
|
|
43
|
+
--a-space-5: calc(var(--a-density) * 1.25rem);
|
|
44
|
+
--a-space-6: calc(var(--a-density) * 1.5rem);
|
|
45
|
+
--a-space-7: calc(var(--a-density) * 1.75rem);
|
|
46
|
+
--a-space-8: calc(var(--a-density) * 2rem);
|
|
47
|
+
--a-space-9: calc(var(--a-density) * 2.25rem);
|
|
48
|
+
--a-space-10: calc(var(--a-density) * 2.5rem);
|
|
49
|
+
--a-space-12: calc(var(--a-density) * 3rem);
|
|
50
|
+
--a-space-16: calc(var(--a-density) * 4rem);
|
|
51
|
+
|
|
52
|
+
--a-inset-sm: var(--a-space-3-5);
|
|
53
|
+
--a-inset-md: var(--a-space-4);
|
|
54
|
+
--a-inset-lg: var(--a-space-4-5);
|
|
55
|
+
--a-inset: var(--a-inset-md);
|
|
56
|
+
|
|
57
|
+
--a-gap-xs: calc(var(--a-space-2) * var(--a-gap-k));
|
|
58
|
+
--a-gap-sm: calc(var(--a-space-2-5) * var(--a-gap-k));
|
|
59
|
+
--a-gap-md: calc(var(--a-space-3) * var(--a-gap-k));
|
|
60
|
+
--a-gap-lg: calc(var(--a-space-3-5) * var(--a-gap-k));
|
|
61
|
+
--a-gap-xl: calc(var(--a-space-4) * var(--a-gap-k));
|
|
62
|
+
--a-gap: var(--a-gap-md);
|
|
63
|
+
|
|
64
|
+
--a-padding-xs: calc(var(--a-space-2) * var(--a-padding-k));
|
|
65
|
+
--a-padding-sm: calc(var(--a-space-4) * var(--a-padding-k));
|
|
66
|
+
--a-padding-md: calc(var(--a-space-6) * var(--a-padding-k));
|
|
67
|
+
--a-padding-lg: calc(var(--a-space-8) * var(--a-padding-k));
|
|
68
|
+
--a-padding-xl: calc(var(--a-space-10) * var(--a-padding-k));
|
|
69
|
+
--a-margin-xs: calc(var(--a-space-2) * var(--a-margin-k));
|
|
70
|
+
--a-margin-sm: calc(var(--a-space-4) * var(--a-margin-k));
|
|
71
|
+
--a-margin-md: calc(var(--a-space-6) * var(--a-margin-k));
|
|
72
|
+
--a-margin-lg: calc(var(--a-space-8) * var(--a-margin-k));
|
|
73
|
+
--a-margin-xl: calc(var(--a-space-10) * var(--a-margin-k));
|
|
74
|
+
|
|
75
|
+
/* ── Sizing (foundation/size.css) ── */
|
|
76
|
+
--a-size-sm: calc(var(--a-density) * 1.5rem);
|
|
77
|
+
--a-size-md: calc(var(--a-density) * 1.875rem);
|
|
78
|
+
--a-size-lg: calc(var(--a-density) * 2.25rem);
|
|
79
|
+
--a-size: var(--a-size-md);
|
|
80
|
+
--a-toggle-size: calc(var(--a-size-sm) - var(--a-space-1));
|
|
81
|
+
}
|
package/styles/components.css
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
@import "../components/modal/modal.css";
|
|
35
35
|
@import "../components/feed/feed.css";
|
|
36
36
|
@import "../components/toast/toast.css";
|
|
37
|
+
@import "../components/anchor-bar/anchor-bar.css";
|
|
37
38
|
@import "../components/tabs/tabs.css";
|
|
38
39
|
@import "../components/tooltip/tooltip.css";
|
|
39
40
|
@import "../components/badge/badge.css";
|
package/styles/tokens.css
CHANGED