@dbcdk/react-components 0.0.136 → 0.0.137

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.
Files changed (30) hide show
  1. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.cjs +11 -9
  2. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.js +11 -9
  3. package/dist/components/sidebar/components/expandable-sidebar-item/ExpandableSidebarItem.module.css +18 -14
  4. package/dist/components/sidebar/components/sidebar-item-content/SidebarItemContent.module.css +12 -0
  5. package/dist/components/table/Table.cjs +3 -4
  6. package/dist/components/table/Table.d.ts +1 -1
  7. package/dist/components/table/Table.js +4 -5
  8. package/dist/components/table/Table.module.css +52 -21
  9. package/dist/components/table/Table.types.d.ts +9 -1
  10. package/dist/components/table/components/TableBody.cjs +2 -0
  11. package/dist/components/table/components/TableBody.d.ts +2 -1
  12. package/dist/components/table/components/TableBody.js +2 -0
  13. package/dist/components/table/components/TableHeader.cjs +1 -10
  14. package/dist/components/table/components/TableHeader.d.ts +1 -2
  15. package/dist/components/table/components/TableHeader.js +1 -10
  16. package/dist/components/table/components/TableRow.cjs +89 -68
  17. package/dist/components/table/components/TableRow.d.ts +2 -1
  18. package/dist/components/table/components/TableRow.js +89 -68
  19. package/dist/components/table/table.utils.cjs +0 -2
  20. package/dist/components/table/table.utils.d.ts +0 -1
  21. package/dist/components/table/table.utils.js +1 -2
  22. package/dist/components/table/tanstackTable.utils.cjs +2 -2
  23. package/dist/components/table/tanstackTable.utils.js +3 -3
  24. package/dist/hooks/useSorting.cjs +1 -0
  25. package/dist/hooks/useSorting.d.ts +6 -5
  26. package/dist/hooks/useSorting.js +1 -1
  27. package/dist/hooks/useTableData.cjs +29 -7
  28. package/dist/hooks/useTableData.d.ts +3 -1
  29. package/dist/hooks/useTableData.js +31 -9
  30. package/package.json +1 -1
@@ -106,7 +106,7 @@ function ExpandableSidebarItem({
106
106
  );
107
107
  };
108
108
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.container}`, children: [
109
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.itemRow, children: [
109
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${styles__default.default.itemRow} ${expanded ? styles__default.default.itemRowExpanded : ""}`, children: [
110
110
  /* @__PURE__ */ jsxRuntime.jsx(Component, { onClick: () => toggleAccordion(void 0, true), children: /* @__PURE__ */ jsxRuntime.jsx(
111
111
  SidebarItemContent.SidebarItemContent,
112
112
  {
@@ -116,23 +116,25 @@ function ExpandableSidebarItem({
116
116
  label,
117
117
  href,
118
118
  disableActiveStyles: expanded,
119
+ suffixIcon: !isSidebarCollapsed ? /* @__PURE__ */ jsxRuntime.jsx(
120
+ lucideReact.ChevronDown,
121
+ {
122
+ className: `${styles__default.default.chevron} ${expanded ? styles__default.default.chevronExpanded : ""}`
123
+ }
124
+ ) : void 0,
119
125
  truncateLabel
120
126
  }
121
127
  ) }),
122
128
  !isSidebarCollapsed && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.toggleButton, children: /* @__PURE__ */ jsxRuntime.jsx(
123
129
  Button.Button,
124
130
  {
125
- variant: "outlined",
131
+ variant: "inline",
132
+ shape: "round",
133
+ className: styles__default.default.toggleButtonControl,
126
134
  "aria-label": expanded ? `Collapse ${label}` : `Expand ${label}`,
127
135
  "aria-expanded": expanded,
128
136
  "aria-controls": `${href}-children`,
129
- onClick: toggleAccordion,
130
- children: /* @__PURE__ */ jsxRuntime.jsx(
131
- lucideReact.ChevronDown,
132
- {
133
- className: `${styles__default.default.chevron} ${expanded ? styles__default.default.chevronExpanded : ""}`
134
- }
135
- )
137
+ onClick: toggleAccordion
136
138
  }
137
139
  ) })
138
140
  ] }),
@@ -100,7 +100,7 @@ function ExpandableSidebarItem({
100
100
  );
101
101
  };
