@adia-ai/web-components 0.8.45 → 0.8.46
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 +9 -0
- package/components/card/card.css +12 -23
- package/components/card/card.yaml +11 -0
- package/components/chart/chart.a2ui.json +16 -1
- package/components/chart/chart.class.js +611 -41
- package/components/chart/chart.css +174 -0
- package/components/chart/chart.d.ts +5 -1
- package/components/chart/chart.yaml +45 -1
- package/components/field/field.css +24 -2
- package/components/index.js +1 -0
- package/components/input/input.css +7 -0
- package/components/table/table.a2ui.json +19 -4
- package/components/table/table.class.js +163 -12
- package/components/table/table.d.ts +9 -3
- package/components/table/table.yaml +109 -8
- package/components/table-footer/table-footer.a2ui.json +150 -0
- package/components/table-footer/table-footer.class.js +391 -0
- package/components/table-footer/table-footer.css +64 -0
- package/components/table-footer/table-footer.d.ts +39 -0
- package/components/table-footer/table-footer.examples.md +46 -0
- package/components/table-footer/table-footer.js +17 -0
- package/components/table-footer/table-footer.yaml +219 -0
- package/components/table-toolbar/table-toolbar.yaml +17 -6
- package/custom-elements.json +138 -4
- package/dist/theme-provider.min.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +87 -87
- package/dist/web-components.sheet.js +1 -1
- package/package.json +1 -1
- package/patterns/chart-in-card/chart-in-card.examples.html +36 -9
- package/patterns/new-enrollments/new-enrollments.examples.html +140 -0
- package/patterns/new-enrollments/new-enrollments.html +54 -0
- package/patterns/table-in-card/table-in-card.examples.html +168 -0
- package/patterns/table-in-card/table-in-card.examples.js +139 -0
- package/patterns/table-in-card/table-in-card.html +86 -0
- package/styles/components.css +1 -0
|
@@ -26,7 +26,21 @@
|
|
|
26
26
|
* table-ui has no local `density` prop (ADR-0054) — it converges onto the
|
|
27
27
|
* ambient global [density="compact"|"spacious"] attribute; --table-py/-px
|
|
28
28
|
* already derive from --a-space-* steps, which --a-density scales.
|
|
29
|
-
* paginate — rows per page (0 = no pagination)
|
|
29
|
+
* paginate — rows per page (0 = no pagination); purely presentational
|
|
30
|
+
* (page-size only) when [range-total] is present — gh#1754/ADR-0082
|
|
31
|
+
* range-total — total row count across ALL server pages (Number, reflected,
|
|
32
|
+
* presence-gated via hasAttribute — the attribute's PRESENCE, not
|
|
33
|
+
* its value, is the server-mode switch, gh#1754/ADR-0082). Absent
|
|
34
|
+
* → client mode, today's behavior exactly. Present + [paginate] > 0
|
|
35
|
+
* → server mode: no local slicing (`.data` IS the current page and
|
|
36
|
+
* renders whole, after local search/sort/filter), page count =
|
|
37
|
+
* max(1, ceil(range-total / paginate)), and the internal page-reset
|
|
38
|
+
* sites (`data` set, setFilter, clearFilters) are suppressed so a
|
|
39
|
+
* fetch write-back never fights the pager back to page 0. Explicit
|
|
40
|
+
* range-total="0" is server-confirmed empty (pager hidden), never
|
|
41
|
+
* conflated with absent. With [paginate] absent/0, [range-total] is
|
|
42
|
+
* inert for this table's own rendering but stays readable by a
|
|
43
|
+
* bound table-footer-ui for its count-only label.
|
|
30
44
|
* loading — show loading overlay
|
|
31
45
|
* search — global search filter string
|
|
32
46
|
*
|
|
@@ -61,6 +75,27 @@
|
|
|
61
75
|
* toolbar-filter-clear — { detail: {} } → this.clearFilters()
|
|
62
76
|
* toolbar-columns-set — { detail: { columns } } → this.columns =
|
|
63
77
|
* toolbar-paginate — { detail: { pageSize } } → this.paginate =
|
|
78
|
+
* footer-page — { detail: { page } }, 1-based → gh#1807/ADR-0080,
|
|
79
|
+
* refined 0.2.0/ADR-0082. Dispatched directly at this
|
|
80
|
+
* element (table-footer-ui, or any other consumer).
|
|
81
|
+
* Applies whenever [paginate] > 0 — client mode and
|
|
82
|
+
* table-authoritative server mode ([range-total]
|
|
83
|
+
* present, REQ-D-003) alike, since #pageCount already
|
|
84
|
+
* knows server math; clamped to [1, pageCount]; a
|
|
85
|
+
* non-numeric/NaN detail.page is a documented no-op.
|
|
86
|
+
* At [paginate="0"] the command stays a no-op in
|
|
87
|
+
* either mode — with no page size there is no page
|
|
88
|
+
* range to move within. On a valid page, applies
|
|
89
|
+
* exactly like an internal pager click: updates the
|
|
90
|
+
* page, re-renders, and fires the existing `page`
|
|
91
|
+
* event (the fetch trigger in server mode).
|
|
92
|
+
*
|
|
93
|
+
* [no-pager] — boolean, reflected (gh#1807/ADR-0080). Hides the internal
|
|
94
|
+
* pagination bar while [paginate] slicing, page state, the `page` event, and
|
|
95
|
+
* the `footer-page` listener all stay intact — the anti-doubled-pager
|
|
96
|
+
* mechanism for a table-footer-ui composition, client- or server-mode alike
|
|
97
|
+
* (gh#1754/ADR-0082). Explicit author intent, never an auto-suppression
|
|
98
|
+
* side-effect of binding a footer.
|
|
64
99
|
*/
|
|
65
100
|
|
|
66
101
|
import { UIElement } from '../../core/element.js';
|
|
@@ -243,6 +278,18 @@ export class UITable extends UIElement {
|
|
|
243
278
|
wrap: { type: Boolean, default: false, reflect: true },
|
|
244
279
|
raw: { type: Boolean, default: false, reflect: true },
|
|
245
280
|
paginate: { type: Number, default: 0, reflect: true },
|
|
281
|
+
// gh#1807/ADR-0080 — opt-out for the internal pagination bar. Additive:
|
|
282
|
+
// [paginate] slicing, page state, the `page` event, and the
|
|
283
|
+
// `footer-page` listener are all unaffected; only the internally
|
|
284
|
+
// stamped [data-footer] pagination-ui is suppressed. Explicit intent,
|
|
285
|
+
// for a client-mode table-footer-ui composition to avoid a doubled
|
|
286
|
+
// pager (REQ-W-005).
|
|
287
|
+
noPager: { type: Boolean, default: false, reflect: true, attribute: 'no-pager' },
|
|
288
|
+
// gh#1754/ADR-0082 — the server-total data contract. Presence-gated
|
|
289
|
+
// (#serverMode reads hasAttribute, never this coerced value): total row
|
|
290
|
+
// count across all server pages. See the class-header doc comment above
|
|
291
|
+
// and REQ-D-003..006 for the full server-mode contract.
|
|
292
|
+
rangeTotal: { type: Number, default: 0, reflect: true, attribute: 'range-total' },
|
|
246
293
|
loading: { type: Boolean, default: false, reflect: true },
|
|
247
294
|
search: { type: String, default: '', reflect: true },
|
|
248
295
|
// adiav2 zero-overrides purge (gh#1680) deleted an app-side [data-clickable]
|
|
@@ -271,6 +318,23 @@ export class UITable extends UIElement {
|
|
|
271
318
|
#openFilter = null; // column key of open filter dropdown
|
|
272
319
|
#filterFocusRaf = null;
|
|
273
320
|
|
|
321
|
+
// gh#1754/ADR-0082 — the mode switch is the [range-total] attribute's
|
|
322
|
+
// PRESENCE, never its coerced value (mirrors table-footer-ui's own
|
|
323
|
+
// REQ-S-001/002 hasAttribute discipline). One predicate for both the
|
|
324
|
+
// page-count/no-slice/visibility branches (step 2) and the reset-guard
|
|
325
|
+
// sites (step 3) — deliberately not narrowed by `paginate > 0` (see the
|
|
326
|
+
// reset-suppression call sites for why that widened scope is safe).
|
|
327
|
+
get #serverMode() { return this.hasAttribute('range-total'); }
|
|
328
|
+
|
|
329
|
+
// gh#1754/ADR-0082 REQ-D-003 (CodeRabbit, PR #1828) — a raw
|
|
330
|
+
// `Number(x) || 0` accepts negative and non-finite values verbatim (both
|
|
331
|
+
// are truthy), which can drive #pageCount/the footer's own range text
|
|
332
|
+
// negative or infinite. Clamps to a finite, non-negative integer.
|
|
333
|
+
#safeRangeTotal() {
|
|
334
|
+
const n = Number(this.rangeTotal);
|
|
335
|
+
return Number.isFinite(n) && n > 0 ? Math.trunc(n) : 0;
|
|
336
|
+
}
|
|
337
|
+
|
|
274
338
|
// ── Public API: columns ──
|
|
275
339
|
|
|
276
340
|
set columns(arr) {
|
|
@@ -285,7 +349,11 @@ export class UITable extends UIElement {
|
|
|
285
349
|
set data(arr) {
|
|
286
350
|
this.#data = Array.isArray(arr) ? arr : [];
|
|
287
351
|
this.#selected.clear();
|
|
288
|
-
|
|
352
|
+
// gh#1754/ADR-0082 REQ-D-004 — in server mode a `.data` set is the
|
|
353
|
+
// consumer's fetch write-back for the CURRENT page; resetting to page 0
|
|
354
|
+
// here would fight the pager back to the start on every fetch. Selection
|
|
355
|
+
// still clears unconditionally (rows changed under it either way).
|
|
356
|
+
if (!this.#serverMode) this.#page = 0;
|
|
289
357
|
this.#requestRender();
|
|
290
358
|
}
|
|
291
359
|
|
|
@@ -349,7 +417,10 @@ export class UITable extends UIElement {
|
|
|
349
417
|
} else {
|
|
350
418
|
this.#filters.set(key, { op, value });
|
|
351
419
|
}
|
|
352
|
-
|
|
420
|
+
// gh#1754/ADR-0082 REQ-D-004 — server mode: page state moves only via
|
|
421
|
+
// pager interaction, the `footer-page` command, or setState(); a filter
|
|
422
|
+
// change never resets it (the consumer's fetch loop owns page moves).
|
|
423
|
+
if (!this.#serverMode) this.#page = 0;
|
|
353
424
|
this.#requestRender();
|
|
354
425
|
this.dispatchEvent(new CustomEvent('filter-change', {
|
|
355
426
|
detail: { filters: Object.fromEntries(this.#filters) },
|
|
@@ -360,7 +431,7 @@ export class UITable extends UIElement {
|
|
|
360
431
|
clearFilters() {
|
|
361
432
|
this.#filters.clear();
|
|
362
433
|
this.#openFilter = null;
|
|
363
|
-
this.#page = 0;
|
|
434
|
+
if (!this.#serverMode) this.#page = 0; // gh#1754/ADR-0082 REQ-D-004 — same suppression as setFilter above.
|
|
364
435
|
this.#requestRender();
|
|
365
436
|
this.dispatchEvent(new CustomEvent('filter-change', {
|
|
366
437
|
detail: { filters: {} },
|
|
@@ -416,6 +487,42 @@ export class UITable extends UIElement {
|
|
|
416
487
|
this.paginate = Number(e.detail?.pageSize) || 0;
|
|
417
488
|
};
|
|
418
489
|
|
|
490
|
+
// gh#1807/ADR-0080, refined 0.2.0/ADR-0082 — `footer-page` is the
|
|
491
|
+
// footer→table page-navigation command (REQ-W-002), sender-prefixed like
|
|
492
|
+
// the five `toolbar-*` commands above but from a second sender
|
|
493
|
+
// (table-footer-ui). Applies whenever [paginate] > 0 — client mode AND
|
|
494
|
+
// table-authoritative server mode ([range-total] present, REQ-D-003)
|
|
495
|
+
// alike, since #pageCount already knows server math (step 2 above): the
|
|
496
|
+
// clamp below reads the right ceiling in either mode with no extra
|
|
497
|
+
// branching needed here. At [paginate="0"] the command stays a documented
|
|
498
|
+
// no-op in either mode — with no page size there is no page range to move
|
|
499
|
+
// within. Clamps to the valid page range and never throws (AC-004/AC-018);
|
|
500
|
+
// a non-numeric/NaN detail.page is silently ignored (no page change, no
|
|
501
|
+
// `page` notification).
|
|
502
|
+
#onFooterPage = (e) => {
|
|
503
|
+
if (e.target !== this) return;
|
|
504
|
+
if (!(this.paginate > 0)) return; // paginate=0: documented no-op, either mode
|
|
505
|
+
const n = Number(e.detail?.page);
|
|
506
|
+
if (!Number.isFinite(n)) return;
|
|
507
|
+
const clamped = Math.max(1, Math.min(Math.trunc(n), this.#pageCount));
|
|
508
|
+
this.#page = clamped - 1; // this.#page is 0-based internally
|
|
509
|
+
this.render();
|
|
510
|
+
this.dispatchEvent(new CustomEvent('page', {
|
|
511
|
+
bubbles: true,
|
|
512
|
+
detail: { page: this.#page },
|
|
513
|
+
}));
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
// ── Public API: filteredCount ──
|
|
517
|
+
// gh#1807/ADR-0080, REQ-W-006 — read-only. The row count AFTER search +
|
|
518
|
+
// column filters apply but BEFORE pagination slices it — exactly the
|
|
519
|
+
// number table-footer-ui's client-mode derivation needs for its
|
|
520
|
+
// range-total (a raw `.data.length` read, the toolbar's own `count`
|
|
521
|
+
// fallback precedent, would double-count a filtered-out row). Undocumented
|
|
522
|
+
// in table.yaml by design, matching `.selected`/`.sortState`/`.filters` —
|
|
523
|
+
// a plain read-only JS getter, not a reflected attribute.
|
|
524
|
+
get filteredCount() { return this.#getProcessedIndices().length; }
|
|
525
|
+
|
|
419
526
|
// ── Public API: expansion ──
|
|
420
527
|
|
|
421
528
|
toggleExpand(index) {
|
|
@@ -568,6 +675,9 @@ export class UITable extends UIElement {
|
|
|
568
675
|
this.addEventListener('toolbar-filter-clear', this.#onToolbarFilterClear);
|
|
569
676
|
this.addEventListener('toolbar-columns-set', this.#onToolbarColumnsSet);
|
|
570
677
|
this.addEventListener('toolbar-paginate', this.#onToolbarPaginate);
|
|
678
|
+
// gh#1807/ADR-0080 — a second sender-prefixed command, alongside the
|
|
679
|
+
// five toolbar-* listeners above (same symmetric-lifecycle rule).
|
|
680
|
+
this.addEventListener('footer-page', this.#onFooterPage);
|
|
571
681
|
}
|
|
572
682
|
}
|
|
573
683
|
|
|
@@ -580,6 +690,7 @@ export class UITable extends UIElement {
|
|
|
580
690
|
this.removeEventListener('toolbar-filter-clear', this.#onToolbarFilterClear);
|
|
581
691
|
this.removeEventListener('toolbar-columns-set', this.#onToolbarColumnsSet);
|
|
582
692
|
this.removeEventListener('toolbar-paginate', this.#onToolbarPaginate);
|
|
693
|
+
this.removeEventListener('footer-page', this.#onFooterPage);
|
|
583
694
|
this.#bound = false;
|
|
584
695
|
this.#cleanupResize();
|
|
585
696
|
if (this.#renderRaf) {
|
|
@@ -592,6 +703,21 @@ export class UITable extends UIElement {
|
|
|
592
703
|
}
|
|
593
704
|
}
|
|
594
705
|
|
|
706
|
+
// gh#1754/ADR-0082 — ported from table-footer.class.js's own
|
|
707
|
+
// attributeChangedCallback gotcha (its rangeTotal, same default-0 shape).
|
|
708
|
+
// [range-total]'s default is already 0 (Number), so an absent → "0"
|
|
709
|
+
// transition parses to the SAME coerced value; the base class property
|
|
710
|
+
// setter's Object.is short-circuit (element.js installProps) swallows the
|
|
711
|
+
// signal write, and the reactive render effect never re-runs on its own.
|
|
712
|
+
// This is a presence concern (#serverMode reads hasAttribute, not the
|
|
713
|
+
// coerced value), not a value one. Batched via #requestRender — never
|
|
714
|
+
// render() directly — honoring the R7 render-clock discipline (no edits to
|
|
715
|
+
// #requestRender/#renderRaf themselves).
|
|
716
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
717
|
+
super.attributeChangedCallback(name, oldVal, newVal);
|
|
718
|
+
if (name === 'range-total') this.#requestRender();
|
|
719
|
+
}
|
|
720
|
+
|
|
595
721
|
// ── <col-def> Parsing ──────────────────────────────────────────────────────
|
|
596
722
|
|
|
597
723
|
#parseColDefs() {
|
|
@@ -787,9 +913,15 @@ export class UITable extends UIElement {
|
|
|
787
913
|
}
|
|
788
914
|
|
|
789
915
|
/**
|
|
790
|
-
* Paginate a set of indices.
|
|
916
|
+
* Paginate a set of indices. gh#1754/ADR-0082 REQ-D-003 — server mode:
|
|
917
|
+
* `.data` IS the current page already (the consumer sliced it server-side),
|
|
918
|
+
* so no local slicing runs; [paginate] supplies only the page-size for
|
|
919
|
+
* pager math. `indices` here has already had local search/sort/filter
|
|
920
|
+
* applied by #getProcessedIndices — server mode still renders that whole
|
|
921
|
+
* (unsliced) result.
|
|
791
922
|
*/
|
|
792
923
|
#getPageSlice(indices) {
|
|
924
|
+
if (this.#serverMode) return indices;
|
|
793
925
|
if (!this.paginate || this.paginate <= 0) return indices;
|
|
794
926
|
const start = this.#page * this.paginate;
|
|
795
927
|
return indices.slice(start, start + this.paginate);
|
|
@@ -797,6 +929,11 @@ export class UITable extends UIElement {
|
|
|
797
929
|
|
|
798
930
|
get #pageCount() {
|
|
799
931
|
if (!this.paginate || this.paginate <= 0) return 1;
|
|
932
|
+
// gh#1754/ADR-0082 REQ-D-003 — server mode: page count is server-total-
|
|
933
|
+
// derived, not the loaded page's own length (the exact dual-math drift
|
|
934
|
+
// gh#1754's evidence quoted — this is now the ONE calc site;
|
|
935
|
+
// #renderPagination reads this getter instead of recomputing).
|
|
936
|
+
if (this.#serverMode) return Math.max(1, Math.ceil(this.#safeRangeTotal() / this.paginate));
|
|
800
937
|
// pageCount should reflect filtered data, not raw data
|
|
801
938
|
const filteredCount = this.#getProcessedIndices().length;
|
|
802
939
|
return Math.max(1, Math.ceil(filteredCount / this.paginate));
|
|
@@ -910,7 +1047,15 @@ export class UITable extends UIElement {
|
|
|
910
1047
|
|
|
911
1048
|
// ── Pagination footer ──
|
|
912
1049
|
|
|
913
|
-
|
|
1050
|
+
// gh#1807/ADR-0080 REQ-W-005 — [no-pager] hides only the internally
|
|
1051
|
+
// stamped bar; slicing/page-state/events are untouched (they don't
|
|
1052
|
+
// route through this flag at all).
|
|
1053
|
+
// gh#1754/ADR-0082 REQ-D-005 — server mode drops the client-mode
|
|
1054
|
+
// `data.length > 0` term: an in-flight fetch (momentarily empty `.data`)
|
|
1055
|
+
// must not flicker the pager away, so visibility gates on `range-total`
|
|
1056
|
+
// instead.
|
|
1057
|
+
const showPagination = this.paginate > 0 && !this.noPager
|
|
1058
|
+
&& (this.#serverMode ? this.#safeRangeTotal() > 0 : this.#data.length > 0);
|
|
914
1059
|
let footer = this.querySelector(':scope > [data-footer]');
|
|
915
1060
|
|
|
916
1061
|
if (showPagination) {
|
|
@@ -919,7 +1064,7 @@ export class UITable extends UIElement {
|
|
|
919
1064
|
footer.setAttribute('data-footer', '');
|
|
920
1065
|
this.appendChild(footer);
|
|
921
1066
|
}
|
|
922
|
-
this.#renderPagination(footer
|
|
1067
|
+
this.#renderPagination(footer);
|
|
923
1068
|
} else if (footer) {
|
|
924
1069
|
footer.remove();
|
|
925
1070
|
}
|
|
@@ -1320,7 +1465,7 @@ export class UITable extends UIElement {
|
|
|
1320
1465
|
|
|
1321
1466
|
// ── Pagination ─────────────────────────────────────────────────────────────
|
|
1322
1467
|
|
|
1323
|
-
#renderPagination(footer
|
|
1468
|
+
#renderPagination(footer) {
|
|
1324
1469
|
let pag = footer.querySelector('pagination-ui');
|
|
1325
1470
|
if (!pag) {
|
|
1326
1471
|
footer.innerHTML = '';
|
|
@@ -1335,10 +1480,16 @@ export class UITable extends UIElement {
|
|
|
1335
1480
|
});
|
|
1336
1481
|
footer.appendChild(pag);
|
|
1337
1482
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1483
|
+
// gh#1754/ADR-0082 — #pageCount is now the single calc site (client AND
|
|
1484
|
+
// server math); the duplicated `ceil(filteredTotal / paginate)` this
|
|
1485
|
+
// function used to recompute is gone — that dual-math drift is exactly
|
|
1486
|
+
// gh#1754's evidence. Clamp only the RENDERED page attribute (a display
|
|
1487
|
+
// concern, e.g. the server total shrank below the current page) — never
|
|
1488
|
+
// mutate `#page` or dispatch `page` from render (REQ-D-005: a render must
|
|
1489
|
+
// never self-trigger a fetch).
|
|
1490
|
+
const pageCount = this.#pageCount;
|
|
1491
|
+
const p = Math.min(this.#page, pageCount - 1);
|
|
1492
|
+
pag.setAttribute('page', String(p + 1));
|
|
1342
1493
|
pag.setAttribute('total', String(pageCount));
|
|
1343
1494
|
}
|
|
1344
1495
|
|
|
@@ -31,7 +31,7 @@ export interface TableFilterChangeEventDetail {
|
|
|
31
31
|
|
|
32
32
|
export type TableFilterChangeEvent = CustomEvent<TableFilterChangeEventDetail>;
|
|
33
33
|
export interface TablePageEventDetail {
|
|
34
|
-
/** New active page index (1-based). */
|
|
34
|
+
/** New active page index (0-based — gh#1808; the `footer-page` command and the `page` attribute on <table-footer-ui> are 1-based, this event's own detail is not). */
|
|
35
35
|
page: number;
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -94,15 +94,21 @@ export class UITable extends UIElement {
|
|
|
94
94
|
data: string;
|
|
95
95
|
/** Enable row expansion */
|
|
96
96
|
expandable: boolean;
|
|
97
|
+
/** Read-only. The row count AFTER search + column filters apply but BEFORE pagination slices it (gh#1807, ADR-0080, REQ-W-006) — a plain JS getter, no setter, never a reflected attribute. table-footer-ui's client-mode range-total derivation reads this directly; a raw `.data.length` read (the toolbar's own `count` fallback precedent) would double-count a filtered-out row. In server mode ([range-total] set, gh#1754, ADR-0082), filteredCount stays page-scoped — the loaded page's rows after local filters, NOT the server total across all pages; [range-total] is the server total, filteredCount never is (REQ-D-006). */
|
|
98
|
+
readonly filteredCount: number;
|
|
97
99
|
/** Drop the table's outer 1px perimeter and nothing else (gh#511) — row dividers are untouched (the perimeter is split onto its own --table-perimeter token, defaulting to --table-border). For card-composed tables: the card owns the frame, so the table's square perimeter otherwise renders a doubled edge (flush bleed) or a stray inner box (with content above). Standalone tables keep their chrome by default. Theming path without the attribute: set --table-perimeter to transparent per instance. Note: `<card-ui><section bleed>` already drops a direct-child table-ui's chrome automatically (card.css, gh#796) — `frameless`/`raw` on the instance still applies and is honored, but is no longer required just to avoid the doubled-edge look in that composition. */
|
|
98
100
|
frameless: boolean;
|
|
99
101
|
/** Renders N ghost skeleton rows in place of the body data (count derived from `paginate` if set, else 5). Header + columns stay intact so the table layout is preserved while data fetches. Sets aria-busy="true" on the host. Data updates are deferred until loading is set back to false. */
|
|
100
102
|
loading: boolean;
|
|
101
|
-
/**
|
|
103
|
+
/** Hide the internal pagination bar while leaving [paginate] slicing, page state, the `page` event, and the `footer-page` command listener all intact (gh#1807, ADR-0080). The anti-doubled-pager mechanism for a table-footer-ui composition, client- or server-mode alike (gh#1754, ADR-0082): without it, a bound footer's own composed pager and the table's own internal one would both render for any non-empty paginated table. Explicit author intent — never suppressed automatically just because a footer happens to be bound. */
|
|
104
|
+
noPager: boolean;
|
|
105
|
+
/** Rows per page. 0 = show all rows without pagination. When > 0, renders the internal pagination bar below the table — UNLESS [no-pager] is also set (gh#1807, ADR-0080), which keeps [paginate]'s slicing/page-state/`page`-event/`footer-page`-listener behavior but suppresses only the bar itself (the anti-doubled-pager path for a table-footer-ui composition). When [range-total] is also set (gh#1754, ADR-0082), [paginate] becomes purely presentational — it supplies only the page-size for pager math; no local slicing runs. */
|
|
102
106
|
paginate: number;
|
|
107
|
+
/** Total row count across ALL server pages (gh#1754, ADR-0082) — the table-authoritative server-mode data contract. Presence-gated: the attribute's PRESENCE, not its value, is the mode switch (checked via hasAttribute, never the coerced value alone — the same discipline table-footer-ui's own [range-total] ships). Absent (the default) means client mode: today's behavior exactly, [paginate] slices `.data` as always. Present with [paginate] > 0 means server mode: no local slicing (`.data` IS the current page and renders whole, after local search/sort/filter), the internal pager's page count becomes `max(1, ceil(range-total / paginate))` (one calc site, consolidated), and the internal page-reset sites (`data` set, `setFilter`, `clearFilters`) are suppressed so a fetch write-back never fights the pager back to page 0 — page state then moves only via pager interaction, the `footer-page` command, or `setState()`. The existing `page` event (0-based, unchanged) becomes the fetch trigger: the consumer listens for it, fetches that server page, and writes `.data` back. Explicit `range-total="0"` is server-confirmed empty (pager hidden), never conflated with absent. With [paginate] absent/0, [range-total] is inert for this table's own rendering but stays readable by a bound table-footer-ui (REQ-W-006 branch 2) for its count-only label — see the footer-authoritative shape below, which remains lawful and is unaffected by this attribute. Named identically to table-toolbar-ui's and table-footer-ui's own [range-total] (rows, never `pagination-ui[total]`'s pages — the ADR-0063 B5 collision rule); a third instance of one name for one concept. */
|
|
108
|
+
rangeTotal: number;
|
|
103
109
|
/** Visual-only passthrough — applies `<table-ui>`'s chrome reset (background / border / border-radius all transparent) AND short-circuits the data lifecycle entirely. The consumer owns the body shape: no header injection, no row reconciliation from `.data`, no empty-state / loading overlays, no aggregation or pagination footers. Use raw when embedding `<table-ui>` inside surfaces that supply their own chrome (e.g. `<card-ui><section bleed>`), or when wrapping a consumer-authored native `<table>` for design-token styling without the framework's data semantics. Note: a `<table-ui>` placed directly inside `<card-ui><section bleed>` drops the table's visual chrome automatically (card.css, gh#796) even without `raw` — `raw` is still required to also short-circuit the data lifecycle. Pre-v0.6.33 (FB-53 §2) `raw` was visual-only and the data lifecycle still ran — wrapping a `.data`-unset native table produced a phantom "No data" overlay. v0.6.33+ matches the documented contract. */
|
|
104
110
|
raw: boolean;
|
|
105
|
-
/** Global search/filter string. Filters visible rows across all columns using case-insensitive substring matching.
|
|
111
|
+
/** Global search/filter string. Filters visible rows across all columns using case-insensitive substring matching. Does NOT reset the current page (verified against source at the gh#1754/ADR-0082 build — unlike setFilter()/clearFilters(), no internal page reset ever ran for a search change; this description previously claimed "resets to page 1 on change," which the source never did). Aligning the doc to observed behavior here, not a behavior change — a page reset on search, if wanted, is a separate client-mode ticket. */
|
|
106
112
|
search: string;
|
|
107
113
|
/** Show checkbox column for row selection. Select-all checkbox in header. Shift+click for range select. */
|
|
108
114
|
selectable: boolean;
|
|
@@ -50,10 +50,71 @@ props:
|
|
|
50
50
|
default: false
|
|
51
51
|
reflect: true
|
|
52
52
|
paginate:
|
|
53
|
-
description: Rows per page. 0 = show all rows without pagination. When > 0, renders
|
|
54
|
-
below the table
|
|
53
|
+
description: Rows per page. 0 = show all rows without pagination. When > 0, renders the internal
|
|
54
|
+
pagination bar below the table — UNLESS [no-pager] is also set (gh#1807, ADR-0080), which keeps
|
|
55
|
+
[paginate]'s slicing/page-state/`page`-event/`footer-page`-listener behavior but suppresses only
|
|
56
|
+
the bar itself (the anti-doubled-pager path for a table-footer-ui composition). When [range-total]
|
|
57
|
+
is also set (gh#1754, ADR-0082), [paginate] becomes purely presentational — it supplies only the
|
|
58
|
+
page-size for pager math; no local slicing runs.
|
|
55
59
|
type: number
|
|
56
60
|
default: 0
|
|
61
|
+
no-pager:
|
|
62
|
+
description: >-
|
|
63
|
+
Hide the internal pagination bar while leaving [paginate] slicing, page
|
|
64
|
+
state, the `page` event, and the `footer-page` command listener all
|
|
65
|
+
intact (gh#1807, ADR-0080). The anti-doubled-pager mechanism for a
|
|
66
|
+
table-footer-ui composition, client- or server-mode alike (gh#1754,
|
|
67
|
+
ADR-0082): without it, a bound footer's own composed pager and the
|
|
68
|
+
table's own internal one would both render for any non-empty paginated
|
|
69
|
+
table. Explicit author intent — never suppressed automatically just
|
|
70
|
+
because a footer happens to be bound.
|
|
71
|
+
type: boolean
|
|
72
|
+
default: false
|
|
73
|
+
reflect: true
|
|
74
|
+
range-total:
|
|
75
|
+
description: >-
|
|
76
|
+
Total row count across ALL server pages (gh#1754, ADR-0082) — the
|
|
77
|
+
table-authoritative server-mode data contract. Presence-gated: the
|
|
78
|
+
attribute's PRESENCE, not its value, is the mode switch (checked via
|
|
79
|
+
hasAttribute, never the coerced value alone — the same discipline
|
|
80
|
+
table-footer-ui's own [range-total] ships). Absent (the default) means
|
|
81
|
+
client mode: today's behavior exactly, [paginate] slices `.data` as
|
|
82
|
+
always. Present with [paginate] > 0 means server mode: no local
|
|
83
|
+
slicing (`.data` IS the current page and renders whole, after local
|
|
84
|
+
search/sort/filter), the internal pager's page count becomes
|
|
85
|
+
`max(1, ceil(range-total / paginate))` (one calc site, consolidated),
|
|
86
|
+
and the internal page-reset sites (`data` set, `setFilter`,
|
|
87
|
+
`clearFilters`) are suppressed so a fetch write-back never fights the
|
|
88
|
+
pager back to page 0 — page state then moves only via pager
|
|
89
|
+
interaction, the `footer-page` command, or `setState()`. The existing
|
|
90
|
+
`page` event (0-based, unchanged) becomes the fetch trigger: the
|
|
91
|
+
consumer listens for it, fetches that server page, and writes `.data`
|
|
92
|
+
back. Explicit `range-total="0"` is server-confirmed empty (pager
|
|
93
|
+
hidden), never conflated with absent. With [paginate] absent/0,
|
|
94
|
+
[range-total] is inert for this table's own rendering but stays
|
|
95
|
+
readable by a bound table-footer-ui (REQ-W-006 branch 2) for its
|
|
96
|
+
count-only label — see the footer-authoritative shape below, which
|
|
97
|
+
remains lawful and is unaffected by this attribute. Named identically
|
|
98
|
+
to table-toolbar-ui's and table-footer-ui's own [range-total]
|
|
99
|
+
(rows, never `pagination-ui[total]`'s pages — the ADR-0063 B5
|
|
100
|
+
collision rule); a third instance of one name for one concept.
|
|
101
|
+
type: number
|
|
102
|
+
default: 0
|
|
103
|
+
reflect: true
|
|
104
|
+
filteredCount:
|
|
105
|
+
description: >-
|
|
106
|
+
Read-only. The row count AFTER search + column filters apply but
|
|
107
|
+
BEFORE pagination slices it (gh#1807, ADR-0080, REQ-W-006) — a plain
|
|
108
|
+
JS getter, no setter, never a reflected attribute. table-footer-ui's
|
|
109
|
+
client-mode range-total derivation reads this directly; a raw
|
|
110
|
+
`.data.length` read (the toolbar's own `count` fallback precedent)
|
|
111
|
+
would double-count a filtered-out row. In server mode ([range-total]
|
|
112
|
+
set, gh#1754, ADR-0082), filteredCount stays page-scoped — the loaded
|
|
113
|
+
page's rows after local filters, NOT the server total across all
|
|
114
|
+
pages; [range-total] is the server total, filteredCount never is
|
|
115
|
+
(REQ-D-006).
|
|
116
|
+
type: number
|
|
117
|
+
readonly: true # getter-only, no setter — never A2UI-bindable (not `dynamic:`)
|
|
57
118
|
raw:
|
|
58
119
|
description: >-
|
|
59
120
|
Visual-only passthrough — applies `<table-ui>`'s chrome reset
|
|
@@ -76,8 +137,13 @@ props:
|
|
|
76
137
|
default: false
|
|
77
138
|
reflect: true
|
|
78
139
|
search:
|
|
79
|
-
description:
|
|
80
|
-
|
|
140
|
+
description: >-
|
|
141
|
+
Global search/filter string. Filters visible rows across all columns using
|
|
142
|
+
case-insensitive substring matching. Does NOT reset the current page (verified against
|
|
143
|
+
source at the gh#1754/ADR-0082 build — unlike setFilter()/clearFilters(), no internal page
|
|
144
|
+
reset ever ran for a search change; this description previously claimed "resets to page 1
|
|
145
|
+
on change," which the source never did). Aligning the doc to observed behavior here, not a
|
|
146
|
+
behavior change — a page reset on search, if wanted, is a separate client-mode ticket.
|
|
81
147
|
type: string
|
|
82
148
|
default: ""
|
|
83
149
|
selectable:
|
|
@@ -180,11 +246,21 @@ events:
|
|
|
180
246
|
type: object
|
|
181
247
|
description: "Map of `{ [columnKey]: filterValue }` reflecting active filters."
|
|
182
248
|
page:
|
|
183
|
-
description:
|
|
249
|
+
description: >-
|
|
250
|
+
Fired when the table's own internal page state changes — an internal
|
|
251
|
+
pager click, or a `footer-page` command applied (REQ-W-002). This is a
|
|
252
|
+
RESYNC notification a bound `<table-footer-ui>` listens to for its own
|
|
253
|
+
`page` attribute (REQ-W-004) — it is NOT the public server-mode fetch
|
|
254
|
+
trigger a consumer should listen to; use `<table-footer-ui>`'s own
|
|
255
|
+
`page-change` event for that (1-based, gh#1754/ADR-0082 REQ-W-003).
|
|
256
|
+
Listening to both risks a duplicate fetch or an index-base mismatch.
|
|
184
257
|
detail:
|
|
185
258
|
page:
|
|
186
259
|
type: number
|
|
187
|
-
description:
|
|
260
|
+
description: >-
|
|
261
|
+
New active page index (0-based — gh#1808; the `footer-page`
|
|
262
|
+
command and the `page` attribute on <table-footer-ui> are
|
|
263
|
+
1-based, this event's own detail is not).
|
|
188
264
|
resize:
|
|
189
265
|
description: Fired when a column is resized via drag.
|
|
190
266
|
detail:
|
|
@@ -308,6 +384,19 @@ a2ui:
|
|
|
308
384
|
toolbar-columns-set/toolbar-paginate on itself). Any consumer, not
|
|
309
385
|
only table-toolbar-ui, may dispatch these events directly at a
|
|
310
386
|
table-ui instance.
|
|
387
|
+
- >-
|
|
388
|
+
Pair with <table-footer-ui for="<table-id>"> for the pager +
|
|
389
|
+
"Showing X-Y of N" range label (gh#1807, ADR-0080; gh#1754, ADR-0082)
|
|
390
|
+
— table-ui listens for its `footer-page` command (detail {page},
|
|
391
|
+
1-based) on itself, applied whenever [paginate] > 0 — client mode
|
|
392
|
+
AND table-authoritative server mode ([range-total] set) alike —
|
|
393
|
+
clamped to the valid page range (server-derived when [range-total]
|
|
394
|
+
is set). Only at [paginate="0"] does the table treat it as a
|
|
395
|
+
documented no-op, in either mode. Set [no-pager] on the table when
|
|
396
|
+
a composition also binds a footer (client- or server-mode), or the
|
|
397
|
+
internal pagination bar and the footer's composed one both render —
|
|
398
|
+
[no-pager] leaves slicing/page-state/the `page` event untouched, it
|
|
399
|
+
only hides the internal bar.
|
|
311
400
|
- >-
|
|
312
401
|
Cells truncate single-line by default (v0.6.21 §403
|
|
313
402
|
truncate-default). Opt out per-table with [wrap] for whole-table
|
|
@@ -334,8 +423,20 @@ a2ui:
|
|
|
334
423
|
rendered rows and add a pagination bar. [virtual] is NOT a
|
|
335
424
|
recognized prop and is silently ignored — there is no DOM-level
|
|
336
425
|
virtual scrolling in table-ui. [paginate] is the supported
|
|
337
|
-
performance mechanism.
|
|
338
|
-
|
|
426
|
+
performance mechanism. For server-driven pagination (gh#1754,
|
|
427
|
+
ADR-0082), set [paginate="N"] (page size) + [range-total="M"]
|
|
428
|
+
(server total row count) together — [paginate] then becomes purely
|
|
429
|
+
presentational (no local slicing), `.data` holds exactly the
|
|
430
|
+
current server page. The table's own `page` event (0-based) is an
|
|
431
|
+
internal resync notification, not the fetch trigger — a bound
|
|
432
|
+
<table-footer-ui> listens to it to keep its own [page] in sync.
|
|
433
|
+
The PUBLIC fetch trigger is <table-footer-ui>'s own `page-change`
|
|
434
|
+
event (1-based): listen for it, fetch that server page, then write
|
|
435
|
+
the rows back to `.data` and the footer's own [page]. Listening to
|
|
436
|
+
the table's `page` event instead risks a duplicate fetch or an
|
|
437
|
+
index-base mismatch (0-based vs 1-based). [search]/[sort]/column
|
|
438
|
+
filters, when used alongside server paging, still operate on the
|
|
439
|
+
loaded page only — not a server-side query.
|
|
339
440
|
anti_patterns:
|
|
340
441
|
- wrong: '<table-ui virtual></table-ui>'
|
|
341
442
|
why: >-
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://adiaui.dev/a2ui/v0_9/components/TableFooter.json",
|
|
4
|
+
"title": "TableFooter",
|
|
5
|
+
"description": "Footer / companion bar for a sibling table-ui (gh#1807, ADR-0080) — a \"Showing X–Y of N\" range label paired with a composed pagination-ui. Derivation-model API: set `page` / `page-size` / `range-total` and the footer derives total pages and the range window itself, so it never drifts out of sync with its own pager. Wired to the target table via a [for] id-ref and CustomEvents only (ADR-0079/ADR-0080) — the footer never writes a property or calls a method on the bound table. Drop below (or inside a card-ui footer alongside) any table-ui to add the standard data-grid pager + range summary without re-implementing pagination-ui's ellipsis truncation, keyboard handling, or ARIA.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"allOf": [
|
|
8
|
+
{
|
|
9
|
+
"$ref": "common_types.json#/$defs/ComponentCommon"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"$ref": "common_types.json#/$defs/CatalogComponentCommon"
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"properties": {
|
|
16
|
+
"component": {
|
|
17
|
+
"const": "TableFooter"
|
|
18
|
+
},
|
|
19
|
+
"for": {
|
|
20
|
+
"description": "id-ref of the table-ui to control. Falls back to the first sibling table-ui within the same parent when omitted.",
|
|
21
|
+
"type": "string",
|
|
22
|
+
"default": ""
|
|
23
|
+
},
|
|
24
|
+
"page": {
|
|
25
|
+
"description": "Current page, 1-based. Explicit attributes always win over derivation (per-attribute, not all-or-nothing) — see page-size/range-total.",
|
|
26
|
+
"type": "number",
|
|
27
|
+
"default": 1
|
|
28
|
+
},
|
|
29
|
+
"page-size": {
|
|
30
|
+
"description": "Rows per page. Default 0 (unknown) is the ORDINARY default state, not an exotic edge case: with page-size absent/0 and range-total present, the range label renders in count-only form (\"128 items\") and the pager does not render — the derivation math (pages = range-total / page-size) is undefined without a page size. In a client-mode composition (the resolved target has [paginate] > 0) and this attribute is unset, the footer derives page-size from the target's own [paginate] value.",
|
|
31
|
+
"type": "number",
|
|
32
|
+
"default": 0
|
|
33
|
+
},
|
|
34
|
+
"range-total": {
|
|
35
|
+
"description": "Total ROWS across all pages. Absent (the default) means \"not yet known\" (loading) — never \"zero\"; both the range label and the pager stay hidden until this is set. Explicit range-total=\"0\" is the confirmed-empty state (pager hidden; the `empty` slot renders in the range label's position when supplied). Named identically to table-toolbar-ui's [range-total] and table-ui's own [range-total] (gh#1754, ADR-0082) and deliberately NOT `total` (pagination-ui's `total` is total PAGES — the ADR-0063 B5 collision rule). When this attribute is unset, the footer derives it from the resolved target via a two-branch ladder (REQ-W-006, amended 0.2.0/ADR-0082): (1) the target's own [range-total] attribute, when present — the table-authoritative SERVER mode (gh#1754 Shape 1's second lawful composition); the identity rule: the footer's range-total derives from the table's range-total, never the table's filteredCount, and this branch wins even when the target's [paginate] is also > 0; (2) otherwise, when the target has [paginate] > 0, CLIENT mode: the target's filtered row count (search + column filters applied, before pagination). Refreshes on the target's `page` / `filter-change` / `sort` events in either branch. Widened named staleness edge: a programmatic `.data` swap on the target — or a `range-total` update on the target without an accompanying page move — emits no event; either re-set this footer's own attributes after such a change, or accept staleness until the target's next event.",
|
|
36
|
+
"type": "number",
|
|
37
|
+
"default": 0
|
|
38
|
+
},
|
|
39
|
+
"siblings": {
|
|
40
|
+
"description": "Passed through to the composed pagination-ui's own [siblings] (page-number window size on each side of the current page).",
|
|
41
|
+
"type": "number",
|
|
42
|
+
"default": 1
|
|
43
|
+
},
|
|
44
|
+
"size": {
|
|
45
|
+
"description": "Passed through to the composed pagination-ui's own [size] (sm | md | lg, the universal size system).",
|
|
46
|
+
"type": "string",
|
|
47
|
+
"default": "md"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"required": [
|
|
51
|
+
"component"
|
|
52
|
+
],
|
|
53
|
+
"unevaluatedProperties": false,
|
|
54
|
+
"x-adiaui": {
|
|
55
|
+
"anti_patterns": [
|
|
56
|
+
{
|
|
57
|
+
"fix": "<table-footer-ui page=\"1\" page-size=\"10\" range-total=\"128\"></table-footer-ui>",
|
|
58
|
+
"why": "table-footer-ui is derivation-only (REQ-F-002) — there is no [range-start]/[range-end] attribute pair (that shape belongs to table-toolbar-ui, which has no page/page-size knowledge of its own). Setting [page] + [page-size] + [range-total] derives the range window instead; a permanent three-way drift hazard is exactly what the derivation model exists to avoid.",
|
|
59
|
+
"wrong": "<table-footer-ui range-start=\"1\" range-end=\"10\" range-total=\"128\"></table-footer-ui>"
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
"category": "agent",
|
|
63
|
+
"composes": [
|
|
64
|
+
"pagination-ui"
|
|
65
|
+
],
|
|
66
|
+
"events": {
|
|
67
|
+
"footer-page": {
|
|
68
|
+
"description": "gh#1807, ADR-0080 (events-only interaction contract, extending ADR-0079's sender-prefixed toolbar-* precedent to a second sender) — dispatched directly at the resolved [for] target on every pager interaction. Detail: { page } (1-based). table-ui listens for this on itself, applied only when [paginate] > 0 (clamped to the valid page range; a non-numeric/NaN detail.page is a no-op); at [paginate=\"0\"] the command is a documented no-op on the table. Additive: any consumer, not only table-footer-ui, may dispatch this at a table-ui."
|
|
69
|
+
},
|
|
70
|
+
"page-change": {
|
|
71
|
+
"description": "The footer's own consumer-facing notification — a distinct name from the inbound footer-page command (ADR-0079's command≠notification separation). Fires on every pager interaction, in both client- and server-mode. Detail: { page } (1-based). This is the server-mode fetch hook: a consumer listens for it, fetches the new page, then sets `table.data` and the footer's own `page` (and `range-total` if the server's total moved) — the footer never optimistically advances its own state in server-mode."
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"examples": [
|
|
75
|
+
{
|
|
76
|
+
"description": "Server-mode footer (gh#1754 Shape 1) paired with a for=-bound table-ui.",
|
|
77
|
+
"a2ui": "[\n {\"id\": \"root\", \"component\": \"Column\", \"gap\": \"0\", \"children\": [\"tests\", \"ftr\"]},\n {\"id\": \"tests\", \"component\": \"Table\", \"raw\": true},\n {\"id\": \"ftr\", \"component\": \"TableFooter\", \"for\": \"tests\", \"page\": 1, \"page-size\": 10, \"range-total\": 128}\n]",
|
|
78
|
+
"name": "table-footer-server-mode"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"description": "Client-mode footer bound to a [paginate]d table-ui with its own internal pager suppressed via [no-pager].",
|
|
82
|
+
"a2ui": "[\n {\"id\": \"root\", \"component\": \"Column\", \"gap\": \"0\", \"children\": [\"tests-c\", \"ftr\"]},\n {\"id\": \"tests-c\", \"component\": \"Table\", \"paginate\": 10, \"no-pager\": true, \"raw\": true},\n {\"id\": \"ftr\", \"component\": \"TableFooter\", \"for\": \"tests-c\"}\n]",
|
|
83
|
+
"name": "table-footer-client-mode"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"keywords": [
|
|
87
|
+
"table-footer",
|
|
88
|
+
"pagination",
|
|
89
|
+
"pager",
|
|
90
|
+
"range",
|
|
91
|
+
"showing",
|
|
92
|
+
"data-grid",
|
|
93
|
+
"directory",
|
|
94
|
+
"admin",
|
|
95
|
+
"backoffice",
|
|
96
|
+
"listing",
|
|
97
|
+
"records"
|
|
98
|
+
],
|
|
99
|
+
"name": "UITableFooter",
|
|
100
|
+
"parts": {},
|
|
101
|
+
"related": [
|
|
102
|
+
"table",
|
|
103
|
+
"table-toolbar",
|
|
104
|
+
"pagination",
|
|
105
|
+
"card"
|
|
106
|
+
],
|
|
107
|
+
"slots": {
|
|
108
|
+
"empty": {
|
|
109
|
+
"description": "Renders in place of the range label — the same [data-range] region — when [range-total] is EXPLICITLY present and equal to \"0\" (checked via hasAttribute, never the computed value alone, so an unset range-total during loading never flashes this content). Mutually exclusive with a positive [range-total]: the normal \"Showing X–Y of N\" (or count-only) text always wins whenever range-total resolves positive. Plain author-supplied markup — table-footer-ui does not template or constrain its shape. Naming matches table-toolbar-ui's own `empty` slot convention."
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"states": [
|
|
113
|
+
{
|
|
114
|
+
"description": "Default, ready for interaction.",
|
|
115
|
+
"name": "idle"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"status": "beta",
|
|
119
|
+
"synonyms": {
|
|
120
|
+
"pager": [
|
|
121
|
+
"table-footer",
|
|
122
|
+
"pagination"
|
|
123
|
+
],
|
|
124
|
+
"pagination": [
|
|
125
|
+
"table-footer",
|
|
126
|
+
"pagination"
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
"tag": "table-footer-ui",
|
|
130
|
+
"tokens": {
|
|
131
|
+
"--table-footer-gap": {
|
|
132
|
+
"description": "Gap between the range label and the pager"
|
|
133
|
+
},
|
|
134
|
+
"--table-footer-px": {
|
|
135
|
+
"description": "Horizontal padding"
|
|
136
|
+
},
|
|
137
|
+
"--table-footer-py": {
|
|
138
|
+
"description": "Vertical padding"
|
|
139
|
+
},
|
|
140
|
+
"--table-footer-summary-fg": {
|
|
141
|
+
"description": "Range-label text color"
|
|
142
|
+
},
|
|
143
|
+
"--table-footer-summary-size": {
|
|
144
|
+
"description": "Range-label font size"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
"traits": [],
|
|
148
|
+
"version": 1
|
|
149
|
+
}
|
|
150
|
+
}
|