@dbcdk/react-components 0.0.158 → 0.0.159
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/components/accordion/components/AccordionRow.cjs +1 -1
- package/dist/components/accordion/components/AccordionRow.js +1 -1
- package/dist/components/breadcrumbs/Breadcrumbs.module.css +3 -6
- package/dist/components/nav-bar/NavBar.cjs +4 -1
- package/dist/components/nav-bar/NavBar.js +4 -1
- package/dist/components/nav-bar/NavBar.module.css +18 -0
- package/dist/components/sidebar/Sidebar.cjs +2 -0
- package/dist/components/sidebar/Sidebar.d.ts +1 -1
- package/dist/components/sidebar/Sidebar.js +2 -0
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.cjs +6 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.d.ts +1 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.js +6 -1
- package/dist/components/sidebar/components/sidebar-container/SidebarContainer.module.css +30 -2
- package/dist/components/table/Table.cjs +17 -3
- package/dist/components/table/Table.d.ts +1 -1
- package/dist/components/table/Table.js +18 -4
- package/dist/components/table/Table.module.css +41 -44
- package/dist/components/table/Table.types.d.ts +1 -1
- package/dist/components/table/components/TableBody.cjs +9 -5
- package/dist/components/table/components/TableBody.d.ts +4 -2
- package/dist/components/table/components/TableBody.js +9 -5
- package/dist/components/table/components/TableRow.cjs +39 -18
- package/dist/components/table/components/TableRow.d.ts +4 -1
- package/dist/components/table/components/TableRow.js +40 -19
- package/dist/components/table/components/table-settings/TableSettings.cjs +1 -1
- package/dist/components/table/components/table-settings/TableSettings.js +2 -2
- package/dist/components/table/table.utils.cjs +2 -0
- package/dist/components/table/table.utils.d.ts +1 -0
- package/dist/components/table/table.utils.js +2 -1
- package/dist/styles/themes/dbc/colors.css +6 -0
- package/dist/styles/themes/filmstriben-budget/theme.css +22 -0
- package/dist/themes/filmstriben-budget.css +3 -0
- package/dist/utils/date/formatDate.cjs +15 -1
- package/dist/utils/date/formatDate.d.ts +9 -1
- package/dist/utils/date/formatDate.js +15 -1
- package/package.json +1 -1
|
@@ -57,7 +57,7 @@ function AccordionRow({
|
|
|
57
57
|
renderMode = "lazy"
|
|
58
58
|
}) {
|
|
59
59
|
const isDisabled = !!item.disabled;
|
|
60
|
-
const headlineWeight =
|
|
60
|
+
const headlineWeight = variant === "outlined" ? 400 : 500;
|
|
61
61
|
const buttonId = `${uid}-acc-btn-${index}`;
|
|
62
62
|
const panelId = `${uid}-acc-panel-${index}`;
|
|
63
63
|
const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen, shouldAnimate);
|
|
@@ -51,7 +51,7 @@ function AccordionRow({
|
|
|
51
51
|
renderMode = "lazy"
|
|
52
52
|
}) {
|
|
53
53
|
const isDisabled = !!item.disabled;
|
|
54
|
-
const headlineWeight =
|
|
54
|
+
const headlineWeight = variant === "outlined" ? 400 : 500;
|
|
55
55
|
const buttonId = `${uid}-acc-btn-${index}`;
|
|
56
56
|
const panelId = `${uid}-acc-panel-${index}`;
|
|
57
57
|
const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen, shouldAnimate);
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
.breadcrumbs ul {
|
|
6
6
|
display: flex;
|
|
7
7
|
align-items: center;
|
|
8
|
+
gap: var(--spacing-xs);
|
|
8
9
|
list-style: none;
|
|
9
10
|
margin: 0;
|
|
10
11
|
padding: 0;
|
|
@@ -17,7 +18,7 @@
|
|
|
17
18
|
gap: var(--spacing-xxs);
|
|
18
19
|
padding-block: calc(var(--spacing-xxs) + var(--density));
|
|
19
20
|
padding-inline: 0;
|
|
20
|
-
color: var(--color-fg-
|
|
21
|
+
color: var(--color-fg-muted);
|
|
21
22
|
border-radius: var(--border-radius-sm);
|
|
22
23
|
position: relative;
|
|
23
24
|
transition:
|
|
@@ -27,7 +28,6 @@
|
|
|
27
28
|
|
|
28
29
|
.breadcrumbs li:hover button {
|
|
29
30
|
color: var(--color-fg-default);
|
|
30
|
-
background-color: var(--color-bg-contextual);
|
|
31
31
|
cursor: pointer;
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -39,14 +39,12 @@
|
|
|
39
39
|
|
|
40
40
|
.breadcrumbs li[aria-current='page'] button,
|
|
41
41
|
.breadcrumbs li:last-of-type button {
|
|
42
|
-
background-color: var(--color-bg-contextual) !important;
|
|
43
42
|
font-weight: var(--font-weight-medium);
|
|
44
43
|
}
|
|
45
44
|
|
|
46
45
|
.separator {
|
|
47
46
|
display: flex;
|
|
48
47
|
align-items: center;
|
|
49
|
-
padding: 0 var(--spacing-xs);
|
|
50
48
|
color: var(--color-fg-subtle);
|
|
51
49
|
font-size: var(--font-size-md);
|
|
52
50
|
}
|
|
@@ -62,8 +60,7 @@
|
|
|
62
60
|
all: unset;
|
|
63
61
|
color: inherit;
|
|
64
62
|
border-radius: var(--border-radius-default);
|
|
65
|
-
|
|
66
|
-
padding: var(--spacing-xxs) var(--spacing-sm);
|
|
63
|
+
padding-block: var(--spacing-xxs);
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
.breadcrumbs a:focus-visible,
|
|
@@ -48,7 +48,10 @@ function NavBar({
|
|
|
48
48
|
});
|
|
49
49
|
const productNameContent = productName ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
50
50
|
/* @__PURE__ */ jsxRuntime.jsx(logo.Logo, {}),
|
|
51
|
-
/* @__PURE__ */ jsxRuntime.
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.productNameLabel, children: [
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.productNameSquare }),
|
|
53
|
+
/* @__PURE__ */ jsxRuntime.jsx(Headline.Headline, { disableMargin: true, size: 1, children: productName })
|
|
54
|
+
] })
|
|
52
55
|
] }) : null;
|
|
53
56
|
const productNameNode = (() => {
|
|
54
57
|
if (!productName || !productNameContent) return null;
|
|
@@ -42,7 +42,10 @@ function NavBar({
|
|
|
42
42
|
});
|
|
43
43
|
const productNameContent = productName ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
44
44
|
/* @__PURE__ */ jsx(Logo, {}),
|
|
45
|
-
/* @__PURE__ */
|
|
45
|
+
/* @__PURE__ */ jsxs("span", { className: styles.productNameLabel, children: [
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: styles.productNameSquare }),
|
|
47
|
+
/* @__PURE__ */ jsx(Headline, { disableMargin: true, size: 1, children: productName })
|
|
48
|
+
] })
|
|
46
49
|
] }) : null;
|
|
47
50
|
const productNameNode = (() => {
|
|
48
51
|
if (!productName || !productNameContent) return null;
|
|
@@ -111,6 +111,24 @@
|
|
|
111
111
|
color: inherit;
|
|
112
112
|
text-decoration: none;
|
|
113
113
|
}
|
|
114
|
+
|
|
115
|
+
.productNameLabel {
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: var(--spacing-xs);
|
|
119
|
+
color: var(--color-fg-default);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.productNameSquare {
|
|
123
|
+
inline-size: 5px;
|
|
124
|
+
block-size: 5px;
|
|
125
|
+
flex: 0 0 auto;
|
|
126
|
+
background-color: var(--color-logo);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.productNameLabel h1 {
|
|
130
|
+
font-size: var(--font-size-sm);
|
|
131
|
+
}
|
|
114
132
|
.productName svg {
|
|
115
133
|
inline-size: auto;
|
|
116
134
|
block-size: var(--icon-size-md);
|
|
@@ -6,6 +6,7 @@ var SidebarProvider = require('./providers/SidebarProvider');
|
|
|
6
6
|
|
|
7
7
|
function Sidebar({
|
|
8
8
|
items,
|
|
9
|
+
productName,
|
|
9
10
|
productLogo,
|
|
10
11
|
activeLink,
|
|
11
12
|
version,
|
|
@@ -21,6 +22,7 @@ function Sidebar({
|
|
|
21
22
|
return /* @__PURE__ */ jsxRuntime.jsx(SidebarProvider.SidebarProvider, { items, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
22
23
|
SidebarContainer.SidebarContainer,
|
|
23
24
|
{
|
|
25
|
+
productName,
|
|
24
26
|
productLogo,
|
|
25
27
|
activeLink,
|
|
26
28
|
version,
|
|
@@ -19,5 +19,5 @@ interface SidebarProps {
|
|
|
19
19
|
minWidth?: number;
|
|
20
20
|
storageKey?: string;
|
|
21
21
|
}
|
|
22
|
-
export declare function Sidebar({ items, productLogo, activeLink, version, hideSearch, searchPlaceholder, showSettings, footer, resizable, defaultWidth, minWidth, storageKey, }: SidebarProps): JSX.Element;
|
|
22
|
+
export declare function Sidebar({ items, productName, productLogo, activeLink, version, hideSearch, searchPlaceholder, showSettings, footer, resizable, defaultWidth, minWidth, storageKey, }: SidebarProps): JSX.Element;
|
|
23
23
|
export {};
|
|
@@ -4,6 +4,7 @@ import { SidebarProvider } from './providers/SidebarProvider';
|
|
|
4
4
|
|
|
5
5
|
function Sidebar({
|
|
6
6
|
items,
|
|
7
|
+
productName,
|
|
7
8
|
productLogo,
|
|
8
9
|
activeLink,
|
|
9
10
|
version,
|
|
@@ -19,6 +20,7 @@ function Sidebar({
|
|
|
19
20
|
return /* @__PURE__ */ jsx(SidebarProvider, { items, children: /* @__PURE__ */ jsx(
|
|
20
21
|
SidebarContainer,
|
|
21
22
|
{
|
|
23
|
+
productName,
|
|
22
24
|
productLogo,
|
|
23
25
|
activeLink,
|
|
24
26
|
version,
|
|
@@ -6,6 +6,7 @@ var lucideReact = require('lucide-react');
|
|
|
6
6
|
var react = require('react');
|
|
7
7
|
var logo = require('../../../../assets/logo');
|
|
8
8
|
var Button = require('../../../../components/button/Button');
|
|
9
|
+
var Headline = require('../../../../components/headline/Headline');
|
|
9
10
|
var SidebarItems = require('../../../../components/sidebar/components/sidebar-items/SidebarItems');
|
|
10
11
|
var SidenavFiltering = require('../../../../components/sidebar/components/sidenav-filteirng/SidenavFiltering');
|
|
11
12
|
var SidebarProvider = require('../../../../components/sidebar/providers/SidebarProvider');
|
|
@@ -43,6 +44,7 @@ function removeStoredWidth(key) {
|
|
|
43
44
|
}
|
|
44
45
|
function SidebarContainer({
|
|
45
46
|
logo: logo$1,
|
|
47
|
+
productName,
|
|
46
48
|
productLogo,
|
|
47
49
|
activeLink,
|
|
48
50
|
version,
|
|
@@ -165,7 +167,10 @@ function SidebarContainer({
|
|
|
165
167
|
style: containerStyle,
|
|
166
168
|
children: [
|
|
167
169
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.header, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.productHeader, children: [
|
|
168
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.productLogo, children: productLogo }),
|
|
170
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.productGroup, children: productLogo ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.productLogo, children: productLogo }) : productName && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.productNameLabel, children: [
|
|
171
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.productNameSquare }),
|
|
172
|
+
/* @__PURE__ */ jsxRuntime.jsx(Headline.Headline, { disableMargin: true, size: 1, allowWrap: false, children: productName })
|
|
173
|
+
] }) }),
|
|
169
174
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
170
175
|
Button.Button,
|
|
171
176
|
{
|
|
@@ -14,5 +14,5 @@ interface SidebarContainerProps {
|
|
|
14
14
|
minWidth?: number;
|
|
15
15
|
storageKey?: string;
|
|
16
16
|
}
|
|
17
|
-
export declare function SidebarContainer({ logo, productLogo, activeLink, version, hideSearch, searchPlaceholder, showSettings, footer, resizable, defaultWidth, minWidth, storageKey, }: SidebarContainerProps): JSX.Element;
|
|
17
|
+
export declare function SidebarContainer({ logo, productName, productLogo, activeLink, version, hideSearch, searchPlaceholder, showSettings, footer, resizable, defaultWidth, minWidth, storageKey, }: SidebarContainerProps): JSX.Element;
|
|
18
18
|
export {};
|
|
@@ -4,6 +4,7 @@ import { PanelLeftOpen, PanelLeft } from 'lucide-react';
|
|
|
4
4
|
import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
5
5
|
import { Logo } from '../../../../assets/logo';
|
|
6
6
|
import { Button } from '../../../../components/button/Button';
|
|
7
|
+
import { Headline } from '../../../../components/headline/Headline';
|
|
7
8
|
import { SidebarItems } from '../../../../components/sidebar/components/sidebar-items/SidebarItems';
|
|
8
9
|
import SidenavFiltering from '../../../../components/sidebar/components/sidenav-filteirng/SidenavFiltering';
|
|
9
10
|
import { useSidebar } from '../../../../components/sidebar/providers/SidebarProvider';
|
|
@@ -36,6 +37,7 @@ function removeStoredWidth(key) {
|
|
|
36
37
|
}
|
|
37
38
|
function SidebarContainer({
|
|
38
39
|
logo,
|
|
40
|
+
productName,
|
|
39
41
|
productLogo,
|
|
40
42
|
activeLink,
|
|
41
43
|
version,
|
|
@@ -158,7 +160,10 @@ function SidebarContainer({
|
|
|
158
160
|
style: containerStyle,
|
|
159
161
|
children: [
|
|
160
162
|
/* @__PURE__ */ jsx("div", { className: styles.header, children: /* @__PURE__ */ jsxs("div", { className: styles.productHeader, children: [
|
|
161
|
-
/* @__PURE__ */ jsx("div", { className: styles.productLogo, children: productLogo }),
|
|
163
|
+
/* @__PURE__ */ jsx("div", { className: styles.productGroup, children: productLogo ? /* @__PURE__ */ jsx("div", { className: styles.productLogo, children: productLogo }) : productName && /* @__PURE__ */ jsxs("span", { className: styles.productNameLabel, children: [
|
|
164
|
+
/* @__PURE__ */ jsx("span", { className: styles.productNameSquare }),
|
|
165
|
+
/* @__PURE__ */ jsx(Headline, { disableMargin: true, size: 1, allowWrap: false, children: productName })
|
|
166
|
+
] }) }),
|
|
162
167
|
/* @__PURE__ */ jsx(
|
|
163
168
|
Button,
|
|
164
169
|
{
|
|
@@ -64,6 +64,15 @@
|
|
|
64
64
|
flex-grow: 1;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/* Product logo + name group */
|
|
68
|
+
.productGroup {
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: var(--spacing-xs);
|
|
72
|
+
min-width: 0;
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
}
|
|
75
|
+
|
|
67
76
|
/* Product logo container */
|
|
68
77
|
.productLogo {
|
|
69
78
|
display: flex;
|
|
@@ -73,6 +82,25 @@
|
|
|
73
82
|
min-width: 0;
|
|
74
83
|
}
|
|
75
84
|
|
|
85
|
+
.productNameLabel {
|
|
86
|
+
display: inline-flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
gap: var(--spacing-xxs);
|
|
89
|
+
color: var(--color-fg-default);
|
|
90
|
+
min-width: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.productNameSquare {
|
|
94
|
+
inline-size: 7px;
|
|
95
|
+
block-size: 7px;
|
|
96
|
+
flex: 0 0 auto;
|
|
97
|
+
background-color: var(--color-logo);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.productNameLabel h1 {
|
|
101
|
+
font-size: var(--font-size-md);
|
|
102
|
+
}
|
|
103
|
+
|
|
76
104
|
/* Let wrapper elements such as Next.js <Link> inherit the logo sizing context */
|
|
77
105
|
.productLogo > * {
|
|
78
106
|
display: flex;
|
|
@@ -245,8 +273,8 @@
|
|
|
245
273
|
}
|
|
246
274
|
|
|
247
275
|
/* === Collapsed header behavior ===
|
|
248
|
-
Hide product logo entirely so the collapse button can truly center. */
|
|
249
|
-
.container.collapsed .
|
|
276
|
+
Hide product logo + name entirely so the collapse button can truly center. */
|
|
277
|
+
.container.collapsed .productGroup {
|
|
250
278
|
display: none;
|
|
251
279
|
}
|
|
252
280
|
|
|
@@ -31,7 +31,6 @@ function Table({
|
|
|
31
31
|
variant = "primary",
|
|
32
32
|
size = "md",
|
|
33
33
|
viewMode,
|
|
34
|
-
striped,
|
|
35
34
|
fillViewport = false,
|
|
36
35
|
fillViewportBottomOffset = 16,
|
|
37
36
|
containScrolling = true,
|
|
@@ -53,6 +52,7 @@ function Table({
|
|
|
53
52
|
getRowSeverity,
|
|
54
53
|
getContextMenuItems,
|
|
55
54
|
showContextMenuOnHover = true,
|
|
55
|
+
expandableRows = false,
|
|
56
56
|
onRowClick,
|
|
57
57
|
onRowMouseEnter,
|
|
58
58
|
onRowSelect,
|
|
@@ -67,6 +67,18 @@ function Table({
|
|
|
67
67
|
const tableRootRefWrapper = react.useRef(tableRootRef);
|
|
68
68
|
const hasSelection = Boolean(selectedRows && onRowSelect);
|
|
69
69
|
const hasPagination = Boolean(onPageChange && (loading || data.length > 0));
|
|
70
|
+
const [expandedRows, setExpandedRows] = react.useState(() => /* @__PURE__ */ new Set());
|
|
71
|
+
const handleToggleRowExpand = react.useCallback((rowId) => {
|
|
72
|
+
setExpandedRows((prev) => {
|
|
73
|
+
const next = new Set(prev);
|
|
74
|
+
if (next.has(rowId)) {
|
|
75
|
+
next.delete(rowId);
|
|
76
|
+
} else {
|
|
77
|
+
next.add(rowId);
|
|
78
|
+
}
|
|
79
|
+
return next;
|
|
80
|
+
});
|
|
81
|
+
}, []);
|
|
70
82
|
const paginationOffset = hasPagination ? 72 : 0;
|
|
71
83
|
const { style: viewportFillStyle, maxHeight } = useViewportFill.useViewportFill(internalTableRootRef, {
|
|
72
84
|
bottomOffset: fillViewportBottomOffset + paginationOffset,
|
|
@@ -94,7 +106,6 @@ function Table({
|
|
|
94
106
|
data,
|
|
95
107
|
dataKey,
|
|
96
108
|
columns: visibleColumns,
|
|
97
|
-
striped,
|
|
98
109
|
selectedRows,
|
|
99
110
|
hasSelection,
|
|
100
111
|
selectionMode,
|
|
@@ -103,9 +114,12 @@ function Table({
|
|
|
103
114
|
getRowSeverity,
|
|
104
115
|
getContextMenuItems,
|
|
105
116
|
showContextMenuOnHover,
|
|
117
|
+
expandableRows,
|
|
118
|
+
expandedRows,
|
|
106
119
|
onRowClick,
|
|
107
120
|
onRowMouseEnter,
|
|
108
|
-
onRowSelect
|
|
121
|
+
onRowSelect,
|
|
122
|
+
onToggleRowExpand: handleToggleRowExpand
|
|
109
123
|
}
|
|
110
124
|
);
|
|
111
125
|
const paginationEl = hasPagination ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { JSX } from 'react';
|
|
2
2
|
import type { TableProps } from './Table.types';
|
|
3
|
-
export declare function Table<T extends Record<string, any>>({ data, dataKey, columns, selectedRows, selectionMode, allRowsSelected, sortById, sortDirection, loading, emptyConfig, variant, size, viewMode,
|
|
3
|
+
export declare function Table<T extends Record<string, any>>({ data, dataKey, columns, selectedRows, selectionMode, allRowsSelected, sortById, sortDirection, loading, emptyConfig, variant, size, viewMode, fillViewport, fillViewportBottomOffset, containScrolling, stickyHeader, tableWidth, tableRootRef, measuringLayout, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement, showFirstLast, showGoToPage, showPageSize, pageSizeOptions, showHeader, getRowSeverity, getContextMenuItems, showContextMenuOnHover, expandableRows, onRowClick, onRowMouseEnter, onRowSelect, onSelectAllRows, onSortChange, onPageChange, ...rest }: TableProps<T>): JSX.Element;
|
|
4
4
|
export type { ColumnItem } from './Table.types';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
import { useMemo, useId, useRef, useCallback } from 'react';
|
|
3
|
+
import { useMemo, useId, useRef, useState, useCallback } from 'react';
|
|
4
4
|
import { Pagination } from '../../components/pagination/Pagination';
|
|
5
5
|
import { SkeletonLoader } from '../../components/skeleton-loader/SkeletonLoader';
|
|
6
6
|
import { useViewportFill } from '../../hooks/useViewportFill';
|
|
@@ -25,7 +25,6 @@ function Table({
|
|
|
25
25
|
variant = "primary",
|
|
26
26
|
size = "md",
|
|
27
27
|
viewMode,
|
|
28
|
-
striped,
|
|
29
28
|
fillViewport = false,
|
|
30
29
|
fillViewportBottomOffset = 16,
|
|
31
30
|
containScrolling = true,
|
|
@@ -47,6 +46,7 @@ function Table({
|
|
|
47
46
|
getRowSeverity,
|
|
48
47
|
getContextMenuItems,
|
|
49
48
|
showContextMenuOnHover = true,
|
|
49
|
+
expandableRows = false,
|
|
50
50
|
onRowClick,
|
|
51
51
|
onRowMouseEnter,
|
|
52
52
|
onRowSelect,
|
|
@@ -61,6 +61,18 @@ function Table({
|
|
|
61
61
|
const tableRootRefWrapper = useRef(tableRootRef);
|
|
62
62
|
const hasSelection = Boolean(selectedRows && onRowSelect);
|
|
63
63
|
const hasPagination = Boolean(onPageChange && (loading || data.length > 0));
|
|
64
|
+
const [expandedRows, setExpandedRows] = useState(() => /* @__PURE__ */ new Set());
|
|
65
|
+
const handleToggleRowExpand = useCallback((rowId) => {
|
|
66
|
+
setExpandedRows((prev) => {
|
|
67
|
+
const next = new Set(prev);
|
|
68
|
+
if (next.has(rowId)) {
|
|
69
|
+
next.delete(rowId);
|
|
70
|
+
} else {
|
|
71
|
+
next.add(rowId);
|
|
72
|
+
}
|
|
73
|
+
return next;
|
|
74
|
+
});
|
|
75
|
+
}, []);
|
|
64
76
|
const paginationOffset = hasPagination ? 72 : 0;
|
|
65
77
|
const { style: viewportFillStyle, maxHeight } = useViewportFill(internalTableRootRef, {
|
|
66
78
|
bottomOffset: fillViewportBottomOffset + paginationOffset,
|
|
@@ -88,7 +100,6 @@ function Table({
|
|
|
88
100
|
data,
|
|
89
101
|
dataKey,
|
|
90
102
|
columns: visibleColumns,
|
|
91
|
-
striped,
|
|
92
103
|
selectedRows,
|
|
93
104
|
hasSelection,
|
|
94
105
|
selectionMode,
|
|
@@ -97,9 +108,12 @@ function Table({
|
|
|
97
108
|
getRowSeverity,
|
|
98
109
|
getContextMenuItems,
|
|
99
110
|
showContextMenuOnHover,
|
|
111
|
+
expandableRows,
|
|
112
|
+
expandedRows,
|
|
100
113
|
onRowClick,
|
|
101
114
|
onRowMouseEnter,
|
|
102
|
-
onRowSelect
|
|
115
|
+
onRowSelect,
|
|
116
|
+
onToggleRowExpand: handleToggleRowExpand
|
|
103
117
|
}
|
|
104
118
|
);
|
|
105
119
|
const paginationEl = hasPagination ? /* @__PURE__ */ jsx(
|
|
@@ -50,8 +50,7 @@
|
|
|
50
50
|
--table-component-header-fg: var(--table-header-fg);
|
|
51
51
|
--table-component-header-font-weight: var(--font-weight-medium);
|
|
52
52
|
--table-component-row-bg: var(--table-row-bg);
|
|
53
|
-
--table-component-row-bg-
|
|
54
|
-
--table-component-row-bg-hover: var(--table-row-bg-hover);
|
|
53
|
+
--table-component-row-bg-hover: var(--color-bg-hover-subtle);
|
|
55
54
|
--table-component-row-bg-selected: var(--table-row-bg-selected);
|
|
56
55
|
--table-component-row-bg-selected-hover: var(--table-row-bg-selected-hover);
|
|
57
56
|
--table-component-cell-fg: var(--table-cell-fg);
|
|
@@ -79,11 +78,6 @@
|
|
|
79
78
|
--table-component-header-fg: var(--color-fg-subtle);
|
|
80
79
|
--table-component-header-font-weight: var(--font-weight-default);
|
|
81
80
|
--table-component-row-bg: transparent;
|
|
82
|
-
--table-component-row-bg-alt: color-mix(
|
|
83
|
-
in srgb,
|
|
84
|
-
var(--color-bg-contextual-subtle) 55%,
|
|
85
|
-
transparent
|
|
86
|
-
);
|
|
87
81
|
--table-component-row-bg-hover: var(--color-bg-contextual-subtle);
|
|
88
82
|
--table-component-row-bg-selected: color-mix(in srgb, var(--color-bg-selected) 55%, transparent);
|
|
89
83
|
--table-component-row-bg-selected-hover: color-mix(
|
|
@@ -207,15 +201,9 @@
|
|
|
207
201
|
height: 32px;
|
|
208
202
|
}
|
|
209
203
|
|
|
210
|
-
.sm .contextMenuOverlay {
|
|
211
|
-
min-block-size: 0;
|
|
212
|
-
block-size: min(100%, 32px);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
204
|
.sm .contextMenuTrigger {
|
|
216
205
|
min-block-size: 0;
|
|
217
206
|
block-size: 100%;
|
|
218
|
-
border-radius: 0;
|
|
219
207
|
}
|
|
220
208
|
|
|
221
209
|
.cell[data-vertical-align='top'] {
|
|
@@ -310,10 +298,6 @@
|
|
|
310
298
|
background-color: var(--table-component-row-bg-selected-hover);
|
|
311
299
|
}
|
|
312
300
|
|
|
313
|
-
.striped > .row:nth-child(even):not(.selectedRow):not(:hover) > .cell {
|
|
314
|
-
background-color: var(--table-component-row-bg-alt);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
301
|
.row:focus-within > .cell {
|
|
318
302
|
box-shadow:
|
|
319
303
|
inset 0 2px 0 var(--color-brand),
|
|
@@ -573,29 +557,35 @@
|
|
|
573
557
|
|
|
574
558
|
.contextMenuTrigger {
|
|
575
559
|
color: var(--color-fg-subtle);
|
|
576
|
-
min-inline-size: var(--component-size-
|
|
577
|
-
min-block-size: var(--component-size-
|
|
578
|
-
border-radius:
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
.contextMenuAnchorCell {
|
|
582
|
-
overflow: visible;
|
|
560
|
+
min-inline-size: calc(var(--component-size-md) + 4px);
|
|
561
|
+
min-block-size: calc(var(--component-size-md) + 4px);
|
|
562
|
+
border-radius: 999px;
|
|
563
|
+
background-color: transparent;
|
|
564
|
+
position: relative;
|
|
583
565
|
z-index: 1;
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
.contextMenuAnchorCell .cellValueEllipsis,
|
|
587
|
-
.contextMenuAnchorCell .cellValueNoEllipsis {
|
|
588
|
-
padding-inline-end: calc(var(--component-size-sm) + var(--spacing-sm));
|
|
566
|
+
overflow: hidden;
|
|
589
567
|
}
|
|
590
568
|
|
|
591
569
|
.contextMenuOverlay {
|
|
592
570
|
position: absolute;
|
|
593
|
-
inset-block:
|
|
594
|
-
inset-inline-end:
|
|
571
|
+
inset-block-start: 50%;
|
|
572
|
+
inset-inline-end: var(--spacing-2xs);
|
|
573
|
+
transform: translateY(-50%);
|
|
595
574
|
display: inline-flex;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
575
|
+
align-items: center;
|
|
576
|
+
justify-content: flex-end;
|
|
577
|
+
inline-size: max-content;
|
|
578
|
+
block-size: auto;
|
|
579
|
+
min-inline-size: 0;
|
|
580
|
+
padding: 0;
|
|
581
|
+
border-radius: var(--border-radius-rounded);
|
|
582
|
+
background-color: transparent;
|
|
583
|
+
z-index: 2;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.contextMenuHoverOnly .contextMenuOverlay {
|
|
587
|
+
opacity: 0;
|
|
588
|
+
pointer-events: none;
|
|
599
589
|
}
|
|
600
590
|
|
|
601
591
|
/*
|
|
@@ -610,11 +600,24 @@
|
|
|
610
600
|
.contextMenuOverlay > div,
|
|
611
601
|
.contextMenuOverlay > div > div {
|
|
612
602
|
align-items: center;
|
|
603
|
+
background-color: transparent;
|
|
604
|
+
overflow: visible;
|
|
605
|
+
border-radius: 999px;
|
|
613
606
|
}
|
|
614
607
|
|
|
615
|
-
.
|
|
616
|
-
|
|
617
|
-
|
|
608
|
+
.actionCell {
|
|
609
|
+
overflow: visible;
|
|
610
|
+
position: relative;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
.cellContentWithActions {
|
|
614
|
+
padding-inline-end: calc(var(--component-size-md) + 4px + var(--spacing-sm));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
.contextMenuTrigger:hover,
|
|
618
|
+
.contextMenuTrigger:focus-visible {
|
|
619
|
+
background-color: var(--table-component-row-bg-hover);
|
|
620
|
+
z-index: 2;
|
|
618
621
|
}
|
|
619
622
|
|
|
620
623
|
.contextMenuItemLabel {
|
|
@@ -628,13 +631,7 @@
|
|
|
628
631
|
min-width: 0;
|
|
629
632
|
}
|
|
630
633
|
|
|
631
|
-
.contextMenuHoverOnly .
|
|
632
|
-
opacity: 0;
|
|
633
|
-
pointer-events: none;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
.contextMenuHoverOnly:hover .contextMenuTrigger,
|
|
637
|
-
.contextMenuHoverOnly:focus-within .contextMenuTrigger {
|
|
634
|
+
.contextMenuHoverOnly:hover .contextMenuOverlay {
|
|
638
635
|
opacity: 1;
|
|
639
636
|
pointer-events: auto;
|
|
640
637
|
}
|
|
@@ -56,7 +56,6 @@ export type TableProps<T extends Record<string, any>> = Omit<HTMLAttributes<HTML
|
|
|
56
56
|
variant?: TableVariant;
|
|
57
57
|
size?: 'sm' | 'md';
|
|
58
58
|
viewMode?: ViewMode;
|
|
59
|
-
striped?: boolean;
|
|
60
59
|
fillViewport?: boolean;
|
|
61
60
|
fillViewportBottomOffset?: number;
|
|
62
61
|
containScrolling?: boolean;
|
|
@@ -82,6 +81,7 @@ export type TableProps<T extends Record<string, any>> = Omit<HTMLAttributes<HTML
|
|
|
82
81
|
open: () => void;
|
|
83
82
|
}) => TableContextMenuItem[];
|
|
84
83
|
showContextMenuOnHover?: boolean;
|
|
84
|
+
expandableRows?: boolean;
|
|
85
85
|
onRowClick?: (row: T) => void;
|
|
86
86
|
onRowMouseEnter?: (row: T) => void;
|
|
87
87
|
onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var table_classes = require('../table.classes');
|
|
5
4
|
var styles = require('../Table.module.css');
|
|
6
5
|
var TableRow = require('./TableRow');
|
|
7
6
|
|
|
@@ -13,7 +12,6 @@ function TableBody({
|
|
|
13
12
|
data,
|
|
14
13
|
dataKey,
|
|
15
14
|
columns,
|
|
16
|
-
striped,
|
|
17
15
|
selectedRows,
|
|
18
16
|
hasSelection,
|
|
19
17
|
selectionMode,
|
|
@@ -22,11 +20,14 @@ function TableBody({
|
|
|
22
20
|
getRowSeverity,
|
|
23
21
|
getContextMenuItems,
|
|
24
22
|
showContextMenuOnHover,
|
|
23
|
+
expandableRows,
|
|
24
|
+
expandedRows,
|
|
25
25
|
onRowClick,
|
|
26
26
|
onRowMouseEnter,
|
|
27
|
-
onRowSelect
|
|
27
|
+
onRowSelect,
|
|
28
|
+
onToggleRowExpand
|
|
28
29
|
}) {
|
|
29
|
-
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className:
|
|
30
|
+
return /* @__PURE__ */ jsxRuntime.jsx("tbody", { className: styles__default.default.body, children: data.map((row) => {
|
|
30
31
|
const rowId = row[dataKey];
|
|
31
32
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
32
33
|
TableRow.TableRow,
|
|
@@ -42,9 +43,12 @@ function TableBody({
|
|
|
42
43
|
getRowSeverity,
|
|
43
44
|
getContextMenuItems,
|
|
44
45
|
showContextMenuOnHover,
|
|
46
|
+
expandableRows,
|
|
47
|
+
expandedRows,
|
|
45
48
|
onRowClick,
|
|
46
49
|
onRowMouseEnter,
|
|
47
|
-
onRowSelect
|
|
50
|
+
onRowSelect,
|
|
51
|
+
onToggleRowExpand
|
|
48
52
|
},
|
|
49
53
|
`gridRow-${rowId}`
|
|
50
54
|
);
|
|
@@ -5,7 +5,6 @@ type Props<T extends Record<string, any>> = {
|
|
|
5
5
|
data: T[];
|
|
6
6
|
dataKey: keyof T;
|
|
7
7
|
columns: ColumnItem<T>[];
|
|
8
|
-
striped?: boolean;
|
|
9
8
|
selectedRows?: Set<number | string>;
|
|
10
9
|
hasSelection: boolean;
|
|
11
10
|
selectionMode: 'single' | 'multiple';
|
|
@@ -18,9 +17,12 @@ type Props<T extends Record<string, any>> = {
|
|
|
18
17
|
open: () => void;
|
|
19
18
|
}) => TableContextMenuItem[];
|
|
20
19
|
showContextMenuOnHover: boolean;
|
|
20
|
+
expandableRows?: boolean;
|
|
21
|
+
expandedRows?: Set<number | string>;
|
|
21
22
|
onRowClick?: (row: T) => void;
|
|
22
23
|
onRowMouseEnter?: (row: T) => void;
|
|
23
24
|
onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
|
|
25
|
+
onToggleRowExpand?: (rowId: number | string) => void;
|
|
24
26
|
};
|
|
25
|
-
export declare function TableBody<T extends Record<string, any>>({ data, dataKey, columns,
|
|
27
|
+
export declare function TableBody<T extends Record<string, any>>({ data, dataKey, columns, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, getContextMenuItems, showContextMenuOnHover, expandableRows, expandedRows, onRowClick, onRowMouseEnter, onRowSelect, onToggleRowExpand, }: Props<T>): ReactNode;
|
|
26
28
|
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { cx } from '../table.classes';
|
|
3
2
|
import styles from '../Table.module.css';
|
|
4
3
|
import { TableRow } from './TableRow';
|
|
5
4
|
|
|
@@ -7,7 +6,6 @@ function TableBody({
|
|
|
7
6
|
data,
|
|
8
7
|
dataKey,
|
|
9
8
|
columns,
|
|
10
|
-
striped,
|
|
11
9
|
selectedRows,
|
|
12
10
|
hasSelection,
|
|
13
11
|
selectionMode,
|
|
@@ -16,11 +14,14 @@ function TableBody({
|
|
|
16
14
|
getRowSeverity,
|
|
17
15
|
getContextMenuItems,
|
|
18
16
|
showContextMenuOnHover,
|
|
17
|
+
expandableRows,
|
|
18
|
+
expandedRows,
|
|
19
19
|
onRowClick,
|
|
20
20
|
onRowMouseEnter,
|
|
21
|
-
onRowSelect
|
|
21
|
+
onRowSelect,
|
|
22
|
+
onToggleRowExpand
|
|
22
23
|
}) {
|
|
23
|
-
return /* @__PURE__ */ jsx("tbody", { className:
|
|
24
|
+
return /* @__PURE__ */ jsx("tbody", { className: styles.body, children: data.map((row) => {
|
|
24
25
|
const rowId = row[dataKey];
|
|
25
26
|
return /* @__PURE__ */ jsx(
|
|
26
27
|
TableRow,
|
|
@@ -36,9 +37,12 @@ function TableBody({
|
|
|
36
37
|
getRowSeverity,
|
|
37
38
|
getContextMenuItems,
|
|
38
39
|
showContextMenuOnHover,
|
|
40
|
+
expandableRows,
|
|
41
|
+
expandedRows,
|
|
39
42
|
onRowClick,
|
|
40
43
|
onRowMouseEnter,
|
|
41
|
-
onRowSelect
|
|
44
|
+
onRowSelect,
|
|
45
|
+
onToggleRowExpand
|
|
42
46
|
},
|
|
43
47
|
`gridRow-${rowId}`
|
|
44
48
|
);
|
|
@@ -30,14 +30,19 @@ function TableRow({
|
|
|
30
30
|
getRowSeverity,
|
|
31
31
|
getContextMenuItems,
|
|
32
32
|
showContextMenuOnHover,
|
|
33
|
+
expandableRows,
|
|
34
|
+
expandedRows,
|
|
33
35
|
onRowClick,
|
|
34
36
|
onRowMouseEnter,
|
|
35
|
-
onRowSelect
|
|
37
|
+
onRowSelect,
|
|
38
|
+
onToggleRowExpand
|
|
36
39
|
}) {
|
|
37
|
-
var _a;
|
|
40
|
+
var _a, _b;
|
|
38
41
|
const isSelected = (_a = selectedRows == null ? void 0 : selectedRows.has(rowId)) != null ? _a : false;
|
|
42
|
+
const isExpanded = (_b = expandedRows == null ? void 0 : expandedRows.has(rowId)) != null ? _b : false;
|
|
39
43
|
const rowSeverity = getRowSeverity == null ? void 0 : getRowSeverity(row);
|
|
40
44
|
const canSelect = Boolean(selectedRows && onRowSelect);
|
|
45
|
+
const canExpand = Boolean(expandableRows && onToggleRowExpand);
|
|
41
46
|
const contextMenuItems = getContextMenuItems == null ? void 0 : getContextMenuItems({
|
|
42
47
|
row,
|
|
43
48
|
rowId,
|
|
@@ -128,32 +133,32 @@ function TableRow({
|
|
|
128
133
|
)
|
|
129
134
|
}
|
|
130
135
|
) }) : null,
|
|
131
|
-
columns.map((column) => {
|
|
132
|
-
var _a2,
|
|
133
|
-
const allowWrap = table_utils.shouldAllowWrap(column.allowWrap, isSelected, viewMode);
|
|
136
|
+
columns.map((column, index) => {
|
|
137
|
+
var _a2, _b2, _c, _d;
|
|
138
|
+
const allowWrap = table_utils.shouldAllowWrap(column.allowWrap, isSelected || isExpanded, viewMode);
|
|
134
139
|
const allowOverflow = column.allowOverflow;
|
|
135
140
|
const cellValue = table_utils.getCellDisplayValue(row, column);
|
|
136
|
-
const
|
|
141
|
+
const showRowActions = index === columns.length - 1 && hasContextMenu;
|
|
137
142
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
138
143
|
"td",
|
|
139
144
|
{
|
|
140
145
|
className: table_classes.cx(
|
|
141
146
|
styles__default.default.cell,
|
|
147
|
+
showRowActions && styles__default.default.actionCell,
|
|
142
148
|
allowOverflow && styles__default.default.allowOverflow,
|
|
143
149
|
allowWrap ? styles__default.default.allowWrap : styles__default.default.nowrap,
|
|
144
|
-
hasContextMenu && isLastColumn && styles__default.default.contextMenuAnchorCell,
|
|
145
150
|
column.divider === "left" && styles__default.default.dividerLeft,
|
|
146
151
|
column.divider === "right" && styles__default.default.dividerRight
|
|
147
152
|
),
|
|
148
|
-
"data-align": (
|
|
149
|
-
"data-vertical-align": (
|
|
153
|
+
"data-align": (_a2 = column.align) != null ? _a2 : "left",
|
|
154
|
+
"data-vertical-align": (_b2 = column.verticalAlign) != null ? _b2 : "top",
|
|
150
155
|
"data-divider": column.divider,
|
|
151
156
|
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
152
157
|
"div",
|
|
153
158
|
{
|
|
154
|
-
className: styles__default.default.cellContent,
|
|
155
|
-
"data-align": (
|
|
156
|
-
"data-vertical-align": (
|
|
159
|
+
className: table_classes.cx(styles__default.default.cellContent, showRowActions && styles__default.default.cellContentWithActions),
|
|
160
|
+
"data-align": (_c = column.align) != null ? _c : "left",
|
|
161
|
+
"data-vertical-align": (_d = column.verticalAlign) != null ? _d : "top",
|
|
157
162
|
children: [
|
|
158
163
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
159
164
|
"div",
|
|
@@ -162,11 +167,14 @@ function TableRow({
|
|
|
162
167
|
children: cellValue
|
|
163
168
|
}
|
|
164
169
|
),
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
showRowActions ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
171
|
+
RowActions,
|
|
167
172
|
{
|
|
168
173
|
rowId,
|
|
169
174
|
items: contextMenuItems,
|
|
175
|
+
expandable: canExpand && viewMode !== "wrapped",
|
|
176
|
+
isExpanded,
|
|
177
|
+
onToggleExpand: onToggleRowExpand ? () => onToggleRowExpand(rowId) : void 0,
|
|
170
178
|
onRowClick: onRowClick ? () => onRowClick(row) : void 0
|
|
171
179
|
}
|
|
172
180
|
) : null
|
|
@@ -181,12 +189,23 @@ function TableRow({
|
|
|
181
189
|
}
|
|
182
190
|
);
|
|
183
191
|
}
|
|
184
|
-
function
|
|
192
|
+
function RowActions({
|
|
185
193
|
rowId,
|
|
186
194
|
items,
|
|
195
|
+
expandable,
|
|
196
|
+
isExpanded,
|
|
197
|
+
onToggleExpand,
|
|
187
198
|
onRowClick
|
|
188
199
|
}) {
|
|
189
200
|
const toggleRef = react.useRef(null);
|
|
201
|
+
const expandItem = expandable ? {
|
|
202
|
+
label: "Udvid r\xE6kke",
|
|
203
|
+
active: isExpanded,
|
|
204
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { size: 16 }),
|
|
205
|
+
onClick: () => onToggleExpand == null ? void 0 : onToggleExpand()
|
|
206
|
+
} : null;
|
|
207
|
+
const menuItems = [...expandItem ? [expandItem] : [], ...items != null ? items : []];
|
|
208
|
+
const hasMenu = Boolean(menuItems.length);
|
|
190
209
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
191
210
|
"div",
|
|
192
211
|
{
|
|
@@ -194,15 +213,17 @@ function RowContextMenu({
|
|
|
194
213
|
"data-row-context-menu": "true",
|
|
195
214
|
onClick: (e) => {
|
|
196
215
|
var _a;
|
|
216
|
+
if (!hasMenu) return;
|
|
197
217
|
e.stopPropagation();
|
|
198
218
|
(_a = toggleRef.current) == null ? void 0 : _a.call(toggleRef, e);
|
|
199
219
|
},
|
|
200
220
|
onContextMenu: (e) => {
|
|
221
|
+
if (!hasMenu) return;
|
|
201
222
|
e.preventDefault();
|
|
202
223
|
e.stopPropagation();
|
|
203
224
|
onRowClick == null ? void 0 : onRowClick();
|
|
204
225
|
},
|
|
205
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
226
|
+
children: hasMenu ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
206
227
|
Popover.Popover,
|
|
207
228
|
{
|
|
208
229
|
matchTriggerWidth: false,
|
|
@@ -229,7 +250,7 @@ function RowContextMenu({
|
|
|
229
250
|
}
|
|
230
251
|
);
|
|
231
252
|
},
|
|
232
|
-
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children:
|
|
253
|
+
children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children: menuItems.map(
|
|
233
254
|
(item, index) => item.type === "header" ? /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: item.label }, index) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
234
255
|
Menu.Menu.Item,
|
|
235
256
|
{
|
|
@@ -258,7 +279,7 @@ function RowContextMenu({
|
|
|
258
279
|
)
|
|
259
280
|
) })
|
|
260
281
|
}
|
|
261
|
-
)
|
|
282
|
+
) : null
|
|
262
283
|
}
|
|
263
284
|
);
|
|
264
285
|
}
|
|
@@ -17,9 +17,12 @@ type Props<T extends Record<string, any>> = {
|
|
|
17
17
|
open: () => void;
|
|
18
18
|
}) => TableContextMenuItem[];
|
|
19
19
|
showContextMenuOnHover: boolean;
|
|
20
|
+
expandableRows?: boolean;
|
|
21
|
+
expandedRows?: Set<number | string>;
|
|
20
22
|
onRowClick?: (row: T) => void;
|
|
21
23
|
onRowMouseEnter?: (row: T) => void;
|
|
22
24
|
onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
|
|
25
|
+
onToggleRowExpand?: (rowId: number | string) => void;
|
|
23
26
|
};
|
|
24
|
-
export declare function TableRow<T extends Record<string, any>>({ row, rowId, columns, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, getContextMenuItems, showContextMenuOnHover, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): React.ReactNode;
|
|
27
|
+
export declare function TableRow<T extends Record<string, any>>({ row, rowId, columns, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, getContextMenuItems, showContextMenuOnHover, expandableRows, expandedRows, onRowClick, onRowMouseEnter, onRowSelect, onToggleRowExpand, }: Props<T>): React.ReactNode;
|
|
25
28
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { MoreVertical } from 'lucide-react';
|
|
2
|
+
import { MoreVertical, ChevronsUpDown } from 'lucide-react';
|
|
3
3
|
import { useRef } from 'react';
|
|
4
4
|
import { Checkbox } from '../../../components/forms/checkbox/Checkbox';
|
|
5
5
|
import { RadioButton } from '../../../components/forms/radio-buttons/RadioButton';
|
|
@@ -24,14 +24,19 @@ function TableRow({
|
|
|
24
24
|
getRowSeverity,
|
|
25
25
|
getContextMenuItems,
|
|
26
26
|
showContextMenuOnHover,
|
|
27
|
+
expandableRows,
|
|
28
|
+
expandedRows,
|
|
27
29
|
onRowClick,
|
|
28
30
|
onRowMouseEnter,
|
|
29
|
-
onRowSelect
|
|
31
|
+
onRowSelect,
|
|
32
|
+
onToggleRowExpand
|
|
30
33
|
}) {
|
|
31
|
-
var _a;
|
|
34
|
+
var _a, _b;
|
|
32
35
|
const isSelected = (_a = selectedRows == null ? void 0 : selectedRows.has(rowId)) != null ? _a : false;
|
|
36
|
+
const isExpanded = (_b = expandedRows == null ? void 0 : expandedRows.has(rowId)) != null ? _b : false;
|
|
33
37
|
const rowSeverity = getRowSeverity == null ? void 0 : getRowSeverity(row);
|
|
34
38
|
const canSelect = Boolean(selectedRows && onRowSelect);
|
|
39
|
+
const canExpand = Boolean(expandableRows && onToggleRowExpand);
|
|
35
40
|
const contextMenuItems = getContextMenuItems == null ? void 0 : getContextMenuItems({
|
|
36
41
|
row,
|
|
37
42
|
rowId,
|
|
@@ -122,32 +127,32 @@ function TableRow({
|
|
|
122
127
|
)
|
|
123
128
|
}
|
|
124
129
|
) }) : null,
|
|
125
|
-
columns.map((column) => {
|
|
126
|
-
var _a2,
|
|
127
|
-
const allowWrap = shouldAllowWrap(column.allowWrap, isSelected, viewMode);
|
|
130
|
+
columns.map((column, index) => {
|
|
131
|
+
var _a2, _b2, _c, _d;
|
|
132
|
+
const allowWrap = shouldAllowWrap(column.allowWrap, isSelected || isExpanded, viewMode);
|
|
128
133
|
const allowOverflow = column.allowOverflow;
|
|
129
134
|
const cellValue = getCellDisplayValue(row, column);
|
|
130
|
-
const
|
|
135
|
+
const showRowActions = index === columns.length - 1 && hasContextMenu;
|
|
131
136
|
return /* @__PURE__ */ jsx(
|
|
132
137
|
"td",
|
|
133
138
|
{
|
|
134
139
|
className: cx(
|
|
135
140
|
styles.cell,
|
|
141
|
+
showRowActions && styles.actionCell,
|
|
136
142
|
allowOverflow && styles.allowOverflow,
|
|
137
143
|
allowWrap ? styles.allowWrap : styles.nowrap,
|
|
138
|
-
hasContextMenu && isLastColumn && styles.contextMenuAnchorCell,
|
|
139
144
|
column.divider === "left" && styles.dividerLeft,
|
|
140
145
|
column.divider === "right" && styles.dividerRight
|
|
141
146
|
),
|
|
142
|
-
"data-align": (
|
|
143
|
-
"data-vertical-align": (
|
|
147
|
+
"data-align": (_a2 = column.align) != null ? _a2 : "left",
|
|
148
|
+
"data-vertical-align": (_b2 = column.verticalAlign) != null ? _b2 : "top",
|
|
144
149
|
"data-divider": column.divider,
|
|
145
150
|
children: /* @__PURE__ */ jsxs(
|
|
146
151
|
"div",
|
|
147
152
|
{
|
|
148
|
-
className: styles.cellContent,
|
|
149
|
-
"data-align": (
|
|
150
|
-
"data-vertical-align": (
|
|
153
|
+
className: cx(styles.cellContent, showRowActions && styles.cellContentWithActions),
|
|
154
|
+
"data-align": (_c = column.align) != null ? _c : "left",
|
|
155
|
+
"data-vertical-align": (_d = column.verticalAlign) != null ? _d : "top",
|
|
151
156
|
children: [
|
|
152
157
|
/* @__PURE__ */ jsx(
|
|
153
158
|
"div",
|
|
@@ -156,11 +161,14 @@ function TableRow({
|
|
|
156
161
|
children: cellValue
|
|
157
162
|
}
|
|
158
163
|
),
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
showRowActions ? /* @__PURE__ */ jsx(
|
|
165
|
+
RowActions,
|
|
161
166
|
{
|
|
162
167
|
rowId,
|
|
163
168
|
items: contextMenuItems,
|
|
169
|
+
expandable: canExpand && viewMode !== "wrapped",
|
|
170
|
+
isExpanded,
|
|
171
|
+
onToggleExpand: onToggleRowExpand ? () => onToggleRowExpand(rowId) : void 0,
|
|
164
172
|
onRowClick: onRowClick ? () => onRowClick(row) : void 0
|
|
165
173
|
}
|
|
166
174
|
) : null
|
|
@@ -175,12 +183,23 @@ function TableRow({
|
|
|
175
183
|
}
|
|
176
184
|
);
|
|
177
185
|
}
|
|
178
|
-
function
|
|
186
|
+
function RowActions({
|
|
179
187
|
rowId,
|
|
180
188
|
items,
|
|
189
|
+
expandable,
|
|
190
|
+
isExpanded,
|
|
191
|
+
onToggleExpand,
|
|
181
192
|
onRowClick
|
|
182
193
|
}) {
|
|
183
194
|
const toggleRef = useRef(null);
|
|
195
|
+
const expandItem = expandable ? {
|
|
196
|
+
label: "Udvid r\xE6kke",
|
|
197
|
+
active: isExpanded,
|
|
198
|
+
icon: /* @__PURE__ */ jsx(ChevronsUpDown, { size: 16 }),
|
|
199
|
+
onClick: () => onToggleExpand == null ? void 0 : onToggleExpand()
|
|
200
|
+
} : null;
|
|
201
|
+
const menuItems = [...expandItem ? [expandItem] : [], ...items != null ? items : []];
|
|
202
|
+
const hasMenu = Boolean(menuItems.length);
|
|
184
203
|
return /* @__PURE__ */ jsx(
|
|
185
204
|
"div",
|
|
186
205
|
{
|
|
@@ -188,15 +207,17 @@ function RowContextMenu({
|
|
|
188
207
|
"data-row-context-menu": "true",
|
|
189
208
|
onClick: (e) => {
|
|
190
209
|
var _a;
|
|
210
|
+
if (!hasMenu) return;
|
|
191
211
|
e.stopPropagation();
|
|
192
212
|
(_a = toggleRef.current) == null ? void 0 : _a.call(toggleRef, e);
|
|
193
213
|
},
|
|
194
214
|
onContextMenu: (e) => {
|
|
215
|
+
if (!hasMenu) return;
|
|
195
216
|
e.preventDefault();
|
|
196
217
|
e.stopPropagation();
|
|
197
218
|
onRowClick == null ? void 0 : onRowClick();
|
|
198
219
|
},
|
|
199
|
-
children: /* @__PURE__ */ jsx(
|
|
220
|
+
children: hasMenu ? /* @__PURE__ */ jsx(
|
|
200
221
|
Popover,
|
|
201
222
|
{
|
|
202
223
|
matchTriggerWidth: false,
|
|
@@ -223,7 +244,7 @@ function RowContextMenu({
|
|
|
223
244
|
}
|
|
224
245
|
);
|
|
225
246
|
},
|
|
226
|
-
children: (close) => /* @__PURE__ */ jsx(Menu, { children:
|
|
247
|
+
children: (close) => /* @__PURE__ */ jsx(Menu, { children: menuItems.map(
|
|
227
248
|
(item, index) => item.type === "header" ? /* @__PURE__ */ jsx(Menu.Header, { children: item.label }, index) : /* @__PURE__ */ jsx(
|
|
228
249
|
Menu.Item,
|
|
229
250
|
{
|
|
@@ -252,7 +273,7 @@ function RowContextMenu({
|
|
|
252
273
|
)
|
|
253
274
|
) })
|
|
254
275
|
}
|
|
255
|
-
)
|
|
276
|
+
) : null
|
|
256
277
|
}
|
|
257
278
|
);
|
|
258
279
|
}
|
|
@@ -73,7 +73,7 @@ function TableSettings({
|
|
|
73
73
|
children: (close) => /* @__PURE__ */ jsxRuntime.jsxs(Menu.Menu, { children: [
|
|
74
74
|
additionalSettings == null ? void 0 : additionalSettings(close),
|
|
75
75
|
/* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Item, { active: viewMode === "wrapped", children: /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [
|
|
76
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
76
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListChevronsUpDown, {}),
|
|
77
77
|
"Ombryd tekst"
|
|
78
78
|
] }) }),
|
|
79
79
|
hideableColumns.length > 0 && onVisibleColumnIdsChange ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import {
|
|
3
|
+
import { ListChevronsUpDown, Settings } from 'lucide-react';
|
|
4
4
|
import { useMemo } from 'react';
|
|
5
5
|
import { Button } from '../../../button/Button';
|
|
6
6
|
import { Menu } from '../../../menu/Menu';
|
|
@@ -71,7 +71,7 @@ function TableSettings({
|
|
|
71
71
|
children: (close) => /* @__PURE__ */ jsxs(Menu, { children: [
|
|
72
72
|
additionalSettings == null ? void 0 : additionalSettings(close),
|
|
73
73
|
/* @__PURE__ */ jsx(Menu.Item, { active: viewMode === "wrapped", children: /* @__PURE__ */ jsxs("button", { type: "button", onClick: () => handleViewModeChange(viewMode, close), children: [
|
|
74
|
-
/* @__PURE__ */ jsx(
|
|
74
|
+
/* @__PURE__ */ jsx(ListChevronsUpDown, {}),
|
|
75
75
|
"Ombryd tekst"
|
|
76
76
|
] }) }),
|
|
77
77
|
hideableColumns.length > 0 && onVisibleColumnIdsChange ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const SELECTION_COLUMN_PX = 40;
|
|
4
|
+
const ACTIONS_COLUMN_PX = 0;
|
|
4
5
|
const DEFAULT_COLUMN_PX = 150;
|
|
5
6
|
function getVisibleColumns(columns) {
|
|
6
7
|
return columns.filter((column) => !column.hidden);
|
|
@@ -44,6 +45,7 @@ function getCellDisplayValue(row, column) {
|
|
|
44
45
|
return empty;
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
exports.ACTIONS_COLUMN_PX = ACTIONS_COLUMN_PX;
|
|
47
49
|
exports.DEFAULT_COLUMN_PX = DEFAULT_COLUMN_PX;
|
|
48
50
|
exports.SELECTION_COLUMN_PX = SELECTION_COLUMN_PX;
|
|
49
51
|
exports.getAriaSort = getAriaSort;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { ColumnItem } from './Table.types';
|
|
3
3
|
export declare const SELECTION_COLUMN_PX: 40;
|
|
4
|
+
export declare const ACTIONS_COLUMN_PX: 0;
|
|
4
5
|
export declare const DEFAULT_COLUMN_PX: 150;
|
|
5
6
|
export type SortDirection = 'asc' | 'desc' | null;
|
|
6
7
|
export declare function getVisibleColumns<T>(columns: Array<ColumnItem<T>>): Array<ColumnItem<T>>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const SELECTION_COLUMN_PX = 40;
|
|
2
|
+
const ACTIONS_COLUMN_PX = 0;
|
|
2
3
|
const DEFAULT_COLUMN_PX = 150;
|
|
3
4
|
function getVisibleColumns(columns) {
|
|
4
5
|
return columns.filter((column) => !column.hidden);
|
|
@@ -42,4 +43,4 @@ function getCellDisplayValue(row, column) {
|
|
|
42
43
|
return empty;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
export { DEFAULT_COLUMN_PX, SELECTION_COLUMN_PX, getAriaSort, getCellDisplayValue, getHeaderLabel, getNextSortDirection, getVisibleColumns, isActiveSort, isModifierClick, shouldAllowWrap, shouldToggleOnKey };
|
|
46
|
+
export { ACTIONS_COLUMN_PX, DEFAULT_COLUMN_PX, SELECTION_COLUMN_PX, getAriaSort, getCellDisplayValue, getHeaderLabel, getNextSortDirection, getVisibleColumns, isActiveSort, isModifierClick, shouldAllowWrap, shouldToggleOnKey };
|
|
@@ -239,6 +239,12 @@ html {
|
|
|
239
239
|
--button-bg-primary-hover: var(--color-brand-hover);
|
|
240
240
|
--button-fg-primary: var(--color-fg-on-brand);
|
|
241
241
|
|
|
242
|
+
/* Product / logo lockup — generic defaults; apps with a custom identity
|
|
243
|
+
override these tokens only (see e.g. filmstriben-budget/theme.css) */
|
|
244
|
+
--color-logo: var(--color-brand);
|
|
245
|
+
--color-logo-bg: color-mix(in srgb, var(--color-logo) 10%, var(--color-bg-surface));
|
|
246
|
+
--color-logo-fg: var(--color-fg-default);
|
|
247
|
+
|
|
242
248
|
/* Tables */
|
|
243
249
|
--table-header-bg: light-dark(#f8f9fb, #1b2533);
|
|
244
250
|
--table-row-bg: light-dark(#ffffff, #111827);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* Filmstriben Budget theme entrypoint.
|
|
2
|
+
*
|
|
3
|
+
* Usage in the consuming app — only two imports needed:
|
|
4
|
+
* @import '@dbcdk/react-components/styles/themes/dbc/base.css';
|
|
5
|
+
* @import '@dbcdk/react-components/styles/themes/filmstriben-budget/theme.css';
|
|
6
|
+
*
|
|
7
|
+
* Pulls in the shared DBC color layer, then overrides only the
|
|
8
|
+
* --color-logo-* tokens. --color-brand and every other semantic/app color
|
|
9
|
+
* stay on the shared DBC palette — buttons, links, focus rings, selected
|
|
10
|
+
* states, charts, and warnings are unaffected.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
@import '../dbc/colors.css';
|
|
14
|
+
|
|
15
|
+
:root {
|
|
16
|
+
--filmstriben-yellow: #ffc107;
|
|
17
|
+
--filmstriben-black: #212529;
|
|
18
|
+
|
|
19
|
+
--color-logo: var(--filmstriben-yellow);
|
|
20
|
+
--color-logo-bg: color-mix(in srgb, var(--color-logo) 10%, var(--color-bg-surface));
|
|
21
|
+
--color-logo-fg: var(--filmstriben-black);
|
|
22
|
+
}
|
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
function formatDate(date, options = {}) {
|
|
4
4
|
const d = date instanceof Date ? date : new Date(date);
|
|
5
5
|
if (isNaN(d.getTime())) return "";
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
showTime = false,
|
|
8
|
+
showSeconds = false,
|
|
9
|
+
userFriendlyLabel = false,
|
|
10
|
+
timeOnly = false,
|
|
11
|
+
ignoreDate = false,
|
|
12
|
+
ignoreDateIfSame = false
|
|
13
|
+
} = options;
|
|
14
|
+
const useTimeOnly = timeOnly || ignoreDate;
|
|
7
15
|
const pad = (n) => n.toString().padStart(2, "0");
|
|
8
16
|
const formatTime = () => {
|
|
9
17
|
const hours = pad(d.getHours());
|
|
@@ -13,6 +21,12 @@ function formatDate(date, options = {}) {
|
|
|
13
21
|
return `${hours}:${minutes}:${seconds}`;
|
|
14
22
|
};
|
|
15
23
|
const isSameCalendarDay = (a, b) => a.getDate() === b.getDate() && a.getMonth() === b.getMonth() && a.getFullYear() === b.getFullYear();
|
|
24
|
+
if (useTimeOnly) {
|
|
25
|
+
return formatTime();
|
|
26
|
+
}
|
|
27
|
+
if (ignoreDateIfSame && isSameCalendarDay(d, /* @__PURE__ */ new Date())) {
|
|
28
|
+
return formatTime();
|
|
29
|
+
}
|
|
16
30
|
if (userFriendlyLabel) {
|
|
17
31
|
const now = /* @__PURE__ */ new Date();
|
|
18
32
|
const yesterday = new Date(now);
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Formats a Date as "dd/mm/yyyy"
|
|
2
|
+
* Formats a Date as "dd/mm/yyyy", "dd/mm/yyyy hh:mm:ss", or time-only.
|
|
3
3
|
* Optionally returns user-friendly Danish labels like "I dag" or "I går".
|
|
4
4
|
*
|
|
5
5
|
* Examples:
|
|
6
6
|
* - formatDate(new Date(), { userFriendlyLabel: true }) => "I dag"
|
|
7
7
|
* - formatDate(new Date(), { userFriendlyLabel: true, showTime: true }) => "I dag, kl. 14:30"
|
|
8
8
|
* - formatDate(date, { showTime: true }) => "10.03.2026 14:30"
|
|
9
|
+
* - formatDate(date, { timeOnly: true }) => "14:30"
|
|
10
|
+
* - formatDate(date, { showTime: true, ignoreDateIfSame: true }) => "14:30" for today, otherwise "10.03.2026 14:30"
|
|
9
11
|
*
|
|
10
12
|
* @param date - The Date or date-parsable value to format
|
|
11
13
|
* @param options.showTime - If true, append time "hh:mm" or "hh:mm:ss"
|
|
12
14
|
* @param options.showSeconds - If true, append seconds when showTime is enabled
|
|
13
15
|
* @param options.userFriendlyLabel - If true, use "I dag" / "I går" when applicable
|
|
16
|
+
* @param options.timeOnly - If true, return only the time portion
|
|
17
|
+
* @param options.ignoreDate - Alias for timeOnly
|
|
18
|
+
* @param options.ignoreDateIfSame - If true, return only the time when the date is today
|
|
14
19
|
* @returns A formatted string
|
|
15
20
|
*/
|
|
16
21
|
export declare function formatDate(date: Date | string | number, options?: {
|
|
17
22
|
showTime?: boolean;
|
|
18
23
|
showSeconds?: boolean;
|
|
19
24
|
userFriendlyLabel?: boolean;
|
|
25
|
+
timeOnly?: boolean;
|
|
26
|
+
ignoreDate?: boolean;
|
|
27
|
+
ignoreDateIfSame?: boolean;
|
|
20
28
|
}): string;
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
function formatDate(date, options = {}) {
|
|
2
2
|
const d = date instanceof Date ? date : new Date(date);
|
|
3
3
|
if (isNaN(d.getTime())) return "";
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
showTime = false,
|
|
6
|
+
showSeconds = false,
|
|
7
|
+
userFriendlyLabel = false,
|
|
8
|
+
timeOnly = false,
|
|
9
|
+
ignoreDate = false,
|
|
10
|
+
ignoreDateIfSame = false
|
|
11
|
+
} = options;
|
|
12
|
+
const useTimeOnly = timeOnly || ignoreDate;
|
|
5
13
|
const pad = (n) => n.toString().padStart(2, "0");
|
|
6
14
|
const formatTime = () => {
|
|
7
15
|
const hours = pad(d.getHours());
|
|
@@ -11,6 +19,12 @@ function formatDate(date, options = {}) {
|
|
|
11
19
|
return `${hours}:${minutes}:${seconds}`;
|
|
12
20
|
};
|
|
13
21
|
const isSameCalendarDay = (a, b) => a.getDate() === b.getDate() && a.getMonth() === b.getMonth() && a.getFullYear() === b.getFullYear();
|
|
22
|
+
if (useTimeOnly) {
|
|
23
|
+
return formatTime();
|
|
24
|
+
}
|
|
25
|
+
if (ignoreDateIfSame && isSameCalendarDay(d, /* @__PURE__ */ new Date())) {
|
|
26
|
+
return formatTime();
|
|
27
|
+
}
|
|
14
28
|
if (userFriendlyLabel) {
|
|
15
29
|
const now = /* @__PURE__ */ new Date();
|
|
16
30
|
const yesterday = new Date(now);
|