102
102
  return /* @__PURE__ */ jsxs("div", { className: `${styles.container}`, children: [
103
- /* @__PURE__ */ jsxs("div", { className: styles.itemRow, children: [
103
+ /* @__PURE__ */ jsxs("div", { className: `${styles.itemRow} ${expanded ? styles.itemRowExpanded : ""}`, children: [
104
104
  /* @__PURE__ */ jsx(Component, { onClick: () => toggleAccordion(void 0, true), children: /* @__PURE__ */ jsx(
105
105
  SidebarItemContent,
106
106
  {
@@ -110,23 +110,25 @@ function ExpandableSidebarItem({
110
110
  label,
111
111
  href,
112
112
  disableActiveStyles: expanded,
113
+ suffixIcon: !isSidebarCollapsed ? /* @__PURE__ */ jsx(
114
+ ChevronDown,
115
+ {
116
+ className: `${styles.chevron} ${expanded ? styles.chevronExpanded : ""}`
117
+ }
118
+ ) : void 0,
113
119
  truncateLabel
114
120
  }
115
121
  ) }),
116
122
  !isSidebarCollapsed && /* @__PURE__ */ jsx("div", { className: styles.toggleButton, children: /* @__PURE__ */ jsx(
117
123
  Button,
118
124
  {
119
- variant: "outlined",
125
+ variant: "inline",
126
+ shape: "round",
127
+ className: styles.toggleButtonControl,
120
128
  "aria-label": expanded ? `Collapse ${label}` : `Expand ${label}`,
121
129
  "aria-expanded": expanded,
122
130
  "aria-controls": `${href}-children`,
123
- onClick: toggleAccordion,
124
- children: /* @__PURE__ */ jsx(
125
- ChevronDown,
126
- {
127
- className: `${styles.chevron} ${expanded ? styles.chevronExpanded : ""}`
128
- }
129
- )
131
+ onClick: toggleAccordion
130
132
  }
131
133
  ) })
132
134
  ] }),
@@ -6,28 +6,32 @@
6
6
  }
7
7
 
8
8
  .itemRow {
9
- display: grid;
10
- grid-template-columns: minmax(0, 1fr) auto;
11
- align-items: center;
12
- column-gap: var(--spacing-xs);
9
+ position: relative;
10
+ display: block;
11
+ border-radius: var(--border-radius-md);
13
12
  }
14
13
 
15
14
  .toggleButton {
16
- display: flex;
15
+ position: absolute;
16
+ inset-inline-end: var(--spacing-xs);
17
+ inset-block-start: 50%;
18
+ transform: translateY(-50%);
19
+ display: inline-flex;
17
20
  align-items: center;
18
21
  justify-content: center;
19
- flex: 0 0 auto;
20
22
  }
21
23
 
22
24
  .container button {
23
- color: var(--color-text);
24
- min-block-size: 20px !important;
25
- min-inline-size: 20px !important;
26
- max-block-size: 20px !important;
27
- max-inline-size: 20px !important;
28
- &:hover {
29
- background-color: var(--color-bg-contextual-subtle) !important;
30
- }
25
+ min-block-size: 28px !important;
26
+ min-inline-size: 28px !important;
27
+ max-block-size: 28px !important;
28
+ max-inline-size: 28px !important;
29
+ border-color: transparent !important;
30
+ background-color: transparent !important;
31
+ }
32
+
33
+ .toggleButtonControl {
34
+ opacity: 0;
31
35
  }
32
36
 
33
37
  .childrenContainer {
@@ -53,6 +53,18 @@
53
53
  color: var(--color-fg-default);
54
54
  }
55
55
 
56
+ .container:not(.active):hover .icon,
57
+ .container:not(.active):hover .suffixIcon,
58
+ .container:focus-visible .icon,
59
+ .container:focus-visible .suffixIcon {
60
+ color: var(--color-fg-default);
61
+ }
62
+
63
+ .active .icon,
64
+ .active .suffixIcon {
65
+ color: var(--color-fg-default);
66
+ }
67
+
56
68
  .icon,
57
69
  .suffixIcon {
58
70
  inline-size: var(--sidebar-item-icon-width, auto);
@@ -52,6 +52,7 @@ function Table({
52
52
  showHeader = true,
53
53
  getRowSeverity,
54
54
  getContextMenuItems,
55
+ showContextMenuOnHover = true,
55
56
  onRowClick,
56
57
  onRowMouseEnter,
57
58
  onRowSelect,
@@ -65,7 +66,6 @@ function Table({
65
66
  const internalTableRootRef = react.useRef(null);
66
67
  const tableRootRefWrapper = react.useRef(tableRootRef);
67
68
  const hasSelection = Boolean(selectedRows && onRowSelect);
68
- const hasContextMenu = Boolean(getContextMenuItems);
69
69
  const hasPagination = Boolean(onPageChange && (loading || data.length > 0));
70
70
  const paginationOffset = hasPagination ? 72 : 0;
71
71
  const { style: viewportFillStyle, maxHeight } = useViewportFill.useViewportFill(internalTableRootRef, {
@@ -102,6 +102,7 @@ function Table({
102
102
  viewMode,
103
103
  getRowSeverity,
104
104
  getContextMenuItems,
105
+ showContextMenuOnHover,
105
106
  onRowClick,
106
107
  onRowMouseEnter,
107
108
  onRowSelect
@@ -158,15 +159,13 @@ function Table({
158
159
  style: column.width != null ? { width: column.width } : void 0
159
160
  },
160
161
  column.id
161
- )),
162
- hasContextMenu ? /* @__PURE__ */ jsxRuntime.jsx("col", { style: { width: table_utils.CONTEXT_MENU_COLUMN_PX } }) : null
162
+ ))
163
163
  ] }),
164
164
  showHeader && /* @__PURE__ */ jsxRuntime.jsx(
165
165
  TableHeader.TableHeader,
166
166
  {
167
167
  columns: visibleColumns,
168
168
  hasSelection,
169
- hasContextMenu,
170
169
  selectionMode,
171
170
  allRowsSelected,
172
171
  onSelectAllRows,
@@ -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, striped, fillViewport, fillViewportBottomOffset, containScrolling, stickyHeader, tableWidth, tableRootRef, measuringLayout, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement, showFirstLast, showGoToPage, showPageSize, pageSizeOptions, showHeader, getRowSeverity, getContextMenuItems, onRowClick, onRowMouseEnter, onRowSelect, onSelectAllRows, onSortChange, onPageChange, ...rest }: TableProps<T>): JSX.Element;
3
+ export declare function Table<T extends Record<string, any>>({ data, dataKey, columns, selectedRows, selectionMode, allRowsSelected, sortById, sortDirection, loading, emptyConfig, variant, size, viewMode, striped, fillViewport, fillViewportBottomOffset, containScrolling, stickyHeader, tableWidth, tableRootRef, measuringLayout, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement, showFirstLast, showGoToPage, showPageSize, pageSizeOptions, showHeader, getRowSeverity, getContextMenuItems, showContextMenuOnHover, onRowClick, onRowMouseEnter, onRowSelect, onSelectAllRows, onSortChange, onPageChange, ...rest }: TableProps<T>): JSX.Element;
4
4
  export type { ColumnItem } from './Table.types';
@@ -9,7 +9,7 @@ import { TableBody } from './components/TableBody';
9
9
  import { TableHeader } from './components/TableHeader';
10
10
  import { cx } from './table.classes';
11
11
  import styles from './Table.module.css';
12
- import { getVisibleColumns, SELECTION_COLUMN_PX, CONTEXT_MENU_COLUMN_PX } from './table.utils';
12
+ import { getVisibleColumns, SELECTION_COLUMN_PX } from './table.utils';
13
13
 
14
14
  function Table({
15
15
  data,
@@ -46,6 +46,7 @@ function Table({
46
46
  showHeader = true,
47
47
  getRowSeverity,
48
48
  getContextMenuItems,
49
+ showContextMenuOnHover = true,
49
50
  onRowClick,
50
51
  onRowMouseEnter,
51
52
  onRowSelect,
@@ -59,7 +60,6 @@ function Table({
59
60
  const internalTableRootRef = useRef(null);
60
61
  const tableRootRefWrapper = useRef(tableRootRef);
61
62
  const hasSelection = Boolean(selectedRows && onRowSelect);
62
- const hasContextMenu = Boolean(getContextMenuItems);
63
63
  const hasPagination = Boolean(onPageChange && (loading || data.length > 0));
64
64
  const paginationOffset = hasPagination ? 72 : 0;
65
65
  const { style: viewportFillStyle, maxHeight } = useViewportFill(internalTableRootRef, {
@@ -96,6 +96,7 @@ function Table({
96
96
  viewMode,
97
97
  getRowSeverity,
98
98
  getContextMenuItems,
99
+ showContextMenuOnHover,
99
100
  onRowClick,
100
101
  onRowMouseEnter,
101
102
  onRowSelect
@@ -152,15 +153,13 @@ function Table({
152
153
  style: column.width != null ? { width: column.width } : void 0
153
154
  },
154
155
  column.id
155
- )),
156
- hasContextMenu ? /* @__PURE__ */ jsx("col", { style: { width: CONTEXT_MENU_COLUMN_PX } }) : null
156
+ ))
157
157
  ] }),
158
158
  showHeader && /* @__PURE__ */ jsx(
159
159
  TableHeader,
160
160
  {
161
161
  columns: visibleColumns,
162
162
  hasSelection,
163
- hasContextMenu,
164
163
  selectionMode,
165
164
  allRowsSelected,
166
165
  onSelectAllRows,
@@ -241,14 +241,6 @@
241
241
  line-height: 0;
242
242
  }
243
243
 
244
- .headerCell.contextMenuCell,
245
- .cell.contextMenuCell {
246
- inline-size: 1%;
247
- white-space: nowrap;
248
- padding-inline: var(--spacing-2xs);
249
- overflow: visible;
250
- }
251
-
252
244
  .headerCell.selectionCell {
253
245
  padding-block: var(--spacing-xxs);
254
246
  vertical-align: middle;
@@ -259,19 +251,10 @@
259
251
  padding-block: var(--spacing-xxs);
260
252
  }
261
253
 
262
- .headerCell.contextMenuHeaderCell {
263
- padding-block: var(--spacing-xxs);
264
- }
265
-
266
254
  .headerCell:hover [data-resizer='true']::after {
267
255
  opacity: 1;
268
256
  }
269
257
 
270
- .cell.contextMenuCell {
271
- vertical-align: top;
272
- padding-block: var(--spacing-2xs);
273
- }
274
-
275
258
  .selectionHitArea {
276
259
  display: inline-flex;
277
260
  align-items: flex-start;
@@ -496,10 +479,6 @@
496
479
  text-align: right;
497
480
  }
498
481
 
499
- .contextMenuCellContent {
500
- justify-content: flex-end;
501
- }
502
-
503
482
  /* vertical alignment inside content wrapper */
504
483
  .cellContent[data-vertical-align='top'] {
505
484
  align-items: flex-start;
@@ -562,6 +541,58 @@
562
541
 
563
542
  .contextMenuTrigger {
564
543
  color: var(--color-fg-subtle);
544
+ min-inline-size: 36px;
545
+ min-block-size: 36px;
546
+ border-radius: var(--border-radius-rounded);
547
+ }
548
+
549
+ .contextMenuAnchorCell {
550
+ overflow: visible;
551
+ }
552
+
553
+ .contextMenuAnchorCell .cellValueEllipsis,
554
+ .contextMenuAnchorCell .cellValueNoEllipsis {
555
+ padding-inline-end: calc(36px + var(--spacing-sm));
556
+ }
557
+
558
+ .contextMenuOverlay {
559
+ position: absolute;
560
+ inset-block-start: 50%;
561
+ inset-inline-end: 0;
562
+ transform: translateY(-50%);
563
+ display: inline-flex;
564
+ align-items: center;
565
+ justify-content: center;
566
+ min-inline-size: 40px;
567
+ min-block-size: 40px;
568
+ z-index: 3;
569
+ }
570
+
571
+ .contextMenuOverlay:hover .contextMenuTrigger,
572
+ .contextMenuOverlay:focus-within .contextMenuTrigger {
573
+ background-color: var(--opac-bg-light);
574
+ }
575
+
576
+ .contextMenuItemLabel {
577
+ display: inline-flex;
578
+ align-items: flex-start;
579
+ gap: var(--spacing-xs);
580
+ min-width: 0;
581
+ }
582
+
583
+ .contextMenuItemText {
584
+ min-width: 0;
585
+ }
586
+
587
+ .contextMenuHoverOnly .contextMenuTrigger {
588
+ opacity: 0;
589
+ pointer-events: none;
590
+ }
591
+
592
+ .contextMenuHoverOnly:hover .contextMenuTrigger,
593
+ .contextMenuHoverOnly:focus-within .contextMenuTrigger {
594
+ opacity: 1;
595
+ pointer-events: auto;
565
596
  }
566
597
 
567
598
  .severityTable {
@@ -24,14 +24,21 @@ export type HeaderExtrasArgs<T> = {
24
24
  column: ColumnItem<T>;
25
25
  index: number;
26
26
  };
27
- export type TableContextMenuItem = {
27
+ export type TableContextMenuActionItem = {
28
+ type?: 'item';
28
29
  label: ReactNode;
30
+ icon?: ReactNode;
29
31
  onClick: () => void;
30
32
  active?: boolean;
31
33
  selected?: boolean;
32
34
  disabled?: boolean;
33
35
  variant?: 'default' | 'danger';
34
36
  };
37
+ export type TableContextMenuHeaderItem = {
38
+ type: 'header';
39
+ label: ReactNode;
40
+ };
41
+ export type TableContextMenuItem = TableContextMenuActionItem | TableContextMenuHeaderItem;
35
42
  export type StickyHeader = false | 'app-header' | number;
36
43
  export type TableVariant = 'primary' | 'embedded';
37
44
  export type SortDirection = 'asc' | 'desc' | null;
@@ -74,6 +81,7 @@ export type TableProps<T extends Record<string, any>> = Omit<HTMLAttributes<HTML
74
81
  rowId: string | number;
75
82
  open: () => void;
76
83
  }) => TableContextMenuItem[];
84
+ showContextMenuOnHover?: boolean;
77
85
  onRowClick?: (row: T) => void;
78
86
  onRowMouseEnter?: (row: T) => void;
79
87
  onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
@@ -21,6 +21,7 @@ function TableBody({
21
21
  viewMode,
22
22
  getRowSeverity,
23
23
  getContextMenuItems,
24
+ showContextMenuOnHover,
24
25
  onRowClick,
25
26
  onRowMouseEnter,
26
27
  onRowSelect
@@ -40,6 +41,7 @@ function TableBody({
40
41
  viewMode,
41
42
  getRowSeverity,
42
43
  getContextMenuItems,
44
+ showContextMenuOnHover,
43
45
  onRowClick,
44
46
  onRowMouseEnter,
45
47
  onRowSelect
@@ -17,9 +17,10 @@ type Props<T extends Record<string, any>> = {
17
17
  rowId: string | number;
18
18
  open: () => void;
19
19
  }) => TableContextMenuItem[];
20
+ showContextMenuOnHover: boolean;
20
21
  onRowClick?: (row: T) => void;
21
22
  onRowMouseEnter?: (row: T) => void;
22
23
  onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
23
24
  };
24
- export declare function TableBody<T extends Record<string, any>>({ data, dataKey, columns, striped, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, getContextMenuItems, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): ReactNode;
25
+ export declare function TableBody<T extends Record<string, any>>({ data, dataKey, columns, striped, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, getContextMenuItems, showContextMenuOnHover, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): ReactNode;
25
26
  export {};
@@ -15,6 +15,7 @@ function TableBody({
15
15
  viewMode,
16
16
  getRowSeverity,
17
17
  getContextMenuItems,
18
+ showContextMenuOnHover,
18
19
  onRowClick,
19
20
  onRowMouseEnter,
20
21
  onRowSelect
@@ -34,6 +35,7 @@ function TableBody({
34
35
  viewMode,
35
36
  getRowSeverity,
36
37
  getContextMenuItems,
38
+ showContextMenuOnHover,
37
39
  onRowClick,
38
40
  onRowMouseEnter,
39
41
  onRowSelect
@@ -12,7 +12,6 @@ var styles__default = /*#__PURE__*/_interopDefault(styles);
12
12
  function TableHeader({
13
13
  columns,
14
14
  hasSelection,
15
- hasContextMenu,
16
15
  selectionMode,
17
16
  allRowsSelected,
18
17
  onSelectAllRows,
@@ -48,15 +47,7 @@ function TableHeader({
48
47
  extraContent: headerExtras == null ? void 0 : headerExtras({ column, index })
49
48
  },
50
49
  column.id
51
- )),
52
- hasContextMenu ? /* @__PURE__ */ jsxRuntime.jsx(
53
- "th",
54
- {
55
- className: [styles__default.default.headerCell, styles__default.default.contextMenuCell, styles__default.default.contextMenuHeaderCell].filter(Boolean).join(" "),
56
- scope: "col",
57
- "aria-label": "R\xE6kkehandlinger"
58
- }
59
- ) : null
50
+ ))
60
51
  ] })
61
52
  }
62
53
  );
@@ -3,7 +3,6 @@ import type { ColumnItem, HeaderExtrasArgs, SortDirection } from '../Table.types
3
3
  type Props<T> = {
4
4
  columns: ColumnItem<T>[];
5
5
  hasSelection: boolean;
6
- hasContextMenu: boolean;
7
6
  selectionMode: 'single' | 'multiple';
8
7
  allRowsSelected?: boolean;
9
8
  onSelectAllRows?: (isSelected: boolean) => void;
@@ -13,5 +12,5 @@ type Props<T> = {
13
12
  headerExtras?: (args: HeaderExtrasArgs<T>) => ReactNode;
14
13
  stickyTop?: string;
15
14
  };
16
- export declare function TableHeader<T>({ columns, hasSelection, hasContextMenu, selectionMode, allRowsSelected, onSelectAllRows, sortById, sortDirection, onSortChange, headerExtras, stickyTop, }: Props<T>): React.ReactNode;
15
+ export declare function TableHeader<T>({ columns, hasSelection, selectionMode, allRowsSelected, onSelectAllRows, sortById, sortDirection, onSortChange, headerExtras, stickyTop, }: Props<T>): React.ReactNode;
17
16
  export {};
@@ -6,7 +6,6 @@ import styles from '../Table.module.css';
6
6
  function TableHeader({
7
7
  columns,
8
8
  hasSelection,
9
- hasContextMenu,
10
9
  selectionMode,
11
10
  allRowsSelected,
12
11
  onSelectAllRows,
@@ -42,15 +41,7 @@ function TableHeader({
42
41
  extraContent: headerExtras == null ? void 0 : headerExtras({ column, index })
43
42
  },
44
43
  column.id
45
- )),
46
- hasContextMenu ? /* @__PURE__ */ jsx(
47
- "th",
48
- {
49
- className: [styles.headerCell, styles.contextMenuCell, styles.contextMenuHeaderCell].filter(Boolean).join(" "),
50
- scope: "col",
51
- "aria-label": "R\xE6kkehandlinger"
52
- }
53
- ) : null
44
+ ))
54
45
  ] })
55
46
  }
56
47
  );
@@ -2,6 +2,7 @@
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var lucideReact = require('lucide-react');
5
+ var react = require('react');
5
6
  var Checkbox = require('../../../components/forms/checkbox/Checkbox');
6
7
  var RadioButton = require('../../../components/forms/radio-buttons/RadioButton');
7
8
  var Popover = require('../../../components/popover/Popover');
@@ -28,6 +29,7 @@ function TableRow({
28
29
  viewMode,
29
30
  getRowSeverity,
30
31
  getContextMenuItems,
32
+ showContextMenuOnHover,
31
33
  onRowClick,
32
34
  onRowMouseEnter,
33
35
  onRowSelect
@@ -41,6 +43,7 @@ function TableRow({
41
43
  rowId,
42
44
  open: () => onRowClick == null ? void 0 : onRowClick(row)
43
45
  });
46
+ const hasContextMenu = Boolean(contextMenuItems == null ? void 0 : contextMenuItems.length);
44
47
  const { handleRowClick, handleRowKeyDown } = useTableRowInteractions.useTableRowInteractions({
45
48
  row,
46
49
  rowId,
@@ -56,8 +59,10 @@ function TableRow({
56
59
  styles__default.default.row,
57
60
  onRowClick && styles__default.default.clickableRow,
58
61
  isSelected && styles__default.default.selectedRow,
59
- rowSeverity && styles__default.default.severity
62
+ rowSeverity && styles__default.default.severity,
63
+ hasContextMenu && showContextMenuOnHover && styles__default.default.contextMenuHoverOnly
60
64
  ),
65
+ "data-context-menu-visibility": hasContextMenu ? showContextMenuOnHover ? "hover" : "always" : void 0,
61
66
  style: {
62
67
  ["--row-severity-color"]: rowSeverity ? `color-mix(in srgb, ${severity.SeverityBgColor[rowSeverity]} 65%, var(--table-component-row-bg))` : void 0
63
68
  },
@@ -124,10 +129,11 @@ function TableRow({
124
129
  }
125
130
  ) }) : null,
126
131
  columns.map((column) => {
127
- var _a2, _b, _c, _d;
132
+ var _a2, _b, _c, _d, _e;
128
133
  const allowWrap = table_utils.shouldAllowWrap(column.allowWrap, isSelected, viewMode);
129
134
  const allowOverflow = column.allowOverflow;
130
135
  const cellValue = table_utils.getCellDisplayValue(row, column);
136
+ const isLastColumn = column.id === ((_a2 = columns[columns.length - 1]) == null ? void 0 : _a2.id);
131
137
  return /* @__PURE__ */ jsxRuntime.jsx(
132
138
  "td",
133
139
  {
@@ -135,96 +141,111 @@ function TableRow({
135
141
  styles__default.default.cell,
136
142
  allowOverflow && styles__default.default.allowOverflow,
137
143
  allowWrap ? styles__default.default.allowWrap : styles__default.default.nowrap,
144
+ hasContextMenu && isLastColumn && styles__default.default.contextMenuAnchorCell,
138
145
  column.divider === "left" && styles__default.default.dividerLeft,
139
146
  column.divider === "right" && styles__default.default.dividerRight
140
147
  ),
141
- "data-align": (_a2 = column.align) != null ? _a2 : "left",
142
- "data-vertical-align": (_b = column.verticalAlign) != null ? _b : "top",
148
+ "data-align": (_b = column.align) != null ? _b : "left",
149
+ "data-vertical-align": (_c = column.verticalAlign) != null ? _c : "top",
143
150
  "data-divider": column.divider,
144
- children: /* @__PURE__ */ jsxRuntime.jsx(
151
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
145
152
  "div",
146
153
  {
147
154
  className: styles__default.default.cellContent,
148
- "data-align": (_c = column.align) != null ? _c : "left",
149
- "data-vertical-align": (_d = column.verticalAlign) != null ? _d : "top",
150
- children: /* @__PURE__ */ jsxRuntime.jsx(
151
- "div",
152
- {
153
- className: allowOverflow ? styles__default.default.cellValueNoEllipsis : styles__default.default.cellValueEllipsis,
154
- children: cellValue
155
- }
156
- )
155
+ "data-align": (_d = column.align) != null ? _d : "left",
156
+ "data-vertical-align": (_e = column.verticalAlign) != null ? _e : "top",
157
+ children: [
158
+ /* @__PURE__ */ jsxRuntime.jsx(
159
+ "div",
160
+ {
161
+ className: allowOverflow ? styles__default.default.cellValueNoEllipsis : styles__default.default.cellValueEllipsis,
162
+ children: cellValue
163
+ }
164
+ ),
165
+ hasContextMenu && isLastColumn ? /* @__PURE__ */ jsxRuntime.jsx(RowContextMenu, { rowId, items: contextMenuItems }) : null
166
+ ]
157
167
  }
158
168
  )
159
169
  },
160
170
  column.id
161
171
  );
162
- }),
163
- (contextMenuItems == null ? void 0 : contextMenuItems.length) ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: table_classes.cx(styles__default.default.cell, styles__default.default.contextMenuCell), "data-row-context-menu": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
164
- "div",
165
- {
166
- className: table_classes.cx(styles__default.default.cellContent, styles__default.default.contextMenuCellContent),
167
- "data-align": "right",
168
- "data-row-context-menu": "true",
169
- children: /* @__PURE__ */ jsxRuntime.jsx(RowContextMenu, { row, rowId, items: contextMenuItems })
170
- }
171
- ) }) : null
172
+ })
172
173
  ]
173
174
  }
174
175
  );
175
176
  }
176
177
  function RowContextMenu({
177
- row,
178
178
  rowId,
179
179
  items
180
180
  }) {
181
+ const toggleRef = react.useRef(null);
181
182
  return /* @__PURE__ */ jsxRuntime.jsx(
182
- Popover.Popover,
183
+ "div",
183
184
  {
184
- matchTriggerWidth: false,
185
- minWidth: "180px",
186
- trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsxRuntime.jsx(
187
- Button.Button,
188
- {
189
- type: "button",
190
- size: "sm",
191
- variant: "inline",
192
- shape: "round",
193
- className: styles__default.default.contextMenuTrigger,
194
- "aria-label": `Flere handlinger for r\xE6kke ${String(rowId)}`,
195
- "aria-haspopup": "menu",
196
- "aria-expanded": isOpen ? true : false,
197
- icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { size: 16 }),
198
- "data-row-context-menu": "true",
199
- onClick: (e) => {
200
- e.stopPropagation();
201
- toggle(e);
202
- }
203
- }
204
- ),
205
- children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
206
- Menu.Menu.Item,
185
+ className: styles__default.default.contextMenuOverlay,
186
+ "data-row-context-menu": "true",
187
+ onClick: (e) => {
188
+ var _a;
189
+ e.stopPropagation();
190
+ (_a = toggleRef.current) == null ? void 0 : _a.call(toggleRef, e);
191
+ },
192
+ children: /* @__PURE__ */ jsxRuntime.jsx(
193
+ Popover.Popover,
207
194
  {
208
- active: item.active,
209
- selected: item.selected,
210
- disabled: item.disabled,
211
- variant: item.variant,
212
- children: /* @__PURE__ */ jsxRuntime.jsx(
213
- "button",
214
- {
215
- type: "button",
216
- "data-row-context-menu": "true",
217
- onClick: (e) => {
218
- e.stopPropagation();
219
- item.onClick();
220
- close();
195
+ matchTriggerWidth: false,
196
+ minWidth: "180px",
197
+ trigger: (toggle, _icon, isOpen) => {
198
+ toggleRef.current = toggle;
199
+ return /* @__PURE__ */ jsxRuntime.jsx(
200
+ Button.Button,
201
+ {
202
+ type: "button",
203
+ size: "sm",
204
+ variant: "inline",
205
+ shape: "round",
206
+ className: styles__default.default.contextMenuTrigger,
207
+ "aria-label": `Flere handlinger for r\xE6kke ${String(rowId)}`,
208
+ "aria-haspopup": "menu",
209
+ "aria-expanded": isOpen ? true : false,
210
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreVertical, { size: 16 }),
211
+ "data-row-context-menu": "true",
212
+ onClick: (e) => {
213
+ e.stopPropagation();
214
+ toggle(e);
215
+ }
216
+ }
217
+ );
218
+ },
219
+ children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children: items.map(
220
+ (item, index) => item.type === "header" ? /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu.Header, { children: item.label }, index) : /* @__PURE__ */ jsxRuntime.jsx(
221
+ Menu.Menu.Item,
222
+ {
223
+ active: item.active,
224
+ selected: item.selected,
225
+ disabled: item.disabled,
226
+ variant: item.variant,
227
+ children: /* @__PURE__ */ jsxRuntime.jsx(
228
+ "button",
229
+ {
230
+ type: "button",
231
+ "data-row-context-menu": "true",
232
+ onClick: (e) => {
233
+ e.stopPropagation();
234
+ item.onClick();
235
+ close();
236
+ },
237
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: styles__default.default.contextMenuItemLabel, children: [
238
+ item.icon,
239
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.contextMenuItemText, children: item.label })
240
+ ] })
241
+ }
242
+ )
221
243
  },
222
- children: item.label
223
- }
224
- )
225
- },
226
- index
227
- )) })
244
+ index
245
+ )
246
+ ) })
247
+ }
248
+ )
228
249
  }
