flexdesk 0.6.1 → 0.6.2

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/README.md CHANGED
@@ -354,6 +354,50 @@ lock.setEnabled(false); // scroll each side on its own; true brings them level
354
354
  position the lock itself wrote moves nobody back. The lock copies pixels, so
355
355
  it lines rows up only when both sides draw rows of the same height.
356
356
 
357
+ ### A server's rows in pages or as one list: `paging`
358
+
359
+ `paging` (off unless you set it) shows rows that your code fetches from a
360
+ server either one page at a time or as one list that loads more as the reader
361
+ scrolls. A strip under the body shows which rows are loaded. It has the page
362
+ buttons or a *Load all rows* button, and a Pages / Scroll switch if you pass
363
+ `onModeChange`. Set `paging` and the old pager (`pagination`) is not drawn.
364
+
365
+ ```js
366
+ new DataTable(host, {
367
+ headers, rows, // the rows you hold: one page, or all scrolled so far
368
+ virtualize: true,
369
+ paging: {
370
+ mode: 'scroll', // what was asked for: 'pages' or 'scroll'
371
+ pageSize: 1000,
372
+ softLimit: 10000, // above this many rows the table is always paged
373
+ total: 22521, // exact count, or null if unknown
374
+ atLeast: 0, // a lower bound when the count is not known
375
+ offset: 0, // in pages: where rows[0] is in the source
376
+ hasMore: true,
377
+ onPage: (offset, limit) => fetchPage(offset),
378
+ onLoadMore: () => fetchNext(), // called near the end of the scroll
379
+ onLoadAll: () => fetchRest(),
380
+ onModeChange: (mode) => remember(mode),
381
+ },
382
+ });
383
+ ```
384
+
385
+ Your code holds the rows and fetches them. The table decides how to show them
386
+ with `resolvePaging`, which is exported so your code gets the same answer when
387
+ it decides what to fetch. A source with more rows than `softLimit` is shown in
388
+ pages even if scroll was asked for. The strip says so, and Scroll is disabled
389
+ with the reason. `softLimit` can't be more than `hardLimit` (default and
390
+ ceiling `PAGING_HARD_LIMIT`, 100,000), and a scrolling table never asks for rows
391
+ past it. If no count is known, the rows already loaded count as evidence: a
392
+ table that has loaded more than `softLimit` rows and still has more is paged.
393
+ While scrolling, `onLoadMore` is called within 400px of the end, or after
394
+ render when the rows don't fill the box. It is never called when the box has
395
+ no height, for example in a hidden tab. A callback that returns a Promise
396
+ blocks the next call until it settles, and the strip shows the table busy.
397
+ `setPaging(patch)` redraws the strip only, for example when a count arrives.
398
+ In pages, `showRowNumbers: 'position'` numbers rows from `offset`. Row indexes
399
+ (`__rowIndex`, the selection, `onRowClick`) still refer to positions in `rows`.
400
+
357
401
  ### Scrollbars
358
402
 
359
403
  `installAutoScrollbars(root)` (from `@flexdesk/widgets`) replaces the browser's
package/css/base.css CHANGED
@@ -1648,6 +1648,49 @@ body.twm-window-maximized .twm-resize-handle {
1648
1648
  opacity: 0.3;
1649
1649
  cursor: not-allowed;
1650
1650
  }
