@dbcdk/react-components 0.0.42 → 0.0.44
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/copy-button/CopyButton.js +5 -1
- package/dist/components/filter-field/FilterField.d.ts +2 -1
- package/dist/components/filter-field/FilterField.js +49 -22
- package/dist/components/table/Table.js +1 -1
- package/dist/components/table/components/TableLoadingBody.js +18 -2
- package/package.json +1 -1
|
@@ -47,5 +47,9 @@ export function CopyButton(props) {
|
|
|
47
47
|
handleCopy();
|
|
48
48
|
}, className: `${styles.link} ${copied ? styles.copied : ''}`, children: [children, copied ? _jsx(Check, {}) : _jsx(Copy, {})] }) }));
|
|
49
49
|
}
|
|
50
|
-
return (_jsxs(Button, { ...rest, "aria-label": children ? '' : ((_b = rest['aria-label']) !== null && _b !== void 0 ? _b : 'Kopier til udklipsholder'), onClick:
|
|
50
|
+
return (_jsxs(Button, { ...rest, "aria-label": children ? '' : ((_b = rest['aria-label']) !== null && _b !== void 0 ? _b : 'Kopier til udklipsholder'), onClick: e => {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
e.stopPropagation();
|
|
53
|
+
handleCopy();
|
|
54
|
+
}, variant: variant, size: size, children: [_jsx("span", { className: `${styles.container} ${copied ? styles.copied : ''}`, children: copied ? _jsx(Check, {}) : _jsx(Copy, {}) }), children] }));
|
|
51
55
|
}
|
|
@@ -25,9 +25,10 @@ export interface FilterFieldProps extends Omit<React.InputHTMLAttributes<HTMLInp
|
|
|
25
25
|
placeholder?: string;
|
|
26
26
|
disabled?: boolean;
|
|
27
27
|
width?: string;
|
|
28
|
+
debounceTime?: number;
|
|
28
29
|
}
|
|
29
30
|
export declare const NUMBER_OPERATORS: Operator[];
|
|
30
|
-
export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, variant, label, placeholder, disabled, 'data-cy': dataCy, width, ...inputProps }: FilterFieldProps & {
|
|
31
|
+
export declare function FilterField({ field, control, operator, value, onChange, operators, options, single, size, variant, label, placeholder, disabled, 'data-cy': dataCy, width, debounceTime, ...inputProps }: FilterFieldProps & {
|
|
31
32
|
'data-cy'?: string;
|
|
32
33
|
}): React.ReactElement;
|
|
33
34
|
export {};
|
|
@@ -44,6 +44,8 @@ export const NUMBER_OPERATORS = [
|
|
|
44
44
|
'isEmpty',
|
|
45
45
|
'isNotEmpty',
|
|
46
46
|
];
|
|
47
|
+
const VALUELESS_OPERATORS = ['isEmpty', 'isNotEmpty'];
|
|
48
|
+
const INPUT_DEBOUNCE_MS = 500;
|
|
47
49
|
function OperatorDropdown({ value, onChange, operators, size = 'sm', disabled, }) {
|
|
48
50
|
const popRef = useRef(null);
|
|
49
51
|
const [activeIndex, setActiveIndex] = useState(() => Math.max(0, operators.indexOf(value)));
|
|
@@ -68,8 +70,7 @@ function isFilterActive(value) {
|
|
|
68
70
|
return value.trim().length > 0;
|
|
69
71
|
return value != null;
|
|
70
72
|
}
|
|
71
|
-
|
|
72
|
-
export function FilterField({ field, control, operator, value, onChange, operators, options = [], single = true, size = 'md', variant = 'surface', label, placeholder = 'Type value…', disabled, 'data-cy': dataCy, width, ...inputProps }) {
|
|
73
|
+
export function FilterField({ field, control, operator, value, onChange, operators, options = [], single = true, size = 'md', variant = 'surface', label, placeholder = 'Type value…', disabled, 'data-cy': dataCy, width, debounceTime = INPUT_DEBOUNCE_MS, ...inputProps }) {
|
|
73
74
|
var _a, _b;
|
|
74
75
|
const ops = useMemo(() => operators !== null && operators !== void 0 ? operators : DEFAULT_TEXT_OPERATORS, [operators]);
|
|
75
76
|
const [selectedOperator, setSelectedOperator] = useState(operator);
|
|
@@ -81,66 +82,92 @@ export function FilterField({ field, control, operator, value, onChange, operato
|
|
|
81
82
|
}, [operator, ops]);
|
|
82
83
|
const [localValue, setLocalValue] = useState((_a = value) !== null && _a !== void 0 ? _a : '');
|
|
83
84
|
const debounceRef = useRef(null);
|
|
84
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Holds the exact text value we most recently sent upward.
|
|
87
|
+
* While waiting for that value to round-trip back through URL/provider state,
|
|
88
|
+
* we ignore intermediate external churn so the input does not visually flicker.
|
|
89
|
+
*/
|
|
90
|
+
const pendingValueRef = useRef(null);
|
|
85
91
|
const emit = (next) => {
|
|
86
92
|
var _a, _b;
|
|
87
93
|
const nextOperator = (_a = next.operator) !== null && _a !== void 0 ? _a : selectedOperator;
|
|
88
94
|
const nextValue = (_b = next.value) !== null && _b !== void 0 ? _b : value;
|
|
89
|
-
if (next.operator)
|
|
95
|
+
if (next.operator) {
|
|
90
96
|
setSelectedOperator(nextOperator);
|
|
97
|
+
}
|
|
91
98
|
onChange({
|
|
92
99
|
field,
|
|
93
100
|
operator: nextOperator,
|
|
94
101
|
value: nextValue,
|
|
95
102
|
});
|
|
96
103
|
};
|
|
104
|
+
const clearDebounce = () => {
|
|
105
|
+
if (debounceRef.current) {
|
|
106
|
+
clearTimeout(debounceRef.current);
|
|
107
|
+
debounceRef.current = null;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const scheduleEmitValue = (nextVal) => {
|
|
111
|
+
clearDebounce();
|
|
112
|
+
pendingValueRef.current = nextVal;
|
|
113
|
+
debounceRef.current = setTimeout(() => {
|
|
114
|
+
emit({ value: nextVal });
|
|
115
|
+
}, debounceTime);
|
|
116
|
+
};
|
|
117
|
+
const flushPendingValue = () => {
|
|
118
|
+
if (control !== 'input')
|
|
119
|
+
return;
|
|
120
|
+
clearDebounce();
|
|
121
|
+
pendingValueRef.current = localValue;
|
|
122
|
+
emit({ value: localValue });
|
|
123
|
+
};
|
|
97
124
|
const handleOperatorChange = (op) => {
|
|
98
125
|
setSelectedOperator(op);
|
|
99
126
|
if (!active && !VALUELESS_OPERATORS.includes(op))
|
|
100
127
|
return;
|
|
101
128
|
if (VALUELESS_OPERATORS.includes(op)) {
|
|
129
|
+
clearDebounce();
|
|
130
|
+
pendingValueRef.current = null;
|
|
102
131
|
emit({ operator: op, value: null });
|
|
103
132
|
return;
|
|
104
133
|
}
|
|
134
|
+
clearDebounce();
|
|
135
|
+
pendingValueRef.current =
|
|
136
|
+
control === 'input' ? localValue : typeof value === 'string' ? value : null;
|
|
105
137
|
emit({ operator: op });
|
|
106
138
|
};
|
|
107
|
-
const scheduleEmitValue = (nextVal) => {
|
|
108
|
-
if (debounceRef.current)
|
|
109
|
-
clearTimeout(debounceRef.current);
|
|
110
|
-
debounceRef.current = setTimeout(() => {
|
|
111
|
-
isTypingRef.current = false;
|
|
112
|
-
emit({ value: nextVal });
|
|
113
|
-
}, 250);
|
|
114
|
-
};
|
|
115
139
|
useEffect(() => {
|
|
116
140
|
var _a;
|
|
117
141
|
if (control !== 'input')
|
|
118
142
|
return;
|
|
119
143
|
const incoming = (_a = value) !== null && _a !== void 0 ? _a : '';
|
|
120
|
-
|
|
121
|
-
|
|
144
|
+
const pending = pendingValueRef.current;
|
|
145
|
+
if (pending !== null) {
|
|
146
|
+
if (incoming === pending) {
|
|
147
|
+
pendingValueRef.current = null;
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
122
150
|
}
|
|
123
|
-
if (incoming
|
|
124
|
-
|
|
151
|
+
if (incoming !== localValue) {
|
|
152
|
+
setLocalValue(incoming);
|
|
125
153
|
}
|
|
126
154
|
}, [value, control, localValue]);
|
|
127
155
|
useEffect(() => {
|
|
128
156
|
return () => {
|
|
129
|
-
|
|
130
|
-
clearTimeout(debounceRef.current);
|
|
157
|
+
clearDebounce();
|
|
131
158
|
};
|
|
132
159
|
}, []);
|
|
133
160
|
return (_jsxs("div", { ...(dataCy ? { 'data-cy': dataCy } : {}), className: [styles.filterField, styles[size], styles[variant], active ? styles.active : '']
|
|
134
161
|
.filter(Boolean)
|
|
135
162
|
.join(' '), children: [label ? _jsx("span", { className: `${styles.label} ${styles[size]}`, children: label }) : null, _jsx(OperatorDropdown, { value: selectedOperator, onChange: handleOperatorChange, operators: ops, size: size, disabled: disabled }), _jsx("div", { className: `${control === 'input' ? 'dbc-flex dbc-flex-grow' : styles.valueWrapper}`, style: { width }, children: control === 'input' ? (_jsx(Input, { variant: "embedded", ...inputProps, value: localValue, onChange: e => {
|
|
136
163
|
const next = e.currentTarget.value;
|
|
137
|
-
isTypingRef.current = true;
|
|
138
164
|
setLocalValue(next);
|
|
139
165
|
scheduleEmitValue(next);
|
|
166
|
+
}, onBlur: () => {
|
|
167
|
+
flushPendingValue();
|
|
140
168
|
}, fullWidth: true, inputSize: size, placeholder: placeholder, disabled: disabled, onClear: () => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
clearTimeout(debounceRef.current);
|
|
169
|
+
clearDebounce();
|
|
170
|
+
pendingValueRef.current = '';
|
|
144
171
|
setLocalValue('');
|
|
145
172
|
emit({ value: '' });
|
|
146
173
|
} })) : single ? (_jsx(Select, { options: options, selectedValue: (_b = value) !== null && _b !== void 0 ? _b : null, onChange: v => emit({ value: v }), placeholder: placeholder, size: size, variant: "inline", onClear: () => emit({ value: '' }), disabled: disabled })) : (_jsx(MultiSelect, { options: options, size: size, variant: "inline", selectedValues: (Array.isArray(value) ? value : []), onChange: nextSelectedValues => emit({ value: nextSelectedValues }), onClear: () => emit({ value: [] }), fullWidth: true, disabled: disabled, children: placeholder })) })] }));
|
|
@@ -17,7 +17,7 @@ export function Table({ data, dataKey, columns, selectedRows, selectionMode = 's
|
|
|
17
17
|
onPageChange === null || onPageChange === void 0 ? void 0 : onPageChange(e);
|
|
18
18
|
}, [onPageChange]);
|
|
19
19
|
const bodyContent = loading && !data.length ? (_jsx(TableLoadingBody, { rows: take !== null && take !== void 0 ? take : 5, columns: visibleColumns, hasSelection: hasSelection })) : (_jsx(TableBody, { data: data, dataKey: dataKey, columns: visibleColumns, striped: striped, selectedRows: selectedRows, hasSelection: hasSelection, selectionMode: selectionMode, selectionInputName: selectionInputName, viewMode: viewMode, getRowSeverity: getRowSeverity, onRowClick: onRowClick, onRowMouseEnter: onRowMouseEnter, onRowSelect: onRowSelect }));
|
|
20
|
-
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;
|
|
20
|
+
const paginationEl = onPageChange && (loading || 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;
|
|
21
21
|
const tableClassName = cx(styles.tableRoot, styles[variant], styles[size], measuringLayout && styles.measuringLayout, getRowSeverity && styles.severityTable);
|
|
22
22
|
const tableShell = (_jsx("div", { ...rest, className: tableClassName, children: _jsx("div", { ref: tableRootRef, className: styles.tableScroll, children: !data.length && !loading ? (_jsx("div", { className: styles.emptyStateSlot, children: _jsx(TableEmptyState, { config: emptyConfig }) })) : (_jsxs("table", { className: styles.tableElement, "aria-rowcount": data.length, style: tableWidth != null ? { width: tableWidth } : undefined, children: [_jsxs("colgroup", { children: [hasSelection ? _jsx("col", { style: { width: SELECTION_COLUMN_PX } }) : null, visibleColumns.map(column => (_jsx("col", { style: column.width != null ? { width: column.width } : undefined }, column.id)))] }), _jsx(TableHeader, { columns: visibleColumns, hasSelection: hasSelection, selectionMode: selectionMode, allRowsSelected: allRowsSelected, onSelectAllRows: onSelectAllRows, sortById: sortById, sortDirection: sortDirection, onSortChange: onSortChange, headerExtras: headerExtras }), bodyContent] })) }) }));
|
|
23
23
|
if (fillViewport) {
|
|
@@ -2,9 +2,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { SkeletonLoaderItem } from '../../../components/skeleton-loader/skeleton-loader-item/SkeletonLoaderItem';
|
|
3
3
|
import { cx } from '../table.classes';
|
|
4
4
|
import styles from '../Table.module.css';
|
|
5
|
+
function getColumnWidth(column) {
|
|
6
|
+
// If column.width is defined and less than 150px, use 100%
|
|
7
|
+
if (typeof column.width === 'number' && column.width < 150) {
|
|
8
|
+
return '100%';
|
|
9
|
+
}
|
|
10
|
+
if (typeof column.width === 'string' && column.width.endsWith('px')) {
|
|
11
|
+
const px = parseInt(column.width, 10);
|
|
12
|
+
if (!isNaN(px) && px < 150) {
|
|
13
|
+
return '100%';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Otherwise, random between 50% and 90%
|
|
17
|
+
const percent = Math.floor(Math.random() * (90 - 50 + 1)) + 50;
|
|
18
|
+
return `${percent}%`;
|
|
19
|
+
}
|
|
5
20
|
export function TableLoadingBody({ rows, columns, hasSelection }) {
|
|
6
|
-
|
|
21
|
+
const widths = Array.from({ length: rows }, () => columns.map(getColumnWidth));
|
|
22
|
+
return (_jsx("tbody", { className: styles.body, children: Array.from({ length: rows }).map((_, rowIndex) => (_jsxs("tr", { className: styles.row, children: [hasSelection ? (_jsx("td", { className: cx(styles.cell, styles.selectionCell), children: _jsx("div", { className: styles.cellContent, children: _jsx(SkeletonLoaderItem, { height: 20, width: 20 }) }) })) : null, columns.map((column, columnIndex) => {
|
|
7
23
|
var _a;
|
|
8
|
-
return (_jsx("td", { className: cx(styles.cell, column.divider === 'left' && styles.dividerLeft, column.divider === 'right' && styles.dividerRight), "data-align": (_a = column.align) !== null && _a !== void 0 ? _a : 'left', "data-divider": column.divider, children: _jsx("div", { className: styles.cellContent, children: _jsx("div", { className: styles.cellValueEllipsis, children: _jsx(SkeletonLoaderItem, { height:
|
|
24
|
+
return (_jsx("td", { className: cx(styles.cell, column.divider === 'left' && styles.dividerLeft, column.divider === 'right' && styles.dividerRight), "data-align": (_a = column.align) !== null && _a !== void 0 ? _a : 'left', "data-divider": column.divider, children: _jsx("div", { className: styles.cellContent, children: _jsx("div", { className: styles.cellValueEllipsis, children: _jsx(SkeletonLoaderItem, { height: 16, width: widths[rowIndex][columnIndex] }) }) }) }, column.id));
|
|
9
25
|
})] }, `loading-row-${rowIndex}`))) }));
|
|
10
26
|
}
|