229
250
  );
230
251
  }
@@ -16,9 +16,10 @@ type Props<T extends Record<string, any>> = {
16
16
  rowId: string | number;
17
17
  open: () => void;
18
18
  }) => TableContextMenuItem[];
19
+ showContextMenuOnHover: boolean;
19
20
  onRowClick?: (row: T) => void;
20
21
  onRowMouseEnter?: (row: T) => void;
21
22
  onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
22
23
  };
23
- export declare function TableRow<T extends Record<string, any>>({ row, rowId, columns, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, getContextMenuItems, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): React.ReactNode;
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;
24
25
  export {};
@@ -1,5 +1,6 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import { MoreVertical } from 'lucide-react';
3
+ import { useRef } from 'react';
3
4
  import { Checkbox } from '../../../components/forms/checkbox/Checkbox';
4
5
  import { RadioButton } from '../../../components/forms/radio-buttons/RadioButton';
5
6
  import { Popover } from '../../../components/popover/Popover';
@@ -22,6 +23,7 @@ function TableRow({
22
23
  viewMode,
23
24
  getRowSeverity,
24
25
  getContextMenuItems,
26
+ showContextMenuOnHover,
25
27
  onRowClick,
26
28
  onRowMouseEnter,
27
29
  onRowSelect
@@ -35,6 +37,7 @@ function TableRow({
35
37
  rowId,
36
38
  open: () => onRowClick == null ? void 0 : onRowClick(row)
37
39
  });
40
+ const hasContextMenu = Boolean(contextMenuItems == null ? void 0 : contextMenuItems.length);
38
41
  const { handleRowClick, handleRowKeyDown } = useTableRowInteractions({
39
42
  row,
40
43
  rowId,
@@ -50,8 +53,10 @@ function TableRow({
50
53
  styles.row,
51
54
  onRowClick && styles.clickableRow,
52
55
  isSelected && styles.selectedRow,
53
- rowSeverity && styles.severity
56
+ rowSeverity && styles.severity,
57
+ hasContextMenu && showContextMenuOnHover && styles.contextMenuHoverOnly
54
58
  ),
59
+ "data-context-menu-visibility": hasContextMenu ? showContextMenuOnHover ? "hover" : "always" : void 0,
55
60
  style: {
56
61
  ["--row-severity-color"]: rowSeverity ? `color-mix(in srgb, ${SeverityBgColor[rowSeverity]} 65%, var(--table-component-row-bg))` : void 0
57
62
  },
@@ -118,10 +123,11 @@ function TableRow({
118
123
  }
119
124
  ) }) : null,
120
125
  columns.map((column) => {
121
- var _a2, _b, _c, _d;
126
+ var _a2, _b, _c, _d, _e;
122
127
  const allowWrap = shouldAllowWrap(column.allowWrap, isSelected, viewMode);
123
128
  const allowOverflow = column.allowOverflow;
124
129
  const cellValue = getCellDisplayValue(row, column);
130
+ const isLastColumn = column.id === ((_a2 = columns[columns.length - 1]) == null ? void 0 : _a2.id);
125
131
  return /* @__PURE__ */ jsx(
126
132
  "td",
127
133
  {
@@ -129,96 +135,111 @@ function TableRow({
129
135
  styles.cell,
130
136
  allowOverflow && styles.allowOverflow,
131
137
  allowWrap ? styles.allowWrap : styles.nowrap,
138
+ hasContextMenu && isLastColumn && styles.contextMenuAnchorCell,
132
139
  column.divider === "left" && styles.dividerLeft,
133
140
  column.divider === "right" && styles.dividerRight
134
141
  ),
135
- "data-align": (_a2 = column.align) != null ? _a2 : "left",
136
- "data-vertical-align": (_b = column.verticalAlign) != null ? _b : "top",
142
+ "data-align": (_b = column.align) != null ? _b : "left",
143
+ "data-vertical-align": (_c = column.verticalAlign) != null ? _c : "top",
137
144
  "data-divider": column.divider,
138
- children: /* @__PURE__ */ jsx(
145
+ children: /* @__PURE__ */ jsxs(
139
146
  "div",
140
147
  {
141
148
  className: styles.cellContent,
142
- "data-align": (_c = column.align) != null ? _c : "left",
143
- "data-vertical-align": (_d = column.verticalAlign) != null ? _d : "top",
144
- children: /* @__PURE__ */ jsx(
145
- "div",
146
- {
147
- className: allowOverflow ? styles.cellValueNoEllipsis : styles.cellValueEllipsis,
148
- children: cellValue
149
- }
150
- )
149
+ "data-align": (_d = column.align) != null ? _d : "left",
150
+ "data-vertical-align": (_e = column.verticalAlign) != null ? _e : "top",
151
+ children: [
152
+ /* @__PURE__ */ jsx(
153
+ "div",
154
+ {
155
+ className: allowOverflow ? styles.cellValueNoEllipsis : styles.cellValueEllipsis,
156
+ children: cellValue
157
+ }
158
+ ),
159
+ hasContextMenu && isLastColumn ? /* @__PURE__ */ jsx(RowContextMenu, { rowId, items: contextMenuItems }) : null
160
+ ]
151
161
  }
152
162
  )
153
163
  },
154
164
  column.id
155
165
  );
156
- }),
157
- (contextMenuItems == null ? void 0 : contextMenuItems.length) ? /* @__PURE__ */ jsx("td", { className: cx(styles.cell, styles.contextMenuCell), "data-row-context-menu": "true", children: /* @__PURE__ */ jsx(
158
- "div",
159
- {
160
- className: cx(styles.cellContent, styles.contextMenuCellContent),
161
- "data-align": "right",
162
- "data-row-context-menu": "true",
163
- children: /* @__PURE__ */ jsx(RowContextMenu, { row, rowId, items: contextMenuItems })
164
- }
165
- ) }) : null
166
+ })
166
167
  ]
167
168
  }
168
169
  );
169
170
  }