1651
+ /* `paging` — the strip UNDER a paged or scrolling DataTable's body: which rows
1652
+ * are held, the page buttons or Load all, why a large source is paged, and the
1653
+ * Pages / Scroll switch. */
1654
+ .twm-dt-paging {
1655
+ display: flex;
1656
+ align-items: center;
1657
+ gap: var(--space-md);
1658
+ flex: 0 0 auto;
1659
+ min-width: 0;
1660
+ padding: var(--space-xs) var(--space-md);
1661
+ border-top: 1px solid var(--border-subtle);
1662
+ font-size: var(--font-size-sm);
1663
+ color: var(--text-muted);
1664
+ white-space: nowrap;
1665
+ overflow: hidden;
1666
+ }
1667
+ .twm-dt-paging__info { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
1668
+ .twm-dt-paging__spacer { flex: 1 1 auto; }
1669
+ .twm-dt-paging__nav { display: inline-flex; align-items: center; gap: var(--space-xs); }
1670
+ .twm-dt-paging__page { min-width: 72px; text-align: center; }
1671
+ .twm-dt-paging .twm-pagination-btn { height: 20px; min-width: 22px; }
1672
+ .twm-dt-paging__note { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; }
1673
+ .twm-dt-paging__all,
1674
+ .twm-dt-paging__mode {
1675
+ height: 20px;
1676
+ padding: 0 var(--space-md);
1677
+ background: transparent;
1678
+ border: 1px solid var(--border-default);
1679
+ border-radius: var(--radius-sm);
1680
+ color: var(--text-body);
1681
+ font: inherit;
1682
+ cursor: pointer;
1683
+ }
1684
+ .twm-dt-paging__all:hover:not(:disabled),
1685
+ .twm-dt-paging__mode:hover:not(:disabled) { border-color: var(--accent); color: var(--text-bright); }
1686
+ .twm-dt-paging__modes { display: inline-flex; }
1687
+ .twm-dt-paging__mode { border-radius: 0; }
1688
+ .twm-dt-paging__mode:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
1689
+ .twm-dt-paging__mode:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
1690
+ .twm-dt-paging__mode[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--text-bright); }
1691
+ .twm-dt-paging__all:disabled,
1692
+ .twm-dt-paging__mode:disabled { opacity: 0.45; cursor: not-allowed; }
1693
+ .twm-dt-paging__mode[aria-pressed="true"]:disabled { opacity: 1; cursor: default; }
1651
1694
  /* Preview Table Styles - Essential for data view */
1652
1695
  .twm-preview-table-wrap {
1653
1696
  overflow: auto;
package/css/flexdesk.css CHANGED
@@ -1746,6 +1746,49 @@ body.twm-window-maximized .twm-resize-handle {
1746
1746
  opacity: 0.3;
1747
1747
  cursor: not-allowed;
1748
1748
  }
1749
+ /* `paging` — the strip UNDER a paged or scrolling DataTable's body: which rows
1750
+ * are held, the page buttons or Load all, why a large source is paged, and the
1751
+ * Pages / Scroll switch. */
1752
+ .twm-dt-paging {
1753
+ display: flex;
1754
+ align-items: center;
1755
+ gap: var(--space-md);
1756
+ flex: 0 0 auto;
1757
+ min-width: 0;
1758
+ padding: var(--space-xs) var(--space-md);
1759
+ border-top: 1px solid var(--border-subtle);
1760
+ font-size: var(--font-size-sm);
1761
+ color: var(--text-muted);
1762
+ white-space: nowrap;
1763
+ overflow: hidden;
1764
+ }
1765
+ .twm-dt-paging__info { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
1766
+ .twm-dt-paging__spacer { flex: 1 1 auto; }
1767
+ .twm-dt-paging__nav { display: inline-flex; align-items: center; gap: var(--space-xs); }
1768
+ .twm-dt-paging__page { min-width: 72px; text-align: center; }
1769
+ .twm-dt-paging .twm-pagination-btn { height: 20px; min-width: 22px; }
1770
+ .twm-dt-paging__note { color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; }
1771
+ .twm-dt-paging__all,
1772
+ .twm-dt-paging__mode {
1773
+ height: 20px;
1774
+ padding: 0 var(--space-md);
1775
+ background: transparent;
1776
+ border: 1px solid var(--border-default);
1777
+ border-radius: var(--radius-sm);
1778
+ color: var(--text-body);
1779
+ font: inherit;
1780
+ cursor: pointer;
1781
+ }
1782
+ .twm-dt-paging__all:hover:not(:disabled),
1783
+ .twm-dt-paging__mode:hover:not(:disabled) { border-color: var(--accent); color: var(--text-bright); }
1784
+ .twm-dt-paging__modes { display: inline-flex; }
1785
+ .twm-dt-paging__mode { border-radius: 0; }
1786
+ .twm-dt-paging__mode:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
1787
+ .twm-dt-paging__mode:last-child { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; margin-left: -1px; }
1788
+ .twm-dt-paging__mode[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--text-bright); }
1789
+ .twm-dt-paging__all:disabled,
1790
+ .twm-dt-paging__mode:disabled { opacity: 0.45; cursor: not-allowed; }
1791
+ .twm-dt-paging__mode[aria-pressed="true"]:disabled { opacity: 1; cursor: default; }
1749
1792
  /* Preview Table Styles - Essential for data view */
1750
1793
  .twm-preview-table-wrap {
1751
1794
  overflow: auto;
package/dist/charts.js CHANGED
@@ -39,10 +39,10 @@ import {
39
39
  setPlotlySource,
40
40
  uid,
41
41
  updateChart
42
- } from "./chunk-ZMCRDOCF.js";
42
+ } from "./chunk-XYUZF5CD.js";
43
43
  import {
44
44
  createRafResizeObserver
45
- } from "./chunk-IYV5JVYB.js";
45
+ } from "./chunk-CPYBQN3Q.js";
46
46
  import {
47
47
  ManagedWindow
48
48
  } from "./chunk-6JSOVNID.js";
