@richardmcquiston01/dashboard-widgets-toolkit 0.9.0 → 0.10.0
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/dist/core.cjs +605 -14
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +134 -3
- package/dist/core.d.ts +134 -3
- package/dist/core.js +583 -15
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +605 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +583 -15
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1014 -164
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +39 -2
- package/dist/react.d.ts +39 -2
- package/dist/react.js +1014 -164
- package/dist/react.js.map +1 -1
- package/dist/{scale-CrXxawQn.d.cts → scale-N69bo7wo.d.cts} +36 -1
- package/dist/{scale-CrXxawQn.d.ts → scale-N69bo7wo.d.ts} +36 -1
- package/dist/styles.css +138 -0
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -429,21 +429,36 @@ function fillColumnSpans(items, columns, largeSpan = 2) {
|
|
|
429
429
|
function fillWidthSpans(items) {
|
|
430
430
|
return placeAndFill(items, WIDTH_COLUMNS, itemWidth);
|
|
431
431
|
}
|
|
432
|
+
function placeRows(items) {
|
|
433
|
+
return placeAndFillRows(items, WIDTH_COLUMNS, itemWidth).rows;
|
|
434
|
+
}
|
|
432
435
|
function placeAndFill(items, columns, spanOf) {
|
|
436
|
+
return placeAndFillRows(items, columns, spanOf).spans;
|
|
437
|
+
}
|
|
438
|
+
function placeAndFillRows(items, columns, spanOf) {
|
|
433
439
|
const trackCount = Math.max(1, Math.floor(columns));
|
|
434
440
|
const spans = /* @__PURE__ */ new Map();
|
|
441
|
+
const rows = [];
|
|
435
442
|
let row = [];
|
|
436
443
|
let used = 0;
|
|
437
444
|
function closeRow() {
|
|
445
|
+
if (row.length === 0) return;
|
|
438
446
|
const fillers = row.filter(({ item }) => fillsWidth(item.fill));
|
|
439
447
|
const leftover = trackCount - used;
|
|
448
|
+
const finalSpans = /* @__PURE__ */ new Map();
|
|
440
449
|
if (fillers.length > 0) {
|
|
441
450
|
const share = Math.floor(leftover / fillers.length);
|
|
442
451
|
const remainder = leftover % fillers.length;
|
|
443
452
|
fillers.forEach(({ item, span }, index) => {
|
|
444
|
-
|
|
453
|
+
const grown = span + share + (index < remainder ? 1 : 0);
|
|
454
|
+
spans.set(item.key, grown);
|
|
455
|
+
finalSpans.set(item.key, grown);
|
|
445
456
|
});
|
|
446
457
|
}
|
|
458
|
+
rows.push({
|
|
459
|
+
keys: row.map(({ item }) => item.key),
|
|
460
|
+
spans: row.map(({ item, span }) => finalSpans.get(item.key) ?? span)
|
|
461
|
+
});
|
|
447
462
|
row = [];
|
|
448
463
|
used = 0;
|
|
449
464
|
}
|
|
@@ -454,7 +469,7 @@ function placeAndFill(items, columns, spanOf) {
|
|
|
454
469
|
used += span;
|
|
455
470
|
}
|
|
456
471
|
closeRow();
|
|
457
|
-
return spans;
|
|
472
|
+
return { spans, rows };
|
|
458
473
|
}
|
|
459
474
|
|
|
460
475
|
// src/core/scale.ts
|
|
@@ -537,6 +552,27 @@ var DEFAULT_LABELS = {
|
|
|
537
552
|
dashboardControls: "Dashboard controls",
|
|
538
553
|
locked: (title) => `${title} is locked`,
|
|
539
554
|
lockedForViewers: (title) => `${title} is locked for viewers`,
|
|
555
|
+
pageBar: "Pages",
|
|
556
|
+
pageTabName: (index, count, title) => `Page ${index} of ${count}: ${title}`,
|
|
557
|
+
previousPageButton: "Previous page",
|
|
558
|
+
nextPageButton: "Next page",
|
|
559
|
+
managePages: "Manage pages",
|
|
560
|
+
addPage: "Add page",
|
|
561
|
+
renamePage: (title) => `Rename ${title}`,
|
|
562
|
+
pageTitle: "Page title",
|
|
563
|
+
savePageTitle: "Save page title",
|
|
564
|
+
cancelPageTitle: "Cancel renaming",
|
|
565
|
+
deletePage: (title) => `Delete ${title}`,
|
|
566
|
+
confirmDeletePage: (title) => `Delete the page "${title}" and move its widgets to another page?`,
|
|
567
|
+
movePageLeft: (title) => `Move ${title} page left`,
|
|
568
|
+
movePageRight: (title) => `Move ${title} page right`,
|
|
569
|
+
moveToPage: (title) => `Move ${title} to another page`,
|
|
570
|
+
moveToPagePlaceholder: "Move to page\u2026",
|
|
571
|
+
moveToPageOption: (title, rowsFree) => `${title} (${rowsFree} ${rowsFree === 1 ? "row" : "rows"} free)`,
|
|
572
|
+
newPageOption: "New page\u2026",
|
|
573
|
+
movedToPage: (title, pageTitle) => `${title} moved to ${pageTitle}`,
|
|
574
|
+
pageFull: (pageTitle, maxRows) => `Page "${pageTitle}" is full (${maxRows} rows). Move or hide a widget first.`,
|
|
575
|
+
emptyPage: "This page has no widgets. Move one here from another page.",
|
|
540
576
|
opensInNewTab: "(opens in a new tab)",
|
|
541
577
|
view: (title) => `View ${title}`,
|
|
542
578
|
close: "Close",
|
|
@@ -1625,6 +1661,9 @@ function isWidgetVisibleTo(definition, roles) {
|
|
|
1625
1661
|
}
|
|
1626
1662
|
|
|
1627
1663
|
// src/core/layout.ts
|
|
1664
|
+
var MAX_PAGE_TITLE_LENGTH = 30;
|
|
1665
|
+
var MAX_PARSED_PAGES = 50;
|
|
1666
|
+
var MAX_PAGE_ROWS = 20;
|
|
1628
1667
|
var EMPTY_LAYOUT = Object.freeze({
|
|
1629
1668
|
order: Object.freeze([]),
|
|
1630
1669
|
hidden: Object.freeze([]),
|
|
@@ -1739,6 +1778,22 @@ function restoreWidget(layout, key) {
|
|
|
1739
1778
|
function toggleMinimized(layout, key) {
|
|
1740
1779
|
return isMinimized(layout, key) ? restoreWidget(layout, key) : minimizeWidget(layout, key);
|
|
1741
1780
|
}
|
|
1781
|
+
function mapLayoutLists(layout, change) {
|
|
1782
|
+
const top = change(layout);
|
|
1783
|
+
const pages = layout.pages?.map((page) => {
|
|
1784
|
+
const next = change(page);
|
|
1785
|
+
return next.order === page.order && next.hidden === page.hidden && next.minimized === page.minimized ? page : { ...page, ...next };
|
|
1786
|
+
});
|
|
1787
|
+
const pagesChanged = pages !== void 0 && pages.some((page, i) => page !== layout.pages?.[i]);
|
|
1788
|
+
if (top.order === layout.order && top.hidden === layout.hidden && top.minimized === layout.minimized && !pagesChanged) {
|
|
1789
|
+
return layout;
|
|
1790
|
+
}
|
|
1791
|
+
return {
|
|
1792
|
+
...layout,
|
|
1793
|
+
...top,
|
|
1794
|
+
...pages === void 0 ? {} : { pages }
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1742
1797
|
function enforceLocks(definitions, layout, options = {}) {
|
|
1743
1798
|
if (options.overrideLocks === true) return layout;
|
|
1744
1799
|
const noMove = /* @__PURE__ */ new Set();
|
|
@@ -1750,11 +1805,337 @@ function enforceLocks(definitions, layout, options = {}) {
|
|
|
1750
1805
|
if (lock.hide) noHide.add(definition.key);
|
|
1751
1806
|
if (lock.minimize) noMinimize.add(definition.key);
|
|
1752
1807
|
}
|
|
1753
|
-
const
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1808
|
+
const without2 = (keys, drop) => keys.some((key) => drop.has(key)) ? keys.filter((key) => !drop.has(key)) : keys;
|
|
1809
|
+
return mapLayoutLists(layout, (lists) => ({
|
|
1810
|
+
order: without2(lists.order, noMove),
|
|
1811
|
+
hidden: without2(lists.hidden, noHide),
|
|
1812
|
+
minimized: without2(lists.minimized, noMinimize)
|
|
1813
|
+
}));
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
// src/core/pages.ts
|
|
1817
|
+
var DEFAULT_PAGE_KEY = "default";
|
|
1818
|
+
var DEFAULT_PAGE_ROWS = 4;
|
|
1819
|
+
function rowsAllowed(page, options) {
|
|
1820
|
+
const rows = page.maxRows ?? options.maxRows ?? DEFAULT_PAGE_ROWS;
|
|
1821
|
+
return Math.max(1, Math.min(MAX_PAGE_ROWS, Math.floor(rows)));
|
|
1822
|
+
}
|
|
1823
|
+
function hasPages(layout) {
|
|
1824
|
+
return layout.pages !== void 0 && layout.pages.length > 0;
|
|
1825
|
+
}
|
|
1826
|
+
function pageList(layout) {
|
|
1827
|
+
if (layout.pages !== void 0 && layout.pages.length > 0) {
|
|
1828
|
+
return layout.pages;
|
|
1829
|
+
}
|
|
1830
|
+
return [
|
|
1831
|
+
{
|
|
1832
|
+
key: DEFAULT_PAGE_KEY,
|
|
1833
|
+
title: "Page 1",
|
|
1834
|
+
order: layout.order,
|
|
1835
|
+
hidden: layout.hidden,
|
|
1836
|
+
minimized: layout.minimized
|
|
1837
|
+
}
|
|
1838
|
+
];
|
|
1839
|
+
}
|
|
1840
|
+
function withExplicitPages(layout) {
|
|
1841
|
+
if (hasPages(layout)) return layout;
|
|
1842
|
+
return {
|
|
1843
|
+
...layout,
|
|
1844
|
+
order: [],
|
|
1845
|
+
hidden: [],
|
|
1846
|
+
minimized: [],
|
|
1847
|
+
pages: pageList(layout)
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
function sameKeys(a, b) {
|
|
1851
|
+
return a === b || a.length === b.length && a.every((k, i) => k === b[i]);
|
|
1852
|
+
}
|
|
1853
|
+
function pageLayout(layout, pageKey) {
|
|
1854
|
+
if (!hasPages(layout))
|
|
1855
|
+
return pageKey === DEFAULT_PAGE_KEY ? layout : void 0;
|
|
1856
|
+
const page = layout.pages?.find(
|
|
1857
|
+
(p) => p.key === pageKey
|
|
1858
|
+
);
|
|
1859
|
+
if (page === void 0) return void 0;
|
|
1860
|
+
const { pages, ...rest } = layout;
|
|
1861
|
+
return {
|
|
1862
|
+
...rest,
|
|
1863
|
+
order: page.order,
|
|
1864
|
+
hidden: page.hidden,
|
|
1865
|
+
minimized: page.minimized
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
function withPageLayout(layout, pageKey, next) {
|
|
1869
|
+
const current = pageLayout(layout, pageKey);
|
|
1870
|
+
if (current === void 0 || sameKeys(current.order, next.order) && sameKeys(current.hidden, next.hidden) && sameKeys(current.minimized, next.minimized)) {
|
|
1871
|
+
return layout;
|
|
1872
|
+
}
|
|
1873
|
+
if (!hasPages(layout)) {
|
|
1874
|
+
return {
|
|
1875
|
+
...layout,
|
|
1876
|
+
order: next.order,
|
|
1877
|
+
hidden: next.hidden,
|
|
1878
|
+
minimized: next.minimized
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
return {
|
|
1882
|
+
...layout,
|
|
1883
|
+
pages: (layout.pages ?? []).map(
|
|
1884
|
+
(page) => page.key === pageKey ? {
|
|
1885
|
+
...page,
|
|
1886
|
+
order: next.order,
|
|
1887
|
+
hidden: next.hidden,
|
|
1888
|
+
minimized: next.minimized
|
|
1889
|
+
} : page
|
|
1890
|
+
)
|
|
1891
|
+
};
|
|
1892
|
+
}
|
|
1893
|
+
function normalizedTitle(title) {
|
|
1894
|
+
return title.trim().normalize("NFKC").toLowerCase();
|
|
1895
|
+
}
|
|
1896
|
+
function resolvePageKey(layout, reference) {
|
|
1897
|
+
if (reference === void 0 || reference === "") return void 0;
|
|
1898
|
+
const pages = pageList(layout);
|
|
1899
|
+
const byKey = pages.find((p) => p.key === reference);
|
|
1900
|
+
if (byKey !== void 0) return byKey.key;
|
|
1901
|
+
const wanted = normalizedTitle(reference);
|
|
1902
|
+
return pages.find((p) => normalizedTitle(p.title) === wanted)?.key;
|
|
1903
|
+
}
|
|
1904
|
+
function homePageKey(layout, item) {
|
|
1905
|
+
return resolvePageKey(layout, item.page) ?? pageList(layout)[0].key;
|
|
1906
|
+
}
|
|
1907
|
+
function assignPages(definitions, layout) {
|
|
1908
|
+
const pages = pageList(layout);
|
|
1909
|
+
const assigned = new Map(pages.map((p) => [p.key, []]));
|
|
1910
|
+
for (const definition of definitions) {
|
|
1911
|
+
let pageKey;
|
|
1912
|
+
if (!resolveWidgetLock(definition).move) {
|
|
1913
|
+
pageKey = pages.find(
|
|
1914
|
+
(p) => p.order.includes(definition.key) || p.hidden.includes(definition.key)
|
|
1915
|
+
)?.key;
|
|
1916
|
+
}
|
|
1917
|
+
assigned.get(pageKey ?? homePageKey(layout, definition))?.push(definition);
|
|
1918
|
+
}
|
|
1919
|
+
return assigned;
|
|
1920
|
+
}
|
|
1921
|
+
function pageOf(definitions, layout, key) {
|
|
1922
|
+
for (const [pageKey, widgets] of assignPages(definitions, layout)) {
|
|
1923
|
+
if (widgets.some((w) => w.key === key)) return pageKey;
|
|
1924
|
+
}
|
|
1925
|
+
return void 0;
|
|
1926
|
+
}
|
|
1927
|
+
function pageWidgets(definitions, layout, pageKey) {
|
|
1928
|
+
const onPage = assignPages(definitions, layout).get(pageKey) ?? [];
|
|
1929
|
+
const view = pageLayout(layout, pageKey);
|
|
1930
|
+
return view === void 0 ? [] : visibleWidgets(onPage, view);
|
|
1931
|
+
}
|
|
1932
|
+
function pageRoom(definitions, layout, pageKey, options = {}) {
|
|
1933
|
+
const page = pageList(layout).find(
|
|
1934
|
+
(p) => p.key === pageKey
|
|
1935
|
+
);
|
|
1936
|
+
if (page === void 0) return void 0;
|
|
1937
|
+
const maxRows = rowsAllowed(page, options);
|
|
1938
|
+
const rowsUsed = placeRows(
|
|
1939
|
+
pageWidgets(definitions, layout, pageKey)
|
|
1940
|
+
).length;
|
|
1941
|
+
return { maxRows, rowsUsed, rowsFree: Math.max(0, maxRows - rowsUsed) };
|
|
1942
|
+
}
|
|
1943
|
+
function describePage(page) {
|
|
1944
|
+
return `Page "${page.title}"`;
|
|
1945
|
+
}
|
|
1946
|
+
function titleOf(item) {
|
|
1947
|
+
return item.title ?? item.key;
|
|
1948
|
+
}
|
|
1949
|
+
function checkTitle(layout, title, exceptKey) {
|
|
1950
|
+
const trimmed = title.trim();
|
|
1951
|
+
if (trimmed === "") return err("A page title must not be empty.");
|
|
1952
|
+
if (trimmed.length > MAX_PAGE_TITLE_LENGTH) {
|
|
1953
|
+
return err(
|
|
1954
|
+
`Page title "${trimmed}" is ${trimmed.length} characters; the most is ${MAX_PAGE_TITLE_LENGTH}.`
|
|
1955
|
+
);
|
|
1956
|
+
}
|
|
1957
|
+
const wanted = normalizedTitle(trimmed);
|
|
1958
|
+
const clash = pageList(layout).find(
|
|
1959
|
+
(p) => p.key !== exceptKey && normalizedTitle(p.title) === wanted
|
|
1960
|
+
);
|
|
1961
|
+
if (clash !== void 0) {
|
|
1962
|
+
return err(`Another page is already called "${clash.title}".`);
|
|
1963
|
+
}
|
|
1964
|
+
return ok(trimmed);
|
|
1965
|
+
}
|
|
1966
|
+
function nextPageKey(layout) {
|
|
1967
|
+
const keys = new Set(pageList(layout).map((p) => p.key));
|
|
1968
|
+
let n = 1;
|
|
1969
|
+
while (keys.has(`page-${n}`)) n += 1;
|
|
1970
|
+
return `page-${n}`;
|
|
1971
|
+
}
|
|
1972
|
+
function nextPageTitle(layout) {
|
|
1973
|
+
const used = new Set(
|
|
1974
|
+
pageList(layout).map((p) => normalizedTitle(p.title))
|
|
1975
|
+
);
|
|
1976
|
+
let n = pageList(layout).length + 1;
|
|
1977
|
+
while (used.has(normalizedTitle(`Page ${n}`))) n += 1;
|
|
1978
|
+
return `Page ${n}`;
|
|
1979
|
+
}
|
|
1980
|
+
function addPage(layout, options = {}) {
|
|
1981
|
+
if (pageList(layout).length >= MAX_PARSED_PAGES) {
|
|
1982
|
+
return err(
|
|
1983
|
+
`The layout already has ${MAX_PARSED_PAGES} pages, the most it can keep.`
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
const key = options.key ?? nextPageKey(layout);
|
|
1987
|
+
if (pageList(layout).some((p) => p.key === key)) {
|
|
1988
|
+
return err(`A page with the key "${key}" already exists.`);
|
|
1989
|
+
}
|
|
1990
|
+
const title = checkTitle(
|
|
1991
|
+
layout,
|
|
1992
|
+
options.title ?? nextPageTitle(layout)
|
|
1993
|
+
);
|
|
1994
|
+
if (!title.ok) return title;
|
|
1995
|
+
const base = withExplicitPages(layout);
|
|
1996
|
+
const page = {
|
|
1997
|
+
key,
|
|
1998
|
+
title: title.value,
|
|
1999
|
+
order: [],
|
|
2000
|
+
hidden: [],
|
|
2001
|
+
minimized: []
|
|
2002
|
+
};
|
|
2003
|
+
return ok({ ...base, pages: [...base.pages ?? [], page] });
|
|
2004
|
+
}
|
|
2005
|
+
function renamePage(layout, pageKey, title) {
|
|
2006
|
+
const page = pageList(layout).find(
|
|
2007
|
+
(p) => p.key === pageKey
|
|
2008
|
+
);
|
|
2009
|
+
if (page === void 0) return err(`Page "${pageKey}" doesn't exist.`);
|
|
2010
|
+
const checked = checkTitle(layout, title, pageKey);
|
|
2011
|
+
if (!checked.ok) return checked;
|
|
2012
|
+
if (checked.value === page.title) return ok(layout);
|
|
2013
|
+
const base = withExplicitPages(layout);
|
|
2014
|
+
return ok({
|
|
2015
|
+
...base,
|
|
2016
|
+
pages: (base.pages ?? []).map(
|
|
2017
|
+
(p) => p.key === pageKey ? { ...p, title: checked.value } : p
|
|
2018
|
+
)
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
function movePage(layout, pageKey, offset) {
|
|
2022
|
+
const pages = layout.pages ?? [];
|
|
2023
|
+
const from = pages.findIndex((p) => p.key === pageKey);
|
|
2024
|
+
if (from === -1) return layout;
|
|
2025
|
+
const to = Math.max(
|
|
2026
|
+
0,
|
|
2027
|
+
Math.min(pages.length - 1, from + Math.trunc(offset))
|
|
2028
|
+
);
|
|
2029
|
+
if (to === from) return layout;
|
|
2030
|
+
const next = [...pages];
|
|
2031
|
+
const [moved] = next.splice(from, 1);
|
|
2032
|
+
next.splice(to, 0, moved);
|
|
2033
|
+
return { ...layout, pages: next };
|
|
2034
|
+
}
|
|
2035
|
+
function overflowing(definitions, layout, options) {
|
|
2036
|
+
return pageList(layout).find(
|
|
2037
|
+
(page) => placeRows(pageWidgets(definitions, layout, page.key)).length > rowsAllowed(page, options)
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
function removePage(definitions, layout, pageKey, options = {}) {
|
|
2041
|
+
const pages = pageList(layout);
|
|
2042
|
+
const index = pages.findIndex((p) => p.key === pageKey);
|
|
2043
|
+
const page = pages[index];
|
|
2044
|
+
if (page === void 0) return err(`Page "${pageKey}" doesn't exist.`);
|
|
2045
|
+
if (pages.length === 1) {
|
|
2046
|
+
return err(
|
|
2047
|
+
`${describePage(page)} is the only page, so it can't be removed.`
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
const target = pages[index > 0 ? index - 1 : 1];
|
|
2051
|
+
const merged = {
|
|
2052
|
+
...layout,
|
|
2053
|
+
pages: pages.filter((p) => p.key !== pageKey).map(
|
|
2054
|
+
(p) => p.key === target.key ? {
|
|
2055
|
+
...p,
|
|
2056
|
+
order: index > 0 ? [...p.order, ...page.order] : [...page.order, ...p.order],
|
|
2057
|
+
hidden: [...p.hidden, ...page.hidden],
|
|
2058
|
+
minimized: [...p.minimized, ...page.minimized]
|
|
2059
|
+
} : p
|
|
2060
|
+
)
|
|
2061
|
+
};
|
|
2062
|
+
const full = overflowing(
|
|
2063
|
+
definitions,
|
|
2064
|
+
merged,
|
|
2065
|
+
options
|
|
2066
|
+
);
|
|
2067
|
+
if (full !== void 0) {
|
|
2068
|
+
return err(
|
|
2069
|
+
`${describePage(page)} has widgets that don't fit on the other pages (${describePage(full)} would need more than ${rowsAllowed(full, options)} rows). Move or hide some first.`
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
return ok(merged);
|
|
2073
|
+
}
|
|
2074
|
+
function without(keys, key) {
|
|
2075
|
+
return keys.includes(key) ? keys.filter((k) => k !== key) : keys;
|
|
2076
|
+
}
|
|
2077
|
+
function moveWidgetToPage(definitions, layout, widgetKey, targetKey, options = {}) {
|
|
2078
|
+
const widget = definitions.find((d) => d.key === widgetKey);
|
|
2079
|
+
if (widget === void 0) {
|
|
2080
|
+
return err(
|
|
2081
|
+
`Widget "${widgetKey}" isn't one of the widgets, so it can't be moved to a page.`
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
const pages = pageList(layout);
|
|
2085
|
+
const target = pages.find((p) => p.key === targetKey);
|
|
2086
|
+
if (target === void 0) return err(`Page "${targetKey}" doesn't exist.`);
|
|
2087
|
+
const sourceKey = pageOf(definitions, layout, widgetKey);
|
|
2088
|
+
if (sourceKey === targetKey) return ok(layout);
|
|
2089
|
+
if (resolveWidgetLock(widget).move) {
|
|
2090
|
+
return err(
|
|
2091
|
+
`Widget "${titleOf(widget)}" is locked against moving, so it can't be moved to ${describePage(target)}.`
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2094
|
+
const base = withExplicitPages(layout);
|
|
2095
|
+
const source = (base.pages ?? []).find(
|
|
2096
|
+
(p) => p.key === sourceKey
|
|
2097
|
+
);
|
|
2098
|
+
const hidden = source.hidden.includes(widgetKey);
|
|
2099
|
+
const minimized = source.minimized.includes(widgetKey);
|
|
2100
|
+
const targetOrder = pageWidgets(
|
|
2101
|
+
definitions,
|
|
2102
|
+
base,
|
|
2103
|
+
targetKey
|
|
2104
|
+
).map((d) => d.key);
|
|
2105
|
+
const moved = {
|
|
2106
|
+
...base,
|
|
2107
|
+
pages: (base.pages ?? []).map((p) => {
|
|
2108
|
+
if (p.key === sourceKey) {
|
|
2109
|
+
return {
|
|
2110
|
+
...p,
|
|
2111
|
+
order: without(p.order, widgetKey),
|
|
2112
|
+
hidden: without(p.hidden, widgetKey),
|
|
2113
|
+
minimized: without(p.minimized, widgetKey)
|
|
2114
|
+
};
|
|
2115
|
+
}
|
|
2116
|
+
if (p.key === targetKey) {
|
|
2117
|
+
return {
|
|
2118
|
+
...p,
|
|
2119
|
+
order: hidden ? p.order : [...targetOrder, widgetKey],
|
|
2120
|
+
hidden: hidden ? [...p.hidden, widgetKey] : p.hidden,
|
|
2121
|
+
minimized: minimized ? [...p.minimized, widgetKey] : p.minimized
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
return p;
|
|
2125
|
+
})
|
|
2126
|
+
};
|
|
2127
|
+
if (!hidden) {
|
|
2128
|
+
const allowed = rowsAllowed(target, options);
|
|
2129
|
+
const needed = placeRows(
|
|
2130
|
+
pageWidgets(definitions, moved, targetKey)
|
|
2131
|
+
).length;
|
|
2132
|
+
if (needed > allowed) {
|
|
2133
|
+
return err(
|
|
2134
|
+
`${describePage(target)} has no room for "${titleOf(widget)}": it would need row ${needed}, and the page allows ${allowed}.`
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
return ok(moved);
|
|
1758
2139
|
}
|
|
1759
2140
|
function nextSort(current, column) {
|
|
1760
2141
|
if (current?.column !== column) return { column, direction: "asc" };
|
|
@@ -2035,6 +2416,25 @@ function useDetailData(definition, load, enabled, fallback) {
|
|
|
2035
2416
|
}, [enabled, load, fallback, definition, attempt]);
|
|
2036
2417
|
return { state, reload: () => setAttempt((count) => count + 1) };
|
|
2037
2418
|
}
|
|
2419
|
+
var NEW_PAGE_VALUE = "__new-page__";
|
|
2420
|
+
function PagePanel({
|
|
2421
|
+
paged,
|
|
2422
|
+
id,
|
|
2423
|
+
labelledBy,
|
|
2424
|
+
children
|
|
2425
|
+
}) {
|
|
2426
|
+
if (!paged) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
2427
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2428
|
+
"div",
|
|
2429
|
+
{
|
|
2430
|
+
role: "tabpanel",
|
|
2431
|
+
id,
|
|
2432
|
+
"aria-labelledby": labelledBy,
|
|
2433
|
+
className: "dwt-page-panel",
|
|
2434
|
+
children
|
|
2435
|
+
}
|
|
2436
|
+
);
|
|
2437
|
+
}
|
|
2038
2438
|
var NARROW_VIEWPORT_QUERY = "(max-width: 640px)";
|
|
2039
2439
|
var WIDE_GRID_PX = 900;
|
|
2040
2440
|
function useFillSpans(definitions, gridRef, twelve) {
|
|
@@ -2205,6 +2605,181 @@ function InlineConfirm({
|
|
|
2205
2605
|
}
|
|
2206
2606
|
);
|
|
2207
2607
|
}
|
|
2608
|
+
function PageTabs({
|
|
2609
|
+
pages,
|
|
2610
|
+
activeKey,
|
|
2611
|
+
idPrefix,
|
|
2612
|
+
panelId,
|
|
2613
|
+
announcement,
|
|
2614
|
+
onSelect
|
|
2615
|
+
}) {
|
|
2616
|
+
const slot = useSlotClassName();
|
|
2617
|
+
const { labels } = useWidgetSettings();
|
|
2618
|
+
const tabs = react.useRef(/* @__PURE__ */ new Map());
|
|
2619
|
+
const activeIndex = pages.findIndex((p) => p.key === activeKey);
|
|
2620
|
+
function onKeyDown(event, index) {
|
|
2621
|
+
const last = pages.length - 1;
|
|
2622
|
+
let next;
|
|
2623
|
+
switch (event.key) {
|
|
2624
|
+
case "ArrowRight":
|
|
2625
|
+
case "ArrowDown":
|
|
2626
|
+
next = index === last ? 0 : index + 1;
|
|
2627
|
+
break;
|
|
2628
|
+
case "ArrowLeft":
|
|
2629
|
+
case "ArrowUp":
|
|
2630
|
+
next = index === 0 ? last : index - 1;
|
|
2631
|
+
break;
|
|
2632
|
+
case "Home":
|
|
2633
|
+
next = 0;
|
|
2634
|
+
break;
|
|
2635
|
+
case "End":
|
|
2636
|
+
next = last;
|
|
2637
|
+
break;
|
|
2638
|
+
default:
|
|
2639
|
+
return;
|
|
2640
|
+
}
|
|
2641
|
+
event.preventDefault();
|
|
2642
|
+
const target = pages[next];
|
|
2643
|
+
if (target === void 0) return;
|
|
2644
|
+
onSelect(target.key);
|
|
2645
|
+
tabs.current.get(target.key)?.focus();
|
|
2646
|
+
}
|
|
2647
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: slot("pageBar", "dwt-pages"), children: [
|
|
2648
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2649
|
+
"button",
|
|
2650
|
+
{
|
|
2651
|
+
type: "button",
|
|
2652
|
+
className: slot(
|
|
2653
|
+
"button",
|
|
2654
|
+
"dwt-button",
|
|
2655
|
+
"dwt-icon-button",
|
|
2656
|
+
"dwt-page-nav"
|
|
2657
|
+
),
|
|
2658
|
+
"aria-label": labels.previousPageButton,
|
|
2659
|
+
disabled: activeIndex <= 0,
|
|
2660
|
+
onClick: () => onSelect(pages[activeIndex - 1].key),
|
|
2661
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2039" })
|
|
2662
|
+
}
|
|
2663
|
+
),
|
|
2664
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", "aria-label": labels.pageBar, className: "dwt-page-tabs", children: pages.map((page, index) => {
|
|
2665
|
+
const selected = page.key === activeKey;
|
|
2666
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2667
|
+
"button",
|
|
2668
|
+
{
|
|
2669
|
+
ref: (element) => {
|
|
2670
|
+
if (element === null) tabs.current.delete(page.key);
|
|
2671
|
+
else tabs.current.set(page.key, element);
|
|
2672
|
+
},
|
|
2673
|
+
type: "button",
|
|
2674
|
+
role: "tab",
|
|
2675
|
+
id: `${idPrefix}-tab-${index}`,
|
|
2676
|
+
"aria-selected": selected,
|
|
2677
|
+
"aria-controls": panelId,
|
|
2678
|
+
"aria-label": labels.pageTabName(
|
|
2679
|
+
index + 1,
|
|
2680
|
+
pages.length,
|
|
2681
|
+
page.title
|
|
2682
|
+
),
|
|
2683
|
+
title: page.title,
|
|
2684
|
+
tabIndex: selected ? 0 : -1,
|
|
2685
|
+
className: slot("button", "dwt-page-tab"),
|
|
2686
|
+
onClick: () => onSelect(page.key),
|
|
2687
|
+
onKeyDown: (event) => onKeyDown(event, index),
|
|
2688
|
+
children: [
|
|
2689
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-page-tab-title", children: page.title }),
|
|
2690
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-page-dot", "aria-hidden": "true" })
|
|
2691
|
+
]
|
|
2692
|
+
},
|
|
2693
|
+
page.key
|
|
2694
|
+
);
|
|
2695
|
+
}) }),
|
|
2696
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2697
|
+
"button",
|
|
2698
|
+
{
|
|
2699
|
+
type: "button",
|
|
2700
|
+
className: slot(
|
|
2701
|
+
"button",
|
|
2702
|
+
"dwt-button",
|
|
2703
|
+
"dwt-icon-button",
|
|
2704
|
+
"dwt-page-nav"
|
|
2705
|
+
),
|
|
2706
|
+
"aria-label": labels.nextPageButton,
|
|
2707
|
+
disabled: activeIndex === pages.length - 1,
|
|
2708
|
+
onClick: () => onSelect(pages[activeIndex + 1].key),
|
|
2709
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u203A" })
|
|
2710
|
+
}
|
|
2711
|
+
),
|
|
2712
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-visually-hidden", "aria-live": "polite", children: announcement })
|
|
2713
|
+
] });
|
|
2714
|
+
}
|
|
2715
|
+
function PageRenameForm({
|
|
2716
|
+
initial,
|
|
2717
|
+
onSubmit,
|
|
2718
|
+
onCancel
|
|
2719
|
+
}) {
|
|
2720
|
+
const slot = useSlotClassName();
|
|
2721
|
+
const { labels } = useWidgetSettings();
|
|
2722
|
+
const [title, setTitle] = react.useState(initial);
|
|
2723
|
+
const [error, setError] = react.useState(void 0);
|
|
2724
|
+
const inputRef = react.useRef(null);
|
|
2725
|
+
react.useEffect(() => {
|
|
2726
|
+
inputRef.current?.focus();
|
|
2727
|
+
inputRef.current?.select();
|
|
2728
|
+
}, []);
|
|
2729
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2730
|
+
"form",
|
|
2731
|
+
{
|
|
2732
|
+
className: "dwt-page-rename",
|
|
2733
|
+
onSubmit: (event) => {
|
|
2734
|
+
event.preventDefault();
|
|
2735
|
+
setError(onSubmit(title));
|
|
2736
|
+
},
|
|
2737
|
+
onKeyDown: (event) => {
|
|
2738
|
+
if (event.key === "Escape") {
|
|
2739
|
+
event.stopPropagation();
|
|
2740
|
+
onCancel();
|
|
2741
|
+
}
|
|
2742
|
+
},
|
|
2743
|
+
children: [
|
|
2744
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2745
|
+
"input",
|
|
2746
|
+
{
|
|
2747
|
+
ref: inputRef,
|
|
2748
|
+
type: "text",
|
|
2749
|
+
className: "dwt-page-title-input",
|
|
2750
|
+
"aria-label": labels.pageTitle,
|
|
2751
|
+
"aria-invalid": error !== void 0,
|
|
2752
|
+
maxLength: MAX_PAGE_TITLE_LENGTH,
|
|
2753
|
+
value: title,
|
|
2754
|
+
onChange: (event) => setTitle(event.target.value)
|
|
2755
|
+
}
|
|
2756
|
+
),
|
|
2757
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2758
|
+
"button",
|
|
2759
|
+
{
|
|
2760
|
+
type: "submit",
|
|
2761
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
2762
|
+
"aria-label": labels.savePageTitle,
|
|
2763
|
+
title: labels.savePageTitle,
|
|
2764
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2713" })
|
|
2765
|
+
}
|
|
2766
|
+
),
|
|
2767
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2768
|
+
"button",
|
|
2769
|
+
{
|
|
2770
|
+
type: "button",
|
|
2771
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
2772
|
+
"aria-label": labels.cancelPageTitle,
|
|
2773
|
+
title: labels.cancelPageTitle,
|
|
2774
|
+
onClick: onCancel,
|
|
2775
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2715" })
|
|
2776
|
+
}
|
|
2777
|
+
),
|
|
2778
|
+
error !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { role: "alert", className: "dwt-page-error", children: error })
|
|
2779
|
+
]
|
|
2780
|
+
}
|
|
2781
|
+
);
|
|
2782
|
+
}
|
|
2208
2783
|
function withoutLock(definition) {
|
|
2209
2784
|
if (definition.locked === void 0) return definition;
|
|
2210
2785
|
const copy = { ...definition };
|
|
@@ -2222,6 +2797,11 @@ function DashboardInner({
|
|
|
2222
2797
|
onEditingChange,
|
|
2223
2798
|
defaultLayout,
|
|
2224
2799
|
toolbar = true,
|
|
2800
|
+
activePage: activePageProp,
|
|
2801
|
+
defaultActivePage,
|
|
2802
|
+
onActivePageChange,
|
|
2803
|
+
maxRows,
|
|
2804
|
+
maxPages,
|
|
2225
2805
|
onRetry,
|
|
2226
2806
|
loadDetail,
|
|
2227
2807
|
onOpenDetail,
|
|
@@ -2237,8 +2817,19 @@ function DashboardInner({
|
|
|
2237
2817
|
const byKey = new Map(
|
|
2238
2818
|
widgets.map((w) => [w.definition.key, w])
|
|
2239
2819
|
);
|
|
2240
|
-
const
|
|
2241
|
-
const
|
|
2820
|
+
const pages = pageList(layout);
|
|
2821
|
+
const paged = pages.length >= 2;
|
|
2822
|
+
const [activeState, setActiveState] = react.useState(
|
|
2823
|
+
defaultActivePage
|
|
2824
|
+
);
|
|
2825
|
+
const requested = activePageProp ?? activeState;
|
|
2826
|
+
const activePage = pages.find((page) => page.key === requested) ?? pages[0];
|
|
2827
|
+
const activeKey = activePage.key;
|
|
2828
|
+
const pageDefs = assignPages(definitions, layout).get(activeKey) ?? [];
|
|
2829
|
+
const view = pageLayout(layout, activeKey) ?? layout;
|
|
2830
|
+
const roomOptions = maxRows === void 0 ? {} : { maxRows };
|
|
2831
|
+
const visible = visibleWidgets(pageDefs, view);
|
|
2832
|
+
const hidden = hiddenWidgets(pageDefs, view);
|
|
2242
2833
|
const editable = onLayoutChange !== void 0;
|
|
2243
2834
|
const toggleMode = editMode === "toggle";
|
|
2244
2835
|
const [editingState, setEditingState] = react.useState(defaultEditing);
|
|
@@ -2257,10 +2848,16 @@ function DashboardInner({
|
|
|
2257
2848
|
);
|
|
2258
2849
|
const pending = editing ? confirming : void 0;
|
|
2259
2850
|
const [announcement, setAnnouncement] = react.useState("");
|
|
2851
|
+
const [pageAnnouncement, setPageAnnouncement] = react.useState("");
|
|
2852
|
+
const [pageError, setPageError] = react.useState(void 0);
|
|
2853
|
+
const [pageEditor, setPageEditor] = react.useState(void 0);
|
|
2854
|
+
const editorMode = pageEditor?.key === activeKey ? pageEditor.mode : void 0;
|
|
2855
|
+
const instanceId = react.useId();
|
|
2856
|
+
const panelId = `${instanceId}-panel`;
|
|
2260
2857
|
const toggleRef = react.useRef(null);
|
|
2261
2858
|
const resetRef = react.useRef(null);
|
|
2262
|
-
const minimized = editable ? visible.filter((definition) => isMinimized(
|
|
2263
|
-
const shown = editable ? visible.filter((definition) => !isMinimized(
|
|
2859
|
+
const minimized = editable ? visible.filter((definition) => isMinimized(view, definition.key)) : [];
|
|
2860
|
+
const shown = editable ? visible.filter((definition) => !isMinimized(view, definition.key)) : visible;
|
|
2264
2861
|
const [detailKey, setDetailKey] = react.useState(void 0);
|
|
2265
2862
|
const gridRef = react.useRef(null);
|
|
2266
2863
|
const twelve = usesWidthColumns(shown);
|
|
@@ -2272,6 +2869,110 @@ function DashboardInner({
|
|
|
2272
2869
|
function change(next) {
|
|
2273
2870
|
if (next !== layout) onLayoutChange?.(next);
|
|
2274
2871
|
}
|
|
2872
|
+
function changePage(next) {
|
|
2873
|
+
setPageError(void 0);
|
|
2874
|
+
change(withPageLayout(layout, activeKey, next));
|
|
2875
|
+
}
|
|
2876
|
+
function selectPage(pageKey) {
|
|
2877
|
+
const index = pages.findIndex((page) => page.key === pageKey);
|
|
2878
|
+
if (index === -1) return;
|
|
2879
|
+
if (activePageProp === void 0) setActiveState(pageKey);
|
|
2880
|
+
onActivePageChange?.(pageKey);
|
|
2881
|
+
setPageError(void 0);
|
|
2882
|
+
setPageEditor(void 0);
|
|
2883
|
+
setPageAnnouncement(
|
|
2884
|
+
labels.pageTabName(
|
|
2885
|
+
index + 1,
|
|
2886
|
+
pages.length,
|
|
2887
|
+
pages[index].title
|
|
2888
|
+
)
|
|
2889
|
+
);
|
|
2890
|
+
}
|
|
2891
|
+
function addPageAction() {
|
|
2892
|
+
const added = addPage(layout);
|
|
2893
|
+
if (!added.ok) {
|
|
2894
|
+
setPageError(added.error);
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2897
|
+
change(added.value);
|
|
2898
|
+
const created = added.value.pages?.at(-1);
|
|
2899
|
+
if (created !== void 0) {
|
|
2900
|
+
if (activePageProp === void 0) setActiveState(created.key);
|
|
2901
|
+
onActivePageChange?.(created.key);
|
|
2902
|
+
setPageError(void 0);
|
|
2903
|
+
setPageEditor({ mode: "rename", key: created.key });
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
function renamePageAction(title) {
|
|
2907
|
+
const renamed = renamePage(layout, activeKey, title);
|
|
2908
|
+
if (!renamed.ok) return renamed.error;
|
|
2909
|
+
change(renamed.value);
|
|
2910
|
+
setPageEditor(void 0);
|
|
2911
|
+
return void 0;
|
|
2912
|
+
}
|
|
2913
|
+
function deletePageAction() {
|
|
2914
|
+
const index = pages.findIndex((page) => page.key === activeKey);
|
|
2915
|
+
const removed = removePage(definitions, layout, activeKey, roomOptions);
|
|
2916
|
+
setPageEditor(void 0);
|
|
2917
|
+
if (!removed.ok) {
|
|
2918
|
+
setPageError(removed.error);
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
const neighbor = pages[index > 0 ? index - 1 : 1];
|
|
2922
|
+
change(removed.value);
|
|
2923
|
+
if (neighbor !== void 0) selectPage(neighbor.key);
|
|
2924
|
+
}
|
|
2925
|
+
function moveWidgetAction(widgetKey, targetKey) {
|
|
2926
|
+
let target = targetKey;
|
|
2927
|
+
let base = layout;
|
|
2928
|
+
if (targetKey === NEW_PAGE_VALUE) {
|
|
2929
|
+
const added = addPage(layout);
|
|
2930
|
+
if (!added.ok) {
|
|
2931
|
+
setPageError(added.error);
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
base = added.value;
|
|
2935
|
+
target = (added.value.pages?.at(-1)).key;
|
|
2936
|
+
}
|
|
2937
|
+
const moved = moveWidgetToPage(
|
|
2938
|
+
definitions,
|
|
2939
|
+
base,
|
|
2940
|
+
widgetKey,
|
|
2941
|
+
target,
|
|
2942
|
+
roomOptions
|
|
2943
|
+
);
|
|
2944
|
+
if (!moved.ok) {
|
|
2945
|
+
setPageError(moved.error);
|
|
2946
|
+
return;
|
|
2947
|
+
}
|
|
2948
|
+
setPageError(void 0);
|
|
2949
|
+
change(moved.value);
|
|
2950
|
+
const destination = moved.value.pages?.find(
|
|
2951
|
+
(page) => page.key === target
|
|
2952
|
+
);
|
|
2953
|
+
setPageAnnouncement(
|
|
2954
|
+
labels.movedToPage(
|
|
2955
|
+
byKey.get(widgetKey)?.definition.title ?? widgetKey,
|
|
2956
|
+
destination?.title ?? target
|
|
2957
|
+
)
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2960
|
+
function showAction(widgetKey) {
|
|
2961
|
+
const next = withPageLayout(
|
|
2962
|
+
layout,
|
|
2963
|
+
activeKey,
|
|
2964
|
+
showWidget(view, widgetKey)
|
|
2965
|
+
);
|
|
2966
|
+
if (hasPages(next)) {
|
|
2967
|
+
const room = pageRoom(definitions, next, activeKey, roomOptions);
|
|
2968
|
+
if (room !== void 0 && room.rowsUsed > room.maxRows) {
|
|
2969
|
+
setPageError(labels.pageFull(activePage.title, room.maxRows));
|
|
2970
|
+
return;
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
setPageError(void 0);
|
|
2974
|
+
change(next);
|
|
2975
|
+
}
|
|
2275
2976
|
function setEditing(next) {
|
|
2276
2977
|
if (editingProp === void 0) setEditingState(next);
|
|
2277
2978
|
onEditingChange?.(next);
|
|
@@ -2349,176 +3050,312 @@ function DashboardInner({
|
|
|
2349
3050
|
]
|
|
2350
3051
|
}
|
|
2351
3052
|
),
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
]
|
|
2365
|
-
},
|
|
2366
|
-
definition.key
|
|
2367
|
-
))
|
|
2368
|
-
] }),
|
|
2369
|
-
minimized.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3053
|
+
paged && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3054
|
+
PageTabs,
|
|
3055
|
+
{
|
|
3056
|
+
pages,
|
|
3057
|
+
activeKey,
|
|
3058
|
+
idPrefix: instanceId,
|
|
3059
|
+
panelId,
|
|
3060
|
+
announcement: pageAnnouncement,
|
|
3061
|
+
onSelect: selectPage
|
|
3062
|
+
}
|
|
3063
|
+
),
|
|
3064
|
+
controlsShown && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2370
3065
|
"div",
|
|
2371
3066
|
{
|
|
2372
|
-
|
|
3067
|
+
role: "group",
|
|
3068
|
+
"aria-label": labels.managePages,
|
|
3069
|
+
className: "dwt-page-manage",
|
|
2373
3070
|
children: [
|
|
2374
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2375
|
-
minimized.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3071
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2376
3072
|
"button",
|
|
2377
3073
|
{
|
|
2378
3074
|
type: "button",
|
|
2379
|
-
className: slot("button", "dwt-button"
|
|
2380
|
-
|
|
2381
|
-
onClick:
|
|
2382
|
-
children:
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
3075
|
+
className: slot("button", "dwt-button"),
|
|
3076
|
+
disabled: maxPages !== void 0 && pages.length >= maxPages,
|
|
3077
|
+
onClick: addPageAction,
|
|
3078
|
+
children: labels.addPage
|
|
3079
|
+
}
|
|
3080
|
+
),
|
|
3081
|
+
paged && editorMode === "rename" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3082
|
+
PageRenameForm,
|
|
3083
|
+
{
|
|
3084
|
+
initial: activePage.title,
|
|
3085
|
+
onSubmit: renamePageAction,
|
|
3086
|
+
onCancel: () => setPageEditor(void 0)
|
|
2386
3087
|
},
|
|
2387
|
-
|
|
2388
|
-
)
|
|
3088
|
+
activeKey
|
|
3089
|
+
),
|
|
3090
|
+
paged && editorMode !== "rename" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3091
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3092
|
+
"button",
|
|
3093
|
+
{
|
|
3094
|
+
type: "button",
|
|
3095
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3096
|
+
"aria-label": labels.renamePage(activePage.title),
|
|
3097
|
+
title: labels.renamePage(activePage.title),
|
|
3098
|
+
onClick: () => setPageEditor({ mode: "rename", key: activeKey }),
|
|
3099
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u270E" })
|
|
3100
|
+
}
|
|
3101
|
+
),
|
|
3102
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3103
|
+
"button",
|
|
3104
|
+
{
|
|
3105
|
+
type: "button",
|
|
3106
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3107
|
+
"aria-label": labels.movePageLeft(activePage.title),
|
|
3108
|
+
title: labels.movePageLeft(activePage.title),
|
|
3109
|
+
disabled: pages[0]?.key === activeKey,
|
|
3110
|
+
onClick: () => change(movePage(layout, activeKey, -1)),
|
|
3111
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2190" })
|
|
3112
|
+
}
|
|
3113
|
+
),
|
|
3114
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3115
|
+
"button",
|
|
3116
|
+
{
|
|
3117
|
+
type: "button",
|
|
3118
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3119
|
+
"aria-label": labels.movePageRight(activePage.title),
|
|
3120
|
+
title: labels.movePageRight(activePage.title),
|
|
3121
|
+
disabled: pages.at(-1)?.key === activeKey,
|
|
3122
|
+
onClick: () => change(movePage(layout, activeKey, 1)),
|
|
3123
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2192" })
|
|
3124
|
+
}
|
|
3125
|
+
),
|
|
3126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3127
|
+
"button",
|
|
3128
|
+
{
|
|
3129
|
+
type: "button",
|
|
3130
|
+
className: slot("button", "dwt-button", "dwt-icon-button"),
|
|
3131
|
+
"aria-label": labels.deletePage(activePage.title),
|
|
3132
|
+
title: labels.deletePage(activePage.title),
|
|
3133
|
+
onClick: () => setPageEditor({ mode: "delete", key: activeKey }),
|
|
3134
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\xD7" })
|
|
3135
|
+
}
|
|
3136
|
+
)
|
|
3137
|
+
] }),
|
|
3138
|
+
paged && editorMode === "delete" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3139
|
+
InlineConfirm,
|
|
3140
|
+
{
|
|
3141
|
+
message: labels.confirmDeletePage(activePage.title),
|
|
3142
|
+
onAnswer: (yes) => yes ? deletePageAction() : setPageEditor(void 0)
|
|
3143
|
+
}
|
|
3144
|
+
),
|
|
3145
|
+
pageError !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { role: "alert", className: "dwt-page-error", children: pageError })
|
|
2389
3146
|
]
|
|
2390
3147
|
}
|
|
2391
3148
|
),
|
|
2392
|
-
|
|
2393
|
-
|
|
3149
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3150
|
+
PagePanel,
|
|
2394
3151
|
{
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
const title = definition.title;
|
|
2404
|
-
const lock = resolveWidgetLock(definition);
|
|
2405
|
-
const ownLock = resolveWidgetLock(
|
|
2406
|
-
widget.definition
|
|
2407
|
-
);
|
|
2408
|
-
const isLocked = ownLock.move || ownLock.hide || ownLock.minimize;
|
|
2409
|
-
const lockLabel = overrideLocks ? labels.lockedForViewers(title) : labels.locked(title);
|
|
2410
|
-
const canMoveEarlier = !lock.move && moveWidgetBy(definitions, layout, key, -1) !== layout;
|
|
2411
|
-
const canMoveLater = !lock.move && moveWidgetBy(definitions, layout, key, 1) !== layout;
|
|
2412
|
-
const actions = controlsShown ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2413
|
-
isLocked && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2414
|
-
"span",
|
|
3152
|
+
paged,
|
|
3153
|
+
id: panelId,
|
|
3154
|
+
labelledBy: `${instanceId}-tab-${pages.findIndex((p) => p.key === activeKey)}`,
|
|
3155
|
+
children: [
|
|
3156
|
+
controlsShown && hidden.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: slot("hiddenBar", "dwt-hidden-bar"), children: [
|
|
3157
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-hidden-label", children: labels.hiddenWidgets }),
|
|
3158
|
+
hidden.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3159
|
+
"button",
|
|
2415
3160
|
{
|
|
2416
|
-
|
|
2417
|
-
className: "dwt-
|
|
2418
|
-
"aria-label":
|
|
2419
|
-
|
|
2420
|
-
children:
|
|
2421
|
-
"
|
|
3161
|
+
type: "button",
|
|
3162
|
+
className: slot("button", "dwt-button", "dwt-show-button"),
|
|
3163
|
+
"aria-label": labels.show(definition.title),
|
|
3164
|
+
onClick: () => showAction(definition.key),
|
|
3165
|
+
children: [
|
|
3166
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "+ " }),
|
|
3167
|
+
definition.title
|
|
3168
|
+
]
|
|
3169
|
+
},
|
|
3170
|
+
definition.key
|
|
3171
|
+
))
|
|
3172
|
+
] }),
|
|
3173
|
+
minimized.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3174
|
+
"div",
|
|
3175
|
+
{
|
|
3176
|
+
className: slot("hiddenBar", "dwt-hidden-bar", "dwt-minimized-bar"),
|
|
3177
|
+
children: [
|
|
3178
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-hidden-label", children: labels.minimizedWidgets }),
|
|
3179
|
+
minimized.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3180
|
+
"button",
|
|
2422
3181
|
{
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
focusable: "false",
|
|
3182
|
+
type: "button",
|
|
3183
|
+
className: slot("button", "dwt-button", "dwt-show-button"),
|
|
3184
|
+
"aria-label": labels.expand(definition.title),
|
|
3185
|
+
onClick: () => changePage(toggleMinimized(view, definition.key)),
|
|
2428
3186
|
children: [
|
|
2429
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
3187
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u25B8 " }),
|
|
3188
|
+
definition.title
|
|
3189
|
+
]
|
|
3190
|
+
},
|
|
3191
|
+
definition.key
|
|
3192
|
+
))
|
|
3193
|
+
]
|
|
3194
|
+
}
|
|
3195
|
+
),
|
|
3196
|
+
visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: paged && pageDefs.length === 0 ? labels.emptyPage : definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : shown.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3197
|
+
"div",
|
|
3198
|
+
{
|
|
3199
|
+
ref: gridRef,
|
|
3200
|
+
className: slot("grid", "dwt-grid", twelve && "dwt-grid--twelve"),
|
|
3201
|
+
children: shown.map((definition, index) => {
|
|
3202
|
+
const widget = byKey.get(
|
|
3203
|
+
definition.key
|
|
3204
|
+
);
|
|
3205
|
+
if (widget === void 0) return null;
|
|
3206
|
+
const key = definition.key;
|
|
3207
|
+
const title = definition.title;
|
|
3208
|
+
const lock = resolveWidgetLock(definition);
|
|
3209
|
+
const ownLock = resolveWidgetLock(
|
|
3210
|
+
widget.definition
|
|
3211
|
+
);
|
|
3212
|
+
const isLocked = ownLock.move || ownLock.hide || ownLock.minimize;
|
|
3213
|
+
const lockLabel = overrideLocks ? labels.lockedForViewers(title) : labels.locked(title);
|
|
3214
|
+
const canMoveEarlier = !lock.move && moveWidgetBy(pageDefs, view, key, -1) !== view;
|
|
3215
|
+
const canMoveLater = !lock.move && moveWidgetBy(pageDefs, view, key, 1) !== view;
|
|
3216
|
+
const actions = controlsShown ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3217
|
+
isLocked && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3218
|
+
"span",
|
|
3219
|
+
{
|
|
3220
|
+
role: "img",
|
|
3221
|
+
className: "dwt-lock",
|
|
3222
|
+
"aria-label": lockLabel,
|
|
3223
|
+
title: lockLabel,
|
|
3224
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3225
|
+
"svg",
|
|
2442
3226
|
{
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
3227
|
+
viewBox: "0 0 16 16",
|
|
3228
|
+
width: "14",
|
|
3229
|
+
height: "14",
|
|
3230
|
+
"aria-hidden": "true",
|
|
3231
|
+
focusable: "false",
|
|
3232
|
+
children: [
|
|
3233
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3234
|
+
"rect",
|
|
3235
|
+
{
|
|
3236
|
+
x: "3",
|
|
3237
|
+
y: "7",
|
|
3238
|
+
width: "10",
|
|
3239
|
+
height: "7",
|
|
3240
|
+
rx: "1.5",
|
|
3241
|
+
fill: "currentColor"
|
|
3242
|
+
}
|
|
3243
|
+
),
|
|
3244
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3245
|
+
"path",
|
|
3246
|
+
{
|
|
3247
|
+
d: "M5.5 7V5a2.5 2.5 0 0 1 5 0v2",
|
|
3248
|
+
fill: "none",
|
|
3249
|
+
stroke: "currentColor",
|
|
3250
|
+
strokeWidth: "1.4"
|
|
3251
|
+
}
|
|
3252
|
+
)
|
|
3253
|
+
]
|
|
2447
3254
|
}
|
|
2448
3255
|
)
|
|
2449
|
-
|
|
2450
|
-
}
|
|
2451
|
-
)
|
|
2452
|
-
}
|
|
2453
|
-
),
|
|
2454
|
-
!lock.move && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2455
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2456
|
-
"button",
|
|
2457
|
-
{
|
|
2458
|
-
type: "button",
|
|
2459
|
-
className: slot(
|
|
2460
|
-
"button",
|
|
2461
|
-
"dwt-button",
|
|
2462
|
-
"dwt-icon-button"
|
|
3256
|
+
}
|
|
2463
3257
|
),
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
3258
|
+
!lock.move && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3259
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3260
|
+
"button",
|
|
3261
|
+
{
|
|
3262
|
+
type: "button",
|
|
3263
|
+
className: slot(
|
|
3264
|
+
"button",
|
|
3265
|
+
"dwt-button",
|
|
3266
|
+
"dwt-icon-button"
|
|
3267
|
+
),
|
|
3268
|
+
"aria-label": labels.moveEarlier(title),
|
|
3269
|
+
title: labels.moveEarlier(title),
|
|
3270
|
+
disabled: index === 0 || !canMoveEarlier,
|
|
3271
|
+
onClick: () => changePage(moveWidgetBy(pageDefs, view, key, -1)),
|
|
3272
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2191" })
|
|
3273
|
+
}
|
|
3274
|
+
),
|
|
3275
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3276
|
+
"button",
|
|
3277
|
+
{
|
|
3278
|
+
type: "button",
|
|
3279
|
+
className: slot(
|
|
3280
|
+
"button",
|
|
3281
|
+
"dwt-button",
|
|
3282
|
+
"dwt-icon-button"
|
|
3283
|
+
),
|
|
3284
|
+
"aria-label": labels.moveLater(title),
|
|
3285
|
+
title: labels.moveLater(title),
|
|
3286
|
+
disabled: index === shown.length - 1 || !canMoveLater,
|
|
3287
|
+
onClick: () => changePage(moveWidgetBy(pageDefs, view, key, 1)),
|
|
3288
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2193" })
|
|
3289
|
+
}
|
|
3290
|
+
),
|
|
3291
|
+
paged && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3292
|
+
"select",
|
|
3293
|
+
{
|
|
3294
|
+
className: "dwt-move-select",
|
|
3295
|
+
"aria-label": labels.moveToPage(title),
|
|
3296
|
+
value: "",
|
|
3297
|
+
onChange: (event) => {
|
|
3298
|
+
if (event.target.value !== "") {
|
|
3299
|
+
moveWidgetAction(key, event.target.value);
|
|
3300
|
+
}
|
|
3301
|
+
},
|
|
3302
|
+
children: [
|
|
3303
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: labels.moveToPagePlaceholder }),
|
|
3304
|
+
pages.filter((page) => page.key !== activeKey).map((page) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: page.key, children: labels.moveToPageOption(
|
|
3305
|
+
page.title,
|
|
3306
|
+
pageRoom(
|
|
3307
|
+
definitions,
|
|
3308
|
+
layout,
|
|
3309
|
+
page.key,
|
|
3310
|
+
roomOptions
|
|
3311
|
+
)?.rowsFree ?? 0
|
|
3312
|
+
) }, page.key)),
|
|
3313
|
+
(maxPages === void 0 || pages.length < maxPages) && /* @__PURE__ */ jsxRuntime.jsx("option", { value: NEW_PAGE_VALUE, children: labels.newPageOption })
|
|
3314
|
+
]
|
|
3315
|
+
}
|
|
3316
|
+
)
|
|
3317
|
+
] }),
|
|
3318
|
+
!lock.hide && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2476
3319
|
"button",
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
...headingLevel === void 0 ? {} : { headingLevel },
|
|
2517
|
-
...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
|
|
2518
|
-
},
|
|
2519
|
-
key
|
|
2520
|
-
);
|
|
2521
|
-
})
|
|
3320
|
+
{
|
|
3321
|
+
type: "button",
|
|
3322
|
+
className: slot(
|
|
3323
|
+
"button",
|
|
3324
|
+
"dwt-button",
|
|
3325
|
+
"dwt-icon-button"
|
|
3326
|
+
),
|
|
3327
|
+
"aria-label": labels.hide(title),
|
|
3328
|
+
title: labels.hide(title),
|
|
3329
|
+
onClick: () => changePage(hideWidget(view, key)),
|
|
3330
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\xD7" })
|
|
3331
|
+
}
|
|
3332
|
+
)
|
|
3333
|
+
] }) : void 0;
|
|
3334
|
+
const viewable = resolveDetailOptions(definition) !== void 0 && (onOpenDetail !== void 0 || loadDetail !== void 0 || widget.status === "ok" && deriveDetailData(widget.data) !== void 0);
|
|
3335
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3336
|
+
ResolvedWidgetCard,
|
|
3337
|
+
{
|
|
3338
|
+
widget,
|
|
3339
|
+
...viewable ? {
|
|
3340
|
+
onView: () => onOpenDetail === void 0 ? setDetailKey(key) : onOpenDetail(key)
|
|
3341
|
+
} : {},
|
|
3342
|
+
...spanProps(spans, key),
|
|
3343
|
+
...widthProps(twelve, definition),
|
|
3344
|
+
minimized: isMinimized(view, key),
|
|
3345
|
+
editing: toggleMode && controlsShown,
|
|
3346
|
+
...actions === void 0 ? {} : { actions },
|
|
3347
|
+
...editable && !lock.minimize ? {
|
|
3348
|
+
onToggleMinimized: () => changePage(toggleMinimized(view, key))
|
|
3349
|
+
} : {},
|
|
3350
|
+
...headingLevel === void 0 ? {} : { headingLevel },
|
|
3351
|
+
...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
|
|
3352
|
+
},
|
|
3353
|
+
key
|
|
3354
|
+
);
|
|
3355
|
+
})
|
|
3356
|
+
}
|
|
3357
|
+
)
|
|
3358
|
+
]
|
|
2522
3359
|
}
|
|
2523
3360
|
),
|
|
2524
3361
|
detailKey !== void 0 && byKey.get(detailKey) !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3177,8 +4014,21 @@ function useWidgets(definitions, providers, context, options = {}) {
|
|
|
3177
4014
|
},
|
|
3178
4015
|
{ rootMargin }
|
|
3179
4016
|
);
|
|
3180
|
-
|
|
3181
|
-
|
|
4017
|
+
const observed = /* @__PURE__ */ new WeakSet();
|
|
4018
|
+
const observeNewCards = () => {
|
|
4019
|
+
grid.querySelectorAll("[data-widget-key]").forEach((card) => {
|
|
4020
|
+
if (observed.has(card)) return;
|
|
4021
|
+
observed.add(card);
|
|
4022
|
+
observer.observe(card);
|
|
4023
|
+
});
|
|
4024
|
+
};
|
|
4025
|
+
observeNewCards();
|
|
4026
|
+
const mutations = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(observeNewCards);
|
|
4027
|
+
mutations?.observe(grid, { childList: true, subtree: true });
|
|
4028
|
+
return () => {
|
|
4029
|
+
mutations?.disconnect();
|
|
4030
|
+
observer.disconnect();
|
|
4031
|
+
};
|
|
3182
4032
|
}, [loader, loadWhen, rootMargin, cardKeys]);
|
|
3183
4033
|
react.useEffect(() => {
|
|
3184
4034
|
if (loader === null || !(refreshMs > 0)) return void 0;
|