170
171
  function RowContextMenu({
171
- row,
172
172
  rowId,
173
173
  items
174
174
  }) {
175
+ const toggleRef = useRef(null);
175
176
  return /* @__PURE__ */ jsx(
176
- Popover,
177
+ "div",
177
178
  {
178
- matchTriggerWidth: false,
179
- minWidth: "180px",
180
- trigger: (toggle, _icon, isOpen) => /* @__PURE__ */ jsx(
181
- Button,
182
- {
183
- type: "button",
184
- size: "sm",
185
- variant: "inline",
186
- shape: "round",
187
- className: styles.contextMenuTrigger,
188
- "aria-label": `Flere handlinger for r\xE6kke ${String(rowId)}`,
189
- "aria-haspopup": "menu",
190
- "aria-expanded": isOpen ? true : false,
191
- icon: /* @__PURE__ */ jsx(MoreVertical, { size: 16 }),
192
- "data-row-context-menu": "true",
193
- onClick: (e) => {
194
- e.stopPropagation();
195
- toggle(e);
196
- }
197
- }
198
- ),
199
- children: (close) => /* @__PURE__ */ jsx(Menu, { children: items.map((item, index) => /* @__PURE__ */ jsx(
200
- Menu.Item,
179
+ className: styles.contextMenuOverlay,
180
+ "data-row-context-menu": "true",
181
+ onClick: (e) => {
182
+ var _a;
183
+ e.stopPropagation();
184
+ (_a = toggleRef.current) == null ? void 0 : _a.call(toggleRef, e);
185
+ },
186
+ children: /* @__PURE__ */ jsx(
187
+ Popover,
201
188
  {
202
- active: item.active,
203
- selected: item.selected,
204
- disabled: item.disabled,
205
- variant: item.variant,
206
- children: /* @__PURE__ */ jsx(
207
- "button",
208
- {
209
- type: "button",
210
- "data-row-context-menu": "true",
211
- onClick: (e) => {
212
- e.stopPropagation();
213
- item.onClick();
214
- close();
189
+ matchTriggerWidth: false,
190
+ minWidth: "180px",
191
+ trigger: (toggle, _icon, isOpen) => {
192
+ toggleRef.current = toggle;
193
+ return /* @__PURE__ */ jsx(
194
+ Button,
195
+ {
196
+ type: "button",
197
+ size: "sm",
198
+ variant: "inline",
199
+ shape: "round",
200
+ className: styles.contextMenuTrigger,
201
+ "aria-label": `Flere handlinger for r\xE6kke ${String(rowId)}`,
202
+ "aria-haspopup": "menu",
203
+ "aria-expanded": isOpen ? true : false,
204
+ icon: /* @__PURE__ */ jsx(MoreVertical, { size: 16 }),
205
+ "data-row-context-menu": "true",
206
+ onClick: (e) => {
207
+ e.stopPropagation();
208
+ toggle(e);
209
+ }
210
+ }
211
+ );
212
+ },
213
+ children: (close) => /* @__PURE__ */ jsx(Menu, { children: items.map(
214
+ (item, index) => item.type === "header" ? /* @__PURE__ */ jsx(Menu.Header, { children: item.label }, index) : /* @__PURE__ */ jsx(
215
+ Menu.Item,
216
+ {
217
+ active: item.active,
218
+ selected: item.selected,
219
+ disabled: item.disabled,
220
+ variant: item.variant,
221
+ children: /* @__PURE__ */ jsx(
222
+ "button",
223
+ {
224
+ type: "button",
225
+ "data-row-context-menu": "true",
226
+ onClick: (e) => {
227
+ e.stopPropagation();
228
+ item.onClick();
229
+ close();
230
+ },
231
+ children: /* @__PURE__ */ jsxs("span", { className: styles.contextMenuItemLabel, children: [
232
+ item.icon,
233
+ /* @__PURE__ */ jsx("span", { className: styles.contextMenuItemText, children: item.label })
234
+ ] })
235
+ }
236
+ )
215
237
  },
216
- children: item.label
217
- }
218
- )
219
- },
220
- index
221
- )) })
238
+ index
239
+ )
240
+ ) })
241
+ }
242
+ )
222
243
  }
223
244
  );
224
245
  }
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const SELECTION_COLUMN_PX = 40;
4
- const CONTEXT_MENU_COLUMN_PX = 44;
5
4
  const DEFAULT_COLUMN_PX = 150;
