@dbcdk/react-components 0.0.29 → 0.0.31

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.
@@ -12,7 +12,7 @@
12
12
  .sm {
13
13
  --acc-trigger-py: var(--spacing-xs);
14
14
  --acc-trigger-px: var(--spacing-sm);
15
- --acc-content-py: var(--spacing-xs);
15
+ --acc-content-py: var(--spacing-sm);
16
16
  }
17
17
 
18
18
  .md {
@@ -10,6 +10,7 @@ export type CardMetaRowProps = {
10
10
  className?: string;
11
11
  nowrapValue?: boolean;
12
12
  labelWidth?: string;
13
+ boldValue?: boolean;
13
14
  };
14
15
  export declare function CardMeta({ columns, className, children, ...rest }: CardMetaProps): JSX.Element;
15
- export declare function CardMetaRow({ label, value, className, nowrapValue, labelWidth, }: CardMetaRowProps): JSX.Element;
16
+ export declare function CardMetaRow({ label, value, className, nowrapValue, labelWidth, boldValue, }: CardMetaRowProps): JSX.Element;
@@ -15,6 +15,12 @@ export function CardMeta({ columns = 2, className, children, ...rest }) {
15
15
  const colsClass = getColsClass(columns);
16
16
  return (_jsx("dl", { ...rest, className: [styles.grid, colsClass, className].filter(Boolean).join(' '), children: children }));
17
17
  }
18
- export function CardMetaRow({ label, value, className, nowrapValue, labelWidth, }) {
19
- return (_jsxs("div", { className: [styles.row, className].filter(Boolean).join(' '), style: labelWidth ? { ['--label-width']: labelWidth } : undefined, children: [_jsx("dt", { className: styles.label, children: label }), _jsx("dd", { className: [styles.value, nowrapValue ? styles.nowrap : ''].filter(Boolean).join(' '), children: value })] }));
18
+ export function CardMetaRow({ label, value, className, nowrapValue, labelWidth, boldValue = true, }) {
19
+ return (_jsxs("div", { className: [styles.row, className].filter(Boolean).join(' '), style: labelWidth ? { ['--label-width']: labelWidth } : undefined, children: [_jsx("dt", { className: styles.label, children: label }), _jsx("dd", { className: [
20
+ styles.value,
21
+ !boldValue ? styles.valueRegular : '',
22
+ nowrapValue ? styles.nowrap : '',
23
+ ]
24
+ .filter(Boolean)
25
+ .join(' '), children: value })] }));
20
26
  }
@@ -46,6 +46,10 @@
46
46
  word-break: break-word;
47
47
  }
48
48
 
49
+ .valueRegular {
50
+ font-weight: var(--font-weight-default);
51
+ }
52
+
49
53
  .nowrap {
50
54
  white-space: nowrap;
51
55
  }
@@ -341,9 +341,12 @@ export const DateTimePicker = forwardRef(function DateTimePicker({ mode = 'singl
341
341
  setText('');
342
342
  }, [mode, enableTime, onChangeDateOnly, onChangeIso, onChangeRange]);
343
343
  const fallbackPlaceholder = mode === 'single' ? 'Vælg dato' : 'Vælg interval';
344
- return (_jsx(Popover, { matchTriggerWidth: false, ref: popRef, onOpenChange: onOpenChange, trigger: toggle => {
344
+ const fullWidth = Boolean(inputProps === null || inputProps === void 0 ? void 0 : inputProps.fullWidth);
345
+ return (_jsx(Popover, { matchTriggerWidth: false, ref: popRef, onOpenChange: onOpenChange, fullWidth: fullWidth, trigger: toggle => {
345
346
  var _a, _b;
346
- return (_jsx("div", { onClick: toggle, className: styles.triggerWrap, children: _jsx(Input, { ...inputProps, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: "false", placeholder: (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.placeholder) !== null && _a !== void 0 ? _a : fallbackPlaceholder, value: dirty ? text : formatted, onInput: e => {
347
+ return (_jsx("div", { onClick: toggle, className: [styles.triggerWrap, fullWidth ? styles.triggerWrapFullWidth : '']
348
+ .filter(Boolean)
349
+ .join(' '), children: _jsx(Input, { ...inputProps, autoComplete: "off", autoCorrect: "off", autoCapitalize: "off", spellCheck: "false", placeholder: (_a = inputProps === null || inputProps === void 0 ? void 0 : inputProps.placeholder) !== null && _a !== void 0 ? _a : fallbackPlaceholder, value: dirty ? text : formatted, onInput: e => {
347
350
  setDirty(true);
348
351
  const raw = e.target.value;
349
352
  const masked = mode === 'single' ? maskSingle(raw, enableTime) : maskRange(raw, false);
@@ -2,6 +2,11 @@
2
2
  display: inline-block;
3
3
  }
4
4
 
5
+ .triggerWrapFullWidth {
6
+ display: block;
7
+ width: 100%;
8
+ }
9
+
5
10
  .panel {
6
11
  display: grid;
7
12
  grid-template-columns: 1fr;
@@ -2,6 +2,7 @@ import { type ReactNode, type JSX } from 'react';
2
2
  export interface MetaItem {
3
3
  label?: ReactNode;
4
4
  value: ReactNode;
5
+ muted?: boolean;
5
6
  }
6
7
  interface MetaBarProps {
7
8
  items: MetaItem[];
@@ -5,5 +5,5 @@ export function MetaBar({ items, separator = '•' }) {
5
5
  const visibleItems = items.filter(item => item.value !== null && item.value !== undefined && item.value !== '');
6
6
  if (visibleItems.length === 0)
7
7
  return null;
8
- return (_jsx("div", { className: styles.meta, children: visibleItems.map((item, index) => (_jsxs(Fragment, { children: [_jsxs("span", { children: [item.label && _jsxs("span", { children: [item.label, ": "] }), _jsx("span", { children: item.value })] }), index < visibleItems.length - 1 && (_jsx("span", { "aria-hidden": "true", className: styles.dot, children: separator }))] }, index))) }));
8
+ return (_jsx("div", { className: styles.meta, children: visibleItems.map((item, index) => (_jsxs(Fragment, { children: [_jsxs("span", { className: item.muted === false ? styles.itemDefault : styles.itemMuted, children: [item.label && _jsxs("span", { children: [item.label, ": "] }), _jsx("span", { children: item.value })] }), index < visibleItems.length - 1 && (_jsx("span", { "aria-hidden": "true", className: styles.dot, children: separator }))] }, index))) }));
9
9
  }
@@ -1,5 +1,4 @@
1
1
  .meta {
2
- color: var(--color-fg-subtle);
3
2
  display: flex;
4
3
  flex-wrap: wrap;
5
4
  align-items: center;
@@ -7,6 +6,14 @@
7
6
  font-size: var(--font-size-xs);
8
7
  }
9
8
 
9
+ .itemMuted {
10
+ color: var(--color-fg-subtle);
11
+ }
12
+
13
+ .itemDefault {
14
+ color: var(--color-fg-default);
15
+ }
16
+
10
17
  .dot {
11
18
  opacity: 0.6;
12
19
  }
@@ -1,3 +1,3 @@
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, gridTemplateColumns, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement, showFirstLast, getRowSeverity, 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, gridTemplateColumns, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement, showFirstLast, pageSizeOptions, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, onSelectAllRows, onSortChange, onPageChange, ...rest }: TableProps<T>): JSX.Element;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useCallback, useMemo } from 'react';
3
+ import { useCallback, useId, useMemo } from 'react';
4
4
  import { Pagination } from '../../components/pagination/Pagination';
5
5
  import { TableEmptyState } from './components/empty-state/EmptyState';
6
6
  import { TableBody } from './components/TableBody';
@@ -9,8 +9,9 @@ import { TableLoadingBody } from './components/TableLoadingBody';
9
9
  import { cx } from './table.classes';
10
10
  import styles from './Table.module.css';
11
11
  import { buildDefaultGridTemplate, getVisibleColumns } from './table.utils';
12
- export function Table({ data, dataKey, columns, selectedRows, selectionMode = 'single', allRowsSelected, sortById, sortDirection, loading, emptyConfig, variant = 'primary', size = 'md', viewMode, striped, fillViewport = false, gridTemplateColumns, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement = 'bottom', showFirstLast = false, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, onSelectAllRows, onSortChange, onPageChange, ...rest }) {
12
+ export function Table({ data, dataKey, columns, selectedRows, selectionMode = 'single', allRowsSelected, sortById, sortDirection, loading, emptyConfig, variant = 'primary', size = 'md', viewMode, striped, fillViewport = false, gridTemplateColumns, toolbar, headerExtras, take, skip, totalItemsCount, paginationPlacement = 'bottom', showFirstLast = false, pageSizeOptions, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, onSelectAllRows, onSortChange, onPageChange, ...rest }) {
13
13
  const visibleColumns = useMemo(() => getVisibleColumns(columns), [columns]);
14
+ const selectionInputName = useId();
14
15
  const hasSelection = Boolean(selectedRows && onRowSelect);
15
16
  const template = useMemo(() => {
16
17
  return (gridTemplateColumns !== null && gridTemplateColumns !== void 0 ? gridTemplateColumns : buildDefaultGridTemplate({
@@ -22,8 +23,8 @@ export function Table({ data, dataKey, columns, selectedRows, selectionMode = 's
22
23
  const handlePageChange = useCallback((e) => {
23
24
  onPageChange === null || onPageChange === void 0 ? void 0 : onPageChange(e);
24
25
  }, [onPageChange]);
25
- const bodyContent = loading && !data.length ? (_jsx(TableLoadingBody, { rows: take !== null && take !== void 0 ? take : 5, columns: visibleColumns, hasSelection: hasSelection, gridStyle: gridStyle })) : (_jsx(TableBody, { data: data, dataKey: dataKey, columns: visibleColumns, gridStyle: gridStyle, striped: striped, selectedRows: selectedRows, hasSelection: hasSelection, viewMode: viewMode, getRowSeverity: getRowSeverity, onRowClick: onRowClick, onRowMouseEnter: onRowMouseEnter, onRowSelect: onRowSelect }));
26
- const paginationEl = onPageChange && data.length > 0 ? (_jsx("div", { className: cx(styles.paginationSlot, paginationPlacement === 'top' && styles.paginationSlotTop), children: _jsx(Pagination, { itemsCount: totalItemsCount, take: take, skip: skip, onPageChange: handlePageChange, showFirstLast: showFirstLast }) })) : null;
26
+ const bodyContent = loading && !data.length ? (_jsx(TableLoadingBody, { rows: take !== null && take !== void 0 ? take : 5, columns: visibleColumns, hasSelection: hasSelection, gridStyle: gridStyle })) : (_jsx(TableBody, { data: data, dataKey: dataKey, columns: visibleColumns, gridStyle: gridStyle, striped: striped, selectedRows: selectedRows, hasSelection: hasSelection, selectionMode: selectionMode, selectionInputName: selectionInputName, viewMode: viewMode, getRowSeverity: getRowSeverity, onRowClick: onRowClick, onRowMouseEnter: onRowMouseEnter, onRowSelect: onRowSelect }));
27
+ const paginationEl = onPageChange && data.length > 0 ? (_jsx("div", { className: cx(styles.paginationSlot, paginationPlacement === 'top' && styles.paginationSlotTop), children: _jsx(Pagination, { itemsCount: totalItemsCount, take: take, skip: skip, onPageChange: handlePageChange, showFirstLast: showFirstLast, pageSizeOptions: pageSizeOptions }) })) : null;
27
28
  const tableClassName = cx(styles.tableRoot, styles[variant], styles[size], getRowSeverity && styles.severityTable);
28
29
  const tableShell = (_jsx("div", { ...rest, className: tableClassName, role: "table", "aria-rowcount": data.length, children: _jsxs("div", { className: styles.tableContent, children: [_jsx("div", { className: styles.header, role: "rowgroup", children: _jsx(TableHeader, { columns: visibleColumns, gridStyle: gridStyle, hasSelection: hasSelection, selectionMode: selectionMode, allRowsSelected: allRowsSelected, onSelectAllRows: onSelectAllRows, sortById: sortById, sortDirection: sortDirection, onSortChange: onSortChange, headerExtras: headerExtras }) }), _jsx("div", { className: styles.bodyScroll, children: !data.length && !loading ? (_jsx("div", { className: styles.emptyStateSlot, children: _jsx(TableEmptyState, { config: emptyConfig }) })) : (bodyContent) })] }) }));
29
30
  if (fillViewport) {
@@ -190,11 +190,11 @@
190
190
  .cell.selectionCell {
191
191
  overflow: visible !important;
192
192
  display: flex;
193
- align-items: center;
194
- justify-content: center;
193
+ align-items: flex-start;
194
+ justify-content: flex-start;
195
195
  min-width: 0;
196
- padding-inline: 0;
197
- padding-block: 0;
196
+ padding-inline: var(--spacing-sm);
197
+ padding-block: 6px;
198
198
  cursor: pointer;
199
199
  }
200
200
 
@@ -210,16 +210,37 @@
210
210
 
211
211
  .selectionHitArea {
212
212
  display: inline-flex;
213
- align-items: center;
214
- justify-content: center;
215
- inline-size: 100%;
216
- block-size: 100%;
217
- min-block-size: var(--component-size-md);
218
- padding: 4px;
213
+ align-items: flex-start;
214
+ justify-content: flex-start;
215
+ inline-size: fit-content;
216
+ block-size: auto;
217
+ min-block-size: 0;
218
+ padding: 0;
219
219
  }
220
220
 
221
221
  .sm .selectionHitArea {
222
- min-block-size: var(--component-size-sm);
222
+ min-block-size: 0;
223
+ }
224
+
225
+ .selectionControlWrap {
226
+ display: inline-flex;
227
+ align-items: flex-start;
228
+ }
229
+
230
+ .selectionControlWrap span {
231
+ gap: 0;
232
+ }
233
+
234
+ .selectionControlWrap input[type='radio'] + span {
235
+ width: 18px;
236
+ height: 18px;
237
+ border-width: 1px;
238
+ border-color: color-mix(in srgb, var(--color-fg-default) 28%, transparent);
239
+ }
240
+
241
+ .selectionControlWrap input[type='radio'] + span > span {
242
+ width: 8px;
243
+ height: 8px;
223
244
  }
224
245
 
225
246
  .clickableRow {
@@ -48,6 +48,7 @@ export type TableProps<T extends Record<string, any>> = Omit<HTMLAttributes<HTML
48
48
  totalItemsCount?: number;
49
49
  paginationPlacement?: 'top' | 'bottom';
50
50
  showFirstLast?: boolean;
51
+ pageSizeOptions?: number[];
51
52
  getRowSeverity?: (row: T) => Severity | undefined;
52
53
  onRowClick?: (row: T) => void;
53
54
  onRowMouseEnter?: (row: T) => void;
@@ -19,6 +19,8 @@ export function TanstackTable(props) {
19
19
  const columnVisibility = React.useMemo(() => buildColumnVisibilityFromVisibleIds(columns, visibleColumnIds), [columns, visibleColumnIds]);
20
20
  const [columnFilters, setColumnFilters] = React.useState([]);
21
21
  const [columnSizing, setColumnSizing] = React.useState({});
22
+ const containerRef = React.useRef(null);
23
+ const [availableWidth, setAvailableWidth] = React.useState(undefined);
22
24
  const table = useReactTable({
23
25
  data,
24
26
  columns: columns,
@@ -72,6 +74,23 @@ export function TanstackTable(props) {
72
74
  return _jsx(ColumnResizer, { id: header.column.id, handler: handler });
73
75
  }, [table]);
74
76
  const hasSelection = Boolean(selectedRows && onRowSelect && dataKey);
77
+ React.useEffect(() => {
78
+ const el = containerRef.current;
79
+ if (!el)
80
+ return;
81
+ const updateWidth = () => {
82
+ const next = el.clientWidth;
83
+ setAvailableWidth(next > 0 ? next : undefined);
84
+ };
85
+ updateWidth();
86
+ if (typeof ResizeObserver === 'undefined') {
87
+ window.addEventListener('resize', updateWidth);
88
+ return () => window.removeEventListener('resize', updateWidth);
89
+ }
90
+ const observer = new ResizeObserver(() => updateWidth());
91
+ observer.observe(el);
92
+ return () => observer.disconnect();
93
+ }, []);
75
94
  const gridTemplateColumns = React.useMemo(() => {
76
95
  return buildDistributedGridTemplateColumns({
77
96
  table,
@@ -79,7 +98,8 @@ export function TanstackTable(props) {
79
98
  hasSelection,
80
99
  defaultMinPx: 80,
81
100
  columnSizing,
101
+ availableWidth,
82
102
  });
83
- }, [table, allowedIds, hasSelection, columnSizing]);
84
- return (_jsx(Table, { ...tableProps, onSortChange: handleSortChange, dataKey: dataKey, data: visibleData, columns: columnItems, sortById: sortById, sortDirection: sortDirection, gridTemplateColumns: gridTemplateColumns, headerExtras: headerExtras, selectedRows: selectedRows, onRowSelect: onRowSelect }));
103
+ }, [table, allowedIds, hasSelection, columnSizing, availableWidth]);
104
+ return (_jsx("div", { ref: containerRef, style: { width: '100%', minWidth: 0 }, children: _jsx(Table, { ...tableProps, onSortChange: handleSortChange, dataKey: dataKey, data: visibleData, columns: columnItems, sortById: sortById, sortDirection: sortDirection, gridTemplateColumns: gridTemplateColumns, headerExtras: headerExtras, selectedRows: selectedRows, onRowSelect: onRowSelect }) }));
85
105
  }
@@ -9,11 +9,13 @@ type Props<T extends Record<string, any>> = {
9
9
  striped?: boolean;
10
10
  selectedRows?: Set<number | string>;
11
11
  hasSelection: boolean;
12
+ selectionMode: 'single' | 'multiple';
13
+ selectionInputName: string;
12
14
  viewMode?: ViewMode;
13
15
  getRowSeverity?: (row: T) => any;
14
16
  onRowClick?: (row: T) => void;
15
17
  onRowMouseEnter?: (row: T) => void;
16
18
  onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
17
19
  };
18
- export declare function TableBody<T extends Record<string, any>>({ data, dataKey, columns, gridStyle, striped, selectedRows, hasSelection, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): ReactNode;
20
+ export declare function TableBody<T extends Record<string, any>>({ data, dataKey, columns, gridStyle, striped, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): ReactNode;
19
21
  export {};
@@ -2,9 +2,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cx } from '../table.classes';
3
3
  import styles from '../Table.module.css';
4
4
  import { TableRow } from './TableRow';
5
- export function TableBody({ data, dataKey, columns, gridStyle, striped, selectedRows, hasSelection, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }) {
5
+ export function TableBody({ data, dataKey, columns, gridStyle, striped, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }) {
6
6
  return (_jsx("div", { className: cx(styles.body, striped && styles.striped), role: "rowgroup", children: data.map(row => {
7
7
  const rowId = row[dataKey];
8
- return (_jsx(TableRow, { row: row, rowId: rowId, columns: columns, gridStyle: gridStyle, selectedRows: selectedRows, hasSelection: hasSelection, viewMode: viewMode, getRowSeverity: getRowSeverity, onRowClick: onRowClick, onRowMouseEnter: onRowMouseEnter, onRowSelect: onRowSelect }, `gridRow-${rowId}`));
8
+ return (_jsx(TableRow, { row: row, rowId: rowId, columns: columns, gridStyle: gridStyle, selectedRows: selectedRows, hasSelection: hasSelection, selectionMode: selectionMode, selectionInputName: selectionInputName, viewMode: viewMode, getRowSeverity: getRowSeverity, onRowClick: onRowClick, onRowMouseEnter: onRowMouseEnter, onRowSelect: onRowSelect }, `gridRow-${rowId}`));
9
9
  }) }));
10
10
  }
@@ -9,11 +9,13 @@ type Props<T extends Record<string, any>> = {
9
9
  gridStyle: CSSProperties;
10
10
  selectedRows?: Set<number | string>;
11
11
  hasSelection: boolean;
12
+ selectionMode: 'single' | 'multiple';
13
+ selectionInputName: string;
12
14
  viewMode?: ViewMode;
13
15
  getRowSeverity?: (row: T) => any;
14
16
  onRowClick?: (row: T) => void;
15
17
  onRowMouseEnter?: (row: T) => void;
16
18
  onRowSelect?: (rowId: number | string, isSelected: boolean) => void;
17
19
  };
18
- export declare function TableRow<T extends Record<string, any>>({ row, rowId, columns, gridStyle, selectedRows, hasSelection, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): React.ReactNode;
20
+ export declare function TableRow<T extends Record<string, any>>({ row, rowId, columns, gridStyle, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }: Props<T>): React.ReactNode;
19
21
  export {};
@@ -1,11 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Checkbox } from '../../../components/forms/checkbox/Checkbox';
3
+ import { RadioButton } from '../../../components/forms/radio-buttons/RadioButton';
3
4
  import { SeverityBgColor } from '../../../constants/severity';
4
5
  import { useTableRowInteractions } from '../hooks/useTableRowInteractions';
5
6
  import { cx } from '../table.classes';
6
7
  import styles from '../Table.module.css';
7
8
  import { getCellDisplayValue, shouldAllowWrap } from '../table.utils';
8
- export function TableRow({ row, rowId, columns, gridStyle, selectedRows, hasSelection, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }) {
9
+ export function TableRow({ row, rowId, columns, gridStyle, selectedRows, hasSelection, selectionMode, selectionInputName, viewMode, getRowSeverity, onRowClick, onRowMouseEnter, onRowSelect, }) {
9
10
  var _a;
10
11
  const isSelected = (_a = selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.has(rowId)) !== null && _a !== void 0 ? _a : false;
11
12
  const rowSeverity = getRowSeverity === null || getRowSeverity === void 0 ? void 0 : getRowSeverity(row);
@@ -23,13 +24,20 @@ export function TableRow({ row, rowId, columns, gridStyle, selectedRows, hasSele
23
24
  ['--row-severity-color']: rowSeverity
24
25
  ? SeverityBgColor[rowSeverity]
25
26
  : undefined,
26
- }, role: "row", tabIndex: onRowClick ? 0 : -1, onKeyDown: handleRowKeyDown, onMouseEnter: () => onRowMouseEnter === null || onRowMouseEnter === void 0 ? void 0 : onRowMouseEnter(row), onClick: handleRowClick, children: [hasSelection ? (_jsx("div", { className: cx(styles.cell, styles.selectionCell), role: "cell", onClick: e => {
27
- e.stopPropagation();
28
- onRowSelect === null || onRowSelect === void 0 ? void 0 : onRowSelect(rowId, !isSelected);
29
- }, children: _jsx("div", { className: styles.selectionHitArea, children: _jsx(Checkbox, { variant: "primary", checked: isSelected, size: "sm", onChange: (checked, e) => {
27
+ }, role: "row", tabIndex: onRowClick ? 0 : -1, onKeyDown: handleRowKeyDown, onMouseEnter: () => onRowMouseEnter === null || onRowMouseEnter === void 0 ? void 0 : onRowMouseEnter(row), onClick: handleRowClick, children: [hasSelection ? (_jsx("div", { className: cx(styles.cell, styles.selectionCell), role: "cell", "data-selection-control": "true", children: _jsx("div", { className: styles.selectionHitArea, "data-selection-control": "true", onClick: e => {
28
+ if (e.target !== e.currentTarget)
29
+ return;
30
+ e.stopPropagation();
31
+ onRowSelect === null || onRowSelect === void 0 ? void 0 : onRowSelect(rowId, selectionMode === 'single' ? true : !isSelected);
32
+ }, children: _jsx("div", { className: styles.selectionControlWrap, "data-selection-control": "true", onClick: e => {
30
33
  e.stopPropagation();
31
- onRowSelect === null || onRowSelect === void 0 ? void 0 : onRowSelect(rowId, checked);
32
- } }) }) })) : null, columns.map(column => {
34
+ }, children: selectionMode === 'single' ? (_jsx(RadioButton, { noContainer: true, name: selectionInputName, value: String(rowId), checked: isSelected, size: "sm", variant: "primary", onChange: (_value, e) => {
35
+ e.stopPropagation();
36
+ onRowSelect === null || onRowSelect === void 0 ? void 0 : onRowSelect(rowId, true);
37
+ } })) : (_jsx(Checkbox, { variant: "primary", checked: isSelected, size: "sm", onChange: (checked, e) => {
38
+ e.stopPropagation();
39
+ onRowSelect === null || onRowSelect === void 0 ? void 0 : onRowSelect(rowId, checked);
40
+ } })) }) }) })) : null, columns.map(column => {
33
41
  var _a;
34
42
  const allowWrap = shouldAllowWrap(column.allowWrap, isSelected, viewMode);
35
43
  const cellValue = getCellDisplayValue(row, column);
@@ -2,6 +2,11 @@ import { useCallback } from 'react';
2
2
  import { isModifierClick, shouldToggleOnKey } from '../table.utils';
3
3
  export function useTableRowInteractions({ row, rowId, isSelected, canSelect, onRowClick, onRowSelect, }) {
4
4
  const handleRowClick = useCallback((e) => {
5
+ var _a;
6
+ const target = e.target;
7
+ if ((_a = target === null || target === void 0 ? void 0 : target.closest) === null || _a === void 0 ? void 0 : _a.call(target, '[data-selection-control="true"]')) {
8
+ return;
9
+ }
5
10
  if (isModifierClick(e) && canSelect) {
6
11
  e.preventDefault();
7
12
  e.stopPropagation();
@@ -16,5 +16,6 @@ export declare function buildDistributedGridTemplateColumns(args: {
16
16
  hasSelection: boolean;
17
17
  defaultMinPx: number;
18
18
  columnSizing: ColumnSizingState;
19
+ availableWidth?: number;
19
20
  }): string;
20
21
  export {};
@@ -92,34 +92,87 @@ function clamp(value, min, max) {
92
92
  return Math.min(lowerBounded, max);
93
93
  }
94
94
  export function buildDistributedGridTemplateColumns(args) {
95
- var _a, _b, _c, _d;
96
- const { table, allowedIds, hasSelection, defaultMinPx, columnSizing } = args;
95
+ var _a, _b, _c, _d, _e, _f, _g;
96
+ const { table, allowedIds, hasSelection, defaultMinPx, columnSizing, availableWidth } = args;
97
97
  const parts = [];
98
98
  const leaf = table.getVisibleLeafColumns().filter((c) => allowedIds.has(c.id));
99
+ const fixedSelectionWidth = hasSelection ? SELECTION_COLUMN_PX : 0;
100
+ const flexTracks = [];
101
+ let fixedWidth = fixedSelectionWidth;
99
102
  if (hasSelection)
100
103
  parts.push(`${SELECTION_COLUMN_PX}px`);
101
104
  for (const c of leaf) {
102
105
  const def = c.columnDef;
103
106
  const meta = ((_b = ((_a = def.meta) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : {});
104
107
  const min = Math.max(1, Number((_c = def.minSize) !== null && _c !== void 0 ? _c : defaultMinPx));
108
+ const preferred = Math.max(min, Number((_f = (_d = def.size) !== null && _d !== void 0 ? _d : (_e = c.getSize) === null || _e === void 0 ? void 0 : _e.call(c)) !== null && _f !== void 0 ? _f : defaultMinPx));
105
109
  const hasMax = def.maxSize != null;
106
110
  const max = hasMax ? Math.max(min, Number(def.maxSize)) : undefined;
107
- const weight = Math.max(1, Number((_d = meta.weight) !== null && _d !== void 0 ? _d : 1));
111
+ const weight = Math.max(1, Number((_g = meta.weight) !== null && _g !== void 0 ? _g : 1));
108
112
  const resizedPxRaw = columnSizing[c.id];
109
113
  const resizedPx = resizedPxRaw != null ? Math.round(clamp(Number(resizedPxRaw), min, max)) : undefined;
110
114
  if (resizedPx != null) {
111
115
  parts.push(`${resizedPx}px`);
116
+ fixedWidth += resizedPx;
112
117
  continue;
113
118
  }
114
119
  if (hasMax && max === min) {
115
120
  parts.push(`${Math.round(min)}px`);
121
+ fixedWidth += Math.round(min);
116
122
  continue;
117
123
  }
118
- if (hasMax && max != null) {
119
- parts.push(`minmax(${Math.round(min)}px, ${Math.round(max)}px)`);
120
- continue;
124
+ flexTracks.push({
125
+ width: hasMax && max != null ? clamp(preferred, min, max) : preferred,
126
+ weight,
127
+ max,
128
+ });
129
+ parts.push('__FLEX__');
130
+ }
131
+ if (availableWidth != null && Number.isFinite(availableWidth) && availableWidth > 0) {
132
+ const totalBaseWidth = fixedWidth + flexTracks.reduce((sum, track) => sum + track.width, 0);
133
+ let remaining = Math.max(0, availableWidth - totalBaseWidth);
134
+ let active = flexTracks.filter(track => track.max == null || track.width < track.max);
135
+ while (remaining > 0.5 && active.length > 0) {
136
+ const totalWeight = active.reduce((sum, track) => sum + track.weight, 0);
137
+ if (totalWeight <= 0)
138
+ break;
139
+ let consumed = 0;
140
+ const nextActive = [];
141
+ for (const track of active) {
142
+ const share = (remaining * track.weight) / totalWeight;
143
+ const maxGrow = track.max == null ? share : Math.max(0, track.max - track.width);
144
+ const growth = Math.min(share, maxGrow);
145
+ track.width += growth;
146
+ consumed += growth;
147
+ if (track.max == null || track.width < track.max - 0.5) {
148
+ nextActive.push(track);
149
+ }
150
+ }
151
+ if (consumed <= 0.5)
152
+ break;
153
+ remaining -= consumed;
154
+ active = nextActive;
121
155
  }
122
- parts.push(`minmax(${Math.round(min)}px, ${weight}fr)`);
156
+ let flexIndex = 0;
157
+ return parts
158
+ .map(part => {
159
+ if (part !== '__FLEX__')
160
+ return part;
161
+ const track = flexTracks[flexIndex++];
162
+ return `${Math.round(track.width)}px`;
163
+ })
164
+ .join(' ');
123
165
  }
124
- return parts.join(' ');
166
+ let flexIndex = 0;
167
+ return parts
168
+ .map(part => {
169
+ if (part !== '__FLEX__')
170
+ return part;
171
+ const track = flexTracks[flexIndex++];
172
+ const roundedWidth = Math.round(track.width);
173
+ if (track.max != null)
174
+ return `minmax(${roundedWidth}px, ${Math.round(track.max)}px)`;
175
+ return `minmax(${roundedWidth}px, ${track.weight}fr)`;
176
+ })
177
+ .join(' ');
125
178
  }
@@ -106,6 +106,10 @@ body.dbc-app {
106
106
  word-break: break-word;
107
107
  }
108
108
 
109
+ .dbc-table.dbc-table--plain-values td {
110
+ font-weight: var(--font-weight-default);
111
+ }
112
+
109
113
  /* Optional: baseline alignment closer to metaRow */
110
114
  .dbc-table th,
111
115
  .dbc-table td {
@@ -106,6 +106,10 @@ body.dbc-app {
106
106
  word-break: break-word;
107
107
  }
108
108
 
109
+ .dbc-table.dbc-table--plain-values td {
110
+ font-weight: var(--font-weight-default);
111
+ }
112
+
109
113
  /* Optional: baseline alignment closer to metaRow */
110
114
  .dbc-table th,
111
115
  .dbc-table td {
@@ -153,7 +153,7 @@ html[data-theme='light'] {
153
153
  --table-header-bg: #f5f6f8;
154
154
  --table-row-bg: #ffffff;
155
155
  --table-row-bg-alt: #f7f9fc;
156
- --table-row-bg-hover: #f6f8fb;
156
+ --table-row-bg-hover: #eef2f7;
157
157
  --table-row-bg-selected: var(--dbc-blue-100);
158
158
  --table-row-bg-selected-hover: var(--dbc-blue-150);
159
159
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcdk/react-components",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "description": "Reusable React components for DBC projects",
5
5
  "license": "ISC",
6
6
  "author": "",