@@ -361,6 +361,34 @@ function matchDurationFilter(ms, filterText, shown) {
361
361
  // src/ui/components/data_table.js
362
362
  var DEFAULT_PAGE_SIZE = 100;
363
363
  var DIFF_STATUSES = /* @__PURE__ */ new Set(["added", "removed", "changed", "same", "gap"]);
364
+ var PAGING_HARD_LIMIT = 1e5;
365
+ var PAGING_SOFT_LIMIT = 1e4;
366
+ function resolvePaging({
367
+ mode = "scroll",
368
+ total = null,
369
+ atLeast = 0,
370
+ held = 0,
371
+ hasMore = false,
372
+ softLimit = PAGING_SOFT_LIMIT,
373
+ hardLimit = PAGING_HARD_LIMIT
374
+ } = {}) {
375
+ const requested = mode === "pages" ? "pages" : "scroll";
376
+ const hard = Number.isFinite(hardLimit) && hardLimit >= 1 ? Math.floor(hardLimit) : PAGING_HARD_LIMIT;
377
+ const soft = Math.min(hard, Number.isFinite(softLimit) && softLimit >= 1 ? Math.floor(softLimit) : PAGING_SOFT_LIMIT);
378
+ const exact = Number.isFinite(total) && total >= 0;
379
+ const known = exact ? total : Math.max(Number.isFinite(atLeast) ? atLeast : 0, (held || 0) + (hasMore ? 1 : 0));
380
+ const forced = requested === "scroll" && known > soft;
381
+ return {
382
+ mode: forced ? "pages" : requested,
383
+ requested,
384
+ forced,
385
+ softLimit: soft,
386
+ hardLimit: hard,
387
+ known,
388
+ exact
389
+ };
390
+ }
391
+ var PAGING_LOAD_MORE_PX = 400;
364
392
  var TYPED_COLUMNS = /* @__PURE__ */ new Set(["date", "datetime", "duration"]);
365
393
  var DESELECTING_CLICKS = /* @__PURE__ */ new WeakSet();
366
394
  var AUTO_DISPOSE = /* @__PURE__ */ new Map();
@@ -513,6 +541,9 @@ var DataTable = class {
513
541
  // promise that adding the key changed no existing layout by a
514
542
  // pixel. Only a consumer that asks for 'content' sees anything new.
515
543
  columnFit: "container",
544
+ // Off unless asked for — see the typedef. With it the old pager is
545
+ // not drawn: the paging strip says the same and more.
546
+ paging: null,
516
547
  // C10. Off unless asked for — see the typedef.
517
548
  virtualize: false,
518
549
  virtualRowHeight: null,
@@ -925,7 +956,7 @@ var DataTable = class {
925
956
  this._wrapperEl.style.cssText = "display:flex; flex-direction:column; height:100%; min-height:0;";
926
957
  }
927
958
  this._loading = false;
928
- if (pagination && rows.length > 0) {
959
+ if (pagination && rows.length > 0 && !this._pagingConfig()) {
929
960
  this._paginationEl = this._createPagination();
930
961
  if (this._paginationEl) this._wrapperEl.appendChild(this._paginationEl);
931
962
  }
@@ -1011,6 +1042,11 @@ var DataTable = class {
1011
1042
  this._wrapperEl.appendChild(tableWrap);
1012
1043
  }
1013
1044
  this._tableWrapEl = tableWrap;
1045
+ this._pagingEl = null;
1046
+ if (this._pagingConfig()) {
1047
+ this._pagingEl = this._createPagingStrip();
1048
+ if (this._pagingEl) this._wrapperEl.appendChild(this._pagingEl);
1049
+ }
1014
1050
  this.container.appendChild(this._wrapperEl);
1015
1051
  if (this.config.scrollLock && typeof this.config.scrollLock.attach === "function") {
1016
1052
  this._disposers.push(this.config.scrollLock.attach(tableWrap));
@@ -1028,6 +1064,14 @@ var DataTable = class {
1028
1064
  this._virtMeasure();
1029
1065
  this._virtUpdate({ force: true, notify: false });
1030
1066
  }
1067
+ if (this._pagingConfig()) {
1068
+ const onScroll = () => this._pagingMaybeLoadMore();
1069
+ tableWrap.addEventListener("scroll", onScroll, { passive: true });
1070
+ this._disposers.push(() => tableWrap.removeEventListener("scroll", onScroll));
1071
+ requestAnimationFrame(() => {
1072
+ if (this._tableWrapEl === tableWrap) this._pagingMaybeLoadMore();
1073
+ });
1074
+ }
1031
1075
  if (this._headerTableEl && this._tableEl) {
1032
1076
  requestAnimationFrame(() => this._syncHeaderWidths());
1033
1077
  if (this._resizeObserver) {
@@ -1890,13 +1934,234 @@ var DataTable = class {
1890
1934
  btn.addEventListener("click", onClick);
1891
1935
  return btn;
1892
1936
  }
1937
+ // ── `paging` ────────────────────────────────────────────────────────────
1938
+ /** The `paging` config with its defaults, or null when it is not set. */
1939
+ _pagingConfig() {
1940
+ const p = this.config.paging;
1941
+ if (!p || typeof p !== "object") return null;
1942
+ const size = Number.isFinite(p.pageSize) && p.pageSize >= 1 ? Math.floor(p.pageSize) : this.config.pageSize;
1943
+ return {
1944
+ ...p,
1945
+ pageSize: size,
1946
+ offset: Number.isFinite(p.offset) && p.offset > 0 ? Math.floor(p.offset) : 0,
1947
+ // What the table holds of the source. A consumer whose `rows` carry
1948
+ // a row the source does not (a blank line to type into) says so.
1949
+ held: Number.isFinite(p.held) ? p.held : this.config.rows?.length || 0,
1950
+ hasMore: !!p.hasMore,
1951
+ loadMorePx: Number.isFinite(p.loadMorePx) ? p.loadMorePx : PAGING_LOAD_MORE_PX
1952
+ };
1953
+ }
1954
+ /**
1955
+ * Which way the rows are shown, and why — `resolvePaging` over this
1956
+ * table's facts. `null` without `paging`.
1957
+ */
1958
+ get pagingState() {
1959
+ const p = this._pagingConfig();
1960
+ if (!p) return null;
1961
+ return resolvePaging({
1962
+ mode: p.mode,
1963
+ total: p.total,
1964
+ atLeast: p.atLeast,
1965
+ held: p.offset + p.held,
1966
+ hasMore: p.hasMore,
1967
+ softLimit: p.softLimit,
1968
+ hardLimit: p.hardLimit
1969
+ });
1970
+ }
1971
+ /**
1972
+ * Change some `paging` facts — a count that arrived, a mode — and redraw
1973
+ * the STRIP only. The rows are not touched: a consumer with new rows
1974
+ * renders the table as it always has.
1975
+ */
1976
+ setPaging(patch = {}) {
1977
+ if (!this.config.paging) return;
1978
+ this.config.paging = { ...this.config.paging, ...patch };
1979
+ this._refreshPagingStrip();
1980
+ this._pagingMaybeLoadMore();
1981
+ }
1982
+ _refreshPagingStrip() {
1983
+ if (!this._wrapperEl) return;
1984
+ const next = this._pagingConfig() ? this._createPagingStrip() : null;
1985
+ const prev = this._pagingEl;
1986
+ if (prev && prev.parentNode === this._wrapperEl) {
1987
+ if (next) prev.replaceWith(next);
1988
+ else prev.remove();
1989
+ } else if (next) {
1990
+ this._wrapperEl.appendChild(next);
1991
+ }
1992
+ this._pagingEl = next;
1993
+ }
1994
+ /**
1995
+ * Call one of the consumer's paging callbacks. A Promise holds every other
1996
+ * paging call back until it settles, and the strip shows the table busy —
1997
+ * a second `onLoadMore` fired by the next scroll event would fetch the same
1998
+ * page twice.
1999
+ */
2000
+ _pagingCall(kind, fn, ...args) {
2001
+ if (typeof fn !== "function" || this._pagingBusy) return;
2002
+ let result;
2003
+ try {
2004
+ result = fn(...args);
2005
+ } catch (err) {
2006
+ console.error(`[DataTable] paging ${kind} threw`, err);
2007
+ return;
2008
+ }
2009
+ if (result && typeof result.then === "function") {
2010
+ this._pagingBusy = kind;
2011
+ this._refreshPagingStrip();
2012
+ const settle = () => {
2013
+ if (this._pagingBusy !== kind) return;
2014
+ this._pagingBusy = null;
2015
+ if (this._pagingEl?.isConnected) this._refreshPagingStrip();
2016
+ };
2017
+ result.then(settle, (err) => {
2018
+ console.error(`[DataTable] paging ${kind} failed`, err);
2019
+ settle();
2020
+ });
2021
+ }
2022
+ }
2023
+ /**
2024
+ * Scrolling: ask for the next rows when the body is near its end — or does
2025
+ * not fill its box, which no scroll can ever change. Never past the hard
2026
+ * limit, never in pages, never with no layout (a hidden table's box is 0px
2027
+ * tall, and "0 ≤ 0" would ask for the whole source).
2028
+ */
2029
+ _pagingMaybeLoadMore() {
2030
+ const p = this._pagingConfig();
2031
+ if (!p || !p.hasMore || this._pagingBusy) return;
2032
+ const state = this.pagingState;
2033
+ if (state.mode !== "scroll" || p.held >= state.hardLimit) return;
2034
+ const wrap = this._tableWrapEl;
2035
+ if (!wrap?.isConnected || !(wrap.clientHeight > 0)) return;
2036
+ const remaining = wrap.scrollHeight - wrap.scrollTop - wrap.clientHeight;
2037
+ if (remaining >= p.loadMorePx) return;
2038
+ this._pagingCall("more", p.onLoadMore);
2039
+ }
2040
+ /** The strip under the body, or null when it would say nothing. */
2041
+ _createPagingStrip() {
2042
+ const p = this._pagingConfig();
2043
+ const state = this.pagingState;
2044
+ const { mode, forced, exact, known } = state;
2045
+ const busy = this._pagingBusy;
2046
+ const n = (x) => Number(x).toLocaleString();
2047
+ const pageSize = p.pageSize;
2048
+ const held = p.held;
2049
+ const total = exact ? p.total : null;
2050
+ const morePages = p.offset > 0 || p.hasMore || exact && total > held;
2051
+ if (!forced && mode === "scroll" && !p.hasMore && held <= pageSize) return null;
2052
+ if (!forced && mode === "pages" && !morePages) return null;
2053
+ const el = document.createElement("div");
2054
+ el.className = `twm-dt-paging twm-dt-paging--${mode}`;
2055
+ el.setAttribute("role", "navigation");
2056
+ el.setAttribute("aria-label", "Rows");
2057
+ if (busy) el.classList.add("twm-dt-paging--busy");
2058
+ const info = document.createElement("span");
2059
+ info.className = "twm-dt-paging__info";
2060
+ el.appendChild(info);
2061
+ if (mode === "pages") {
2062
+ const from = held ? p.offset + 1 : p.offset;
2063
+ const to = p.offset + held;
2064
+ let of = "";
2065
+ if (exact) of = ` of ${n(total)}`;
2066
+ else if (known > to) of = ` of more than ${n(known - 1)}`;
2067
+ info.textContent = held ? `Rows ${n(from)}\u2013${n(to)}${of}` : "No rows on this page";
2068
+ const hasPrev = p.offset > 0;
2069
+ const hasNext = exact ? p.offset + held < total : p.hasMore;
2070
+ const lastOffset = exact && total > 0 ? Math.floor((total - 1) / pageSize) * pageSize : null;
2071
+ const go = (offset) => (ev) => {
2072
+ if (!ev?.currentTarget?.disabled) this._pagingCall("page", p.onPage, offset, pageSize);
2073
+ };
2074
+ const nav = document.createElement("span");
2075
+ nav.className = "twm-dt-paging__nav";
2076
+ const off = !!busy || typeof p.onPage !== "function";
2077
+ nav.append(
2078
+ this._createPaginationBtn("first_page", "First page", off || !hasPrev, go(0)),
2079
+ this._createPaginationBtn(
2080
+ "chevron_left",
2081
+ "Previous page",
2082
+ off || !hasPrev,
2083
+ go(Math.max(0, p.offset - pageSize))
2084
+ )
2085
+ );
2086
+ const page = document.createElement("span");
2087
+ page.className = "twm-dt-paging__page";
2088
+ const current = Math.floor(p.offset / pageSize) + 1;
2089
+ page.textContent = exact ? `Page ${n(current)} of ${n(Math.max(1, Math.ceil(total / pageSize)))}` : `Page ${n(current)}`;
2090
+ nav.append(
2091
+ page,
2092
+ this._createPaginationBtn(
2093
+ "chevron_right",
2094
+ "Next page",
2095
+ off || !hasNext,
2096
+ go(p.offset + pageSize)
2097
+ ),
2098
+ // The last page needs the exact count: without it there is no
2099
+ // offset to go to, and the button says so by being off.
2100
+ this._createPaginationBtn(
2101
+ "last_page",
2102
+ lastOffset === null ? "Last page (the total is not known)" : "Last page",
2103
+ off || !hasNext || lastOffset === null,
2104
+ go(lastOffset)
2105
+ )
2106
+ );
2107
+ el.appendChild(nav);
2108
+ } else {
2109
+ if (exact && total > held) info.textContent = `${n(held)} of ${n(total)} rows`;
2110
+ else if (p.hasMore) info.textContent = `${n(held)} rows, more to come`;
2111
+ else info.textContent = `${n(held)} rows`;
2112
+ if (p.hasMore && typeof p.onLoadAll === "function") {
2113
+ const all = document.createElement("button");
2114
+ all.type = "button";
2115
+ all.className = "twm-dt-paging__all";
2116
+ all.textContent = busy === "all" ? "Loading\u2026" : exact ? `Load all ${n(total)} rows` : "Load all rows";
2117
+ all.disabled = !!busy;
2118
+ all.addEventListener("click", () => {
2119
+ if (!all.disabled) this._pagingCall("all", p.onLoadAll);
2120
+ });
2121
+ el.appendChild(all);
2122
+ }
2123
+ }
2124
+ const spacer = document.createElement("span");
2125
+ spacer.className = "twm-dt-paging__spacer";
2126
+ el.appendChild(spacer);
2127
+ const why = forced ? `More than ${n(state.softLimit)} rows, so they are shown in pages.` : null;
2128
+ if (why) {
2129
+ const note = document.createElement("span");
2130
+ note.className = "twm-dt-paging__note";
2131
+ note.textContent = why;
2132
+ el.appendChild(note);
2133
+ }
2134
+ if (typeof p.onModeChange === "function") {
2135
+ const group = document.createElement("span");
2136
+ group.className = "twm-dt-paging__modes";
2137
+ group.setAttribute("role", "group");
2138
+ group.setAttribute("aria-label", "Show rows");
2139
+ for (const [value, label] of [["pages", "Pages"], ["scroll", "Scroll"]]) {
2140
+ const b = document.createElement("button");
2141
+ b.type = "button";
2142
+ b.className = "twm-dt-paging__mode";
2143
+ b.dataset.mode = value;
2144
+ b.textContent = label;
2145
+ const pressed = mode === value;
2146
+ b.setAttribute("aria-pressed", String(pressed));
2147
+ b.disabled = !!busy || value === "scroll" && forced;
2148
+ if (value === "scroll" && forced) b.title = why;
2149
+ b.addEventListener("click", () => {
2150
+ if (!b.disabled && mode !== value) this._pagingCall("mode", p.onModeChange, value);
2151
+ });
2152
+ group.appendChild(b);
2153
+ }
2154
+ el.appendChild(group);
2155
+ }
2156
+ return el;
2157
+ }
1893
2158
  _createTable() {
1894
2159
  const { headers, rows, pageSize, sortable, filterable, showRowNumbers, readonly, getHeaderIcon, onPageChange, offset: configOffset } = this.config;
1895
2160
  const { sortColumn, sortAscending } = this._state;
1896
2161
  const isServerSide = typeof onPageChange === "function";
1897
2162
  const processedRows = isServerSide ? rows : this._getProcessedRows();
1898
2163
  const offset = isServerSide ? configOffset || 0 : this._state.offset;
1899
- const pageRows = isServerSide || !this.config.pagination ? processedRows : processedRows.slice(offset, offset + pageSize);
2164
+ const pageRows = isServerSide || !this.config.pagination || this._pagingConfig() ? processedRows : processedRows.slice(offset, offset + pageSize);
1900
2165
  const table = document.createElement("table");
1901
2166
  table.className = this._tableClassName();
1902
2167
  table.tabIndex = 0;
@@ -1959,6 +2224,8 @@ var DataTable = class {
1959
2224
  return isServerSide ? (configOffset || 0) + localIdx : this._processedIndexMap?.[processedIdx] ?? processedIdx;
1960
2225
  };
1961
2226
  this._positionBase = isServerSide ? configOffset || 0 : this.config.pagination ? offset : 0;
2227
+ const paged = this._pagingConfig();
2228
+ if (paged && Number.isFinite(paged.offset)) this._positionBase += paged.offset;
1962
2229
  const tbody = document.createElement("tbody");
1963
2230
  table.appendChild(tbody);
1964
2231
  this._tbodyEl = tbody;
@@ -3725,6 +3992,9 @@ export {
3725
3992
  formatDuration,
3726
3993
  matchDateFilter,
3727
3994
  matchDurationFilter,
3995
+ PAGING_HARD_LIMIT,
3996
+ PAGING_SOFT_LIMIT,
3997
+ resolvePaging,
3728
3998
  DataTable
3729
3999
  };
3730
- //# sourceMappingURL=chunk-IYV5JVYB.js.map
4000
+ //# sourceMappingURL=chunk-CPYBQN3Q.js.map