6
5
  function getVisibleColumns(columns) {
7
6
  return columns.filter((column) => !column.hidden);
@@ -45,7 +44,6 @@ function getCellDisplayValue(row, column) {
45
44
  return empty;
46
45
  }
47
46
 
48
- exports.CONTEXT_MENU_COLUMN_PX = CONTEXT_MENU_COLUMN_PX;
49
47
  exports.DEFAULT_COLUMN_PX = DEFAULT_COLUMN_PX;
50
48
  exports.SELECTION_COLUMN_PX = SELECTION_COLUMN_PX;
51
49
  exports.getAriaSort = getAriaSort;
@@ -1,7 +1,6 @@
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 CONTEXT_MENU_COLUMN_PX: 44;
5
4
  export declare const DEFAULT_COLUMN_PX: 150;
6
5
  export type SortDirection = 'asc' | 'desc' | null;
7
6
  export declare function getVisibleColumns<T>(columns: Array<ColumnItem<T>>): Array<ColumnItem<T>>;
@@ -1,5 +1,4 @@
1
1
  const SELECTION_COLUMN_PX = 40;
2
- const CONTEXT_MENU_COLUMN_PX = 44;
3
2
  const DEFAULT_COLUMN_PX = 150;
4
3
  function getVisibleColumns(columns) {
5
4
  return columns.filter((column) => !column.hidden);
@@ -43,4 +42,4 @@ function getCellDisplayValue(row, column) {
43
42
  return empty;
44
43
  }
45
44
 
46
- export { CONTEXT_MENU_COLUMN_PX, DEFAULT_COLUMN_PX, SELECTION_COLUMN_PX, getAriaSort, getCellDisplayValue, getHeaderLabel, getNextSortDirection, getVisibleColumns, isActiveSort, isModifierClick, shouldAllowWrap, shouldToggleOnKey };
45
+ export { DEFAULT_COLUMN_PX, SELECTION_COLUMN_PX, getAriaSort, getCellDisplayValue, getHeaderLabel, getNextSortDirection, getVisibleColumns, isActiveSort, isModifierClick, shouldAllowWrap, shouldToggleOnKey };
@@ -103,7 +103,7 @@ function buildDistributedColumnWidths(args) {
103
103
  } = args;
104
104
  const leaf = table.getVisibleLeafColumns();
105
105
  const selectionWidth = hasSelection ? table_utils.SELECTION_COLUMN_PX : 0;
106
- const contextMenuWidth = hasContextMenu ? table_utils.CONTEXT_MENU_COLUMN_PX : 0;
106
+ const contextMenuWidth = hasContextMenu ? 0 : 0;
107
107
  const tracks = leaf.map((c) => {
108
108
  var _a, _b, _c, _d;
109
109
  const def = c.columnDef;
@@ -165,7 +165,7 @@ function buildDistributedColumnWidths(args) {
165
165
  const totalWidth = selectionWidth + contextMenuWidth + Object.values(widths).reduce((sum, width) => sum + width, 0);
166
166
  return {
167
167
  selectionWidth: hasSelection ? table_utils.SELECTION_COLUMN_PX : void 0,
168
- contextMenuWidth: hasContextMenu ? table_utils.CONTEXT_MENU_COLUMN_PX : void 0,
168
+ contextMenuWidth: hasContextMenu ? 0 : void 0,
169
169
  widths,
170
170
  totalWidth,
171
171
  availableWidth,
@@ -1,4 +1,4 @@
1
- import { DEFAULT_COLUMN_PX, CONTEXT_MENU_COLUMN_PX, SELECTION_COLUMN_PX } from './table.utils';
1
+ import { DEFAULT_COLUMN_PX, SELECTION_COLUMN_PX } from './table.utils';
2
2
 
3
3
  function getColumnId(def, index) {
4
4
  const d = def;
@@ -101,7 +101,7 @@ function buildDistributedColumnWidths(args) {
101
101
  } = args;
102
102
  const leaf = table.getVisibleLeafColumns();
103
103
  const selectionWidth = hasSelection ? SELECTION_COLUMN_PX : 0;
104
- const contextMenuWidth = hasContextMenu ? CONTEXT_MENU_COLUMN_PX : 0;
104
+ const contextMenuWidth = hasContextMenu ? 0 : 0;
105
105
  const tracks = leaf.map((c) => {
106
106
  var _a, _b, _c, _d;
107
107
  const def = c.columnDef;
@@ -163,7 +163,7 @@ function buildDistributedColumnWidths(args) {
163
163
  const totalWidth = selectionWidth + contextMenuWidth + Object.values(widths).reduce((sum, width) => sum + width, 0);
164
164
  return {
165
165
  selectionWidth: hasSelection ? SELECTION_COLUMN_PX : void 0,
166
- contextMenuWidth: hasContextMenu ? CONTEXT_MENU_COLUMN_PX : void 0,
166
+ contextMenuWidth: hasContextMenu ? 0 : void 0,
167
167
  widths,
168
168
  totalWidth,
169
169
  availableWidth,
@@ -116,4 +116,5 @@ function useSorting({
116
116
  };
117
117
  }
118
118
 
119
+ exports.defaultCompare = defaultCompare;
119
120
  exports.useSorting = useSorting;
@@ -1,16 +1,16 @@
1
1
  export type SortDirection = 'asc' | 'desc' | null;
2
- export type SortState<T> = {
3
- sortBy: keyof T | null;
2
+ export type SortState<T = unknown> = {
3
+ sortBy: string | null;
4
4
  sortDirection: SortDirection;
5
5
  };
6
- export type SortEvent<T> = Partial<SortState<T>>;
7
- export type ColumnComparators<T> = Partial<Record<keyof T, (a: T, b: T, direction: Exclude<SortDirection, null>) => number>>;
6
+ export type SortEvent<T = unknown> = Partial<SortState<T>>;
7
+ export type ColumnComparators<T> = Partial<Record<string, (a: T, b: T, direction: Exclude<SortDirection, null>) => number>>;
8
8
  export interface UseSortingProps<T> {
9
9
  data?: readonly T[];
10
10
  /**
11
11
  * Default/initial state. If you pass `state`, these are ignored.
12
12
  */
13
- sortBy?: keyof T | null;
13
+ sortBy?: string | null;
14
14
  sortDirection?: SortDirection;
15
15
  /**
16
16
  * Controlled mode: if provided, hook will not keep its own state.
@@ -46,4 +46,5 @@ export interface UseSortingResult<T> {
46
46
  setSort: (next: SortState<T>) => void;
47
47
  clearSort: () => void;
48
48
  }
49
+ export declare function defaultCompare(a: unknown, b: unknown, dir: 'asc' | 'desc', nulls: 'first' | 'last'): number;
49
50
  export declare function useSorting<T extends Record<string, any>>({ data, sortBy, sortDirection, state, onStateChange, columnComparators, nulls, allowUnsort, resetOnDataChange, }: UseSortingProps<T>): UseSortingResult<T>;
@@ -114,4 +114,4 @@ function useSorting({
114
114
  };
115
115
  }
116
116
 
117
- export { useSorting };
117
+ export { defaultCompare, useSorting };
@@ -12,28 +12,50 @@ function useTableData({
12
12
  resetPageOnSortChange = true
13
13
  }) {
14
14
  var _a, _b, _c, _d, _e, _f;
15
+ const hasPagination = pagination != null;
16
+ const nullsMode = (_a = sorting == null ? void 0 : sorting.nulls) != null ? _a : "last";
17
+ const mergedComparators = react.useMemo(() => {
18
+ var _a2, _b2;
19
+ const derived = {};
20
+ for (const col of (_a2 = sorting == null ? void 0 : sorting.columns) != null ? _a2 : []) {
21
+ const colId = (_b2 = col.id) != null ? _b2 : col.accessorKey;
22
+ if (!colId) continue;
23
+ const accessorFn = col.accessorFn;
24
+ const accessorKey = col.accessorKey;
25
+ if (accessorFn) {
26
+ derived[colId] = (a, b, dir) => useSorting.defaultCompare(accessorFn(a, 0), accessorFn(b, 0), dir, nullsMode);
27
+ } else if (accessorKey) {
28
+ derived[colId] = (a, b, dir) => useSorting.defaultCompare(a[accessorKey], b[accessorKey], dir, nullsMode);
29
+ }
30
+ }
31
+ return { ...derived, ...sorting == null ? void 0 : sorting.columnComparators };
32
+ }, [sorting == null ? void 0 : sorting.columns, sorting == null ? void 0 : sorting.columnComparators, nullsMode]);
15
33
  const s = useSorting.useSorting({
16
34
  data,
17
- sortBy: (_a = sorting == null ? void 0 : sorting.sortBy) != null ? _a : null,
18
- sortDirection: (_b = sorting == null ? void 0 : sorting.direction) != null ? _b : null,
35
+ sortBy: (_b = sorting == null ? void 0 : sorting.sortBy) != null ? _b : null,
36
+ sortDirection: (_c = sorting == null ? void 0 : sorting.direction) != null ? _c : null,
19
37
  state: sorting == null ? void 0 : sorting.state,
20
38
  onStateChange: sorting == null ? void 0 : sorting.onStateChange,
21
- columnComparators: sorting == null ? void 0 : sorting.columnComparators,
22
- nulls: (_c = sorting == null ? void 0 : sorting.nulls) != null ? _c : "last",
39
+ columnComparators: mergedComparators,
40
+ nulls: nullsMode,
23
41
  allowUnsort: (_d = sorting == null ? void 0 : sorting.allowUnsort) != null ? _d : true
24
42
  });
25
43
  const p = usePagination.usePagination({
26
44
  data: s.sortedData,
27
45
  skip: (_e = pagination == null ? void 0 : pagination.skip) != null ? _e : 0,
28
- take: (_f = pagination == null ? void 0 : pagination.take) != null ? _f : 10,
46
+ take: (_f = pagination == null ? void 0 : pagination.take) != null ? _f : Math.max(s.sortedData.length, 1),
29
47
  state: pagination == null ? void 0 : pagination.state,
30
48
  onStateChange: pagination == null ? void 0 : pagination.onStateChange
31
49
  });
32
50
  react.useEffect(() => {
51
+ if (!hasPagination) return;
33
52
  if (!resetPageOnSortChange) return;
34
53
  p.resetPage();
35
- }, [resetPageOnSortChange, s.sortState.sortBy, s.sortState.sortDirection]);
36
- const rows = react.useMemo(() => p.paginatedData, [p.paginatedData]);
54
+ }, [hasPagination, resetPageOnSortChange, s.sortState.sortBy, s.sortState.sortDirection]);
55
+ const rows = react.useMemo(
56
+ () => hasPagination ? p.paginatedData : s.sortedData,
57
+ [hasPagination, p.paginatedData, s.sortedData]
58
+ );
37
59
  return {
38
60
  rows,
39
61
  totalCount: s.sortedData.length,
@@ -1,3 +1,4 @@
1
+ import type { ColumnDef } from '@tanstack/react-table';
1
2
  import type { PageChangeEvent } from '../components/pagination/Pagination';
2
3
  import { type PaginationState } from './usePagination';
3
4
  import { type SortDirection, type SortState, type ColumnComparators } from './useSorting';
@@ -10,13 +11,14 @@ export interface UseTableDataProps<T> {
10
11
  onStateChange?: (next: PaginationState) => void;
11
12
  };
12
13
  sorting?: {
13
- sortBy?: keyof T | null;
14
+ sortBy?: string | null;
14
15
  direction?: SortDirection;
15
16
  state?: SortState<T>;
16
17
  onStateChange?: (next: SortState<T>) => void;
17
18
  columnComparators?: ColumnComparators<T>;
18
19
  nulls?: 'first' | 'last';
19
20
  allowUnsort?: boolean;
21
+ columns?: ReadonlyArray<ColumnDef<T, any>>;
20
22
  };
21
23
  /**
22
24
  * Resets to page 1 whenever sorting changes (typical UX).
@@ -1,7 +1,7 @@
1
1
  'use client';
2
- import { useEffect, useMemo } from 'react';
2
+ import { useMemo, useEffect } from 'react';
3
3
  import { usePagination } from './usePagination';
4
- import { useSorting } from './useSorting';
4
+ import { useSorting, defaultCompare } from './useSorting';
5
5
 
6
6
  function useTableData({
7
7
  data = [],
@@ -10,28 +10,50 @@ function useTableData({
10
10
  resetPageOnSortChange = true
11
11
  }) {
12
12
  var _a, _b, _c, _d, _e, _f;
13
+ const hasPagination = pagination != null;
14
+ const nullsMode = (_a = sorting == null ? void 0 : sorting.nulls) != null ? _a : "last";
15
+ const mergedComparators = useMemo(() => {
16
+ var _a2, _b2;
17
+ const derived = {};
18
+ for (const col of (_a2 = sorting == null ? void 0 : sorting.columns) != null ? _a2 : []) {
19
+ const colId = (_b2 = col.id) != null ? _b2 : col.accessorKey;
20
+ if (!colId) continue;
21
+ const accessorFn = col.accessorFn;
22
+ const accessorKey = col.accessorKey;
23
+ if (accessorFn) {
24
+ derived[colId] = (a, b, dir) => defaultCompare(accessorFn(a, 0), accessorFn(b, 0), dir, nullsMode);
25
+ } else if (accessorKey) {
26
+ derived[colId] = (a, b, dir) => defaultCompare(a[accessorKey], b[accessorKey], dir, nullsMode);
27
+ }
28
+ }
29
+ return { ...derived, ...sorting == null ? void 0 : sorting.columnComparators };
30
+ }, [sorting == null ? void 0 : sorting.columns, sorting == null ? void 0 : sorting.columnComparators, nullsMode]);
13
31
  const s = useSorting({
14
32
  data,
15
- sortBy: (_a = sorting == null ? void 0 : sorting.sortBy) != null ? _a : null,
16
- sortDirection: (_b = sorting == null ? void 0 : sorting.direction) != null ? _b : null,
33
+ sortBy: (_b = sorting == null ? void 0 : sorting.sortBy) != null ? _b : null,
34
+ sortDirection: (_c = sorting == null ? void 0 : sorting.direction) != null ? _c : null,
17
35
  state: sorting == null ? void 0 : sorting.state,
18
36
  onStateChange: sorting == null ? void 0 : sorting.onStateChange,
19
- columnComparators: sorting == null ? void 0 : sorting.columnComparators,
20
- nulls: (_c = sorting == null ? void 0 : sorting.nulls) != null ? _c : "last",
37
+ columnComparators: mergedComparators,
38
+ nulls: nullsMode,
21
39
  allowUnsort: (_d = sorting == null ? void 0 : sorting.allowUnsort) != null ? _d : true
22
40
  });
23
41
  const p = usePagination({
24
42
  data: s.sortedData,
25
43
  skip: (_e = pagination == null ? void 0 : pagination.skip) != null ? _e : 0,
26
- take: (_f = pagination == null ? void 0 : pagination.take) != null ? _f : 10,
44
+ take: (_f = pagination == null ? void 0 : pagination.take) != null ? _f : Math.max(s.sortedData.length, 1),
27
45
  state: pagination == null ? void 0 : pagination.state,
28
46
  onStateChange: pagination == null ? void 0 : pagination.onStateChange
29
47
  });
30
48
  useEffect(() => {
49
+ if (!hasPagination) return;
31
50
  if (!resetPageOnSortChange) return;
32
51
  p.resetPage();
33
- }, [resetPageOnSortChange, s.sortState.sortBy, s.sortState.sortDirection]);
34
- const rows = useMemo(() => p.paginatedData, [p.paginatedData]);
52
+ }, [hasPagination, resetPageOnSortChange, s.sortState.sortBy, s.sortState.sortDirection]);
53
+ const rows = useMemo(
54
+ () => hasPagination ? p.paginatedData : s.sortedData,
55
+ [hasPagination, p.paginatedData, s.sortedData]
56
+ );
35
57
  return {
36
58
  rows,
37
59
  totalCount: s.sortedData.length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcdk/react-components",
3
- "version": "0.0.136",
3
+ "version": "0.0.137",
4
4
  "description": "Reusable React components for DBC projects",
5
5
  "license": "ISC",
6
6
  "author": "",