@indico-data/design-system 2.48.0 → 2.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/table/Table.stories.d.ts +1 -0
- package/lib/components/table/components/HorizontalStickyHeader.d.ts +10 -0
- package/lib/components/table/components/__tests__/HorizontalStickyHeader.test.d.ts +1 -0
- package/lib/components/table/components/helpers.d.ts +6 -0
- package/lib/components/table/hooks/usePinnedColumnsManager.d.ts +8 -0
- package/lib/components/table/sampleData.d.ts +4 -0
- package/lib/components/table/types.d.ts +11 -1
- package/lib/components/table/utils/processColumns.d.ts +2 -0
- package/lib/index.css +28 -9
- package/lib/index.d.ts +12 -1
- package/lib/index.esm.css +28 -9
- package/lib/index.esm.js +238 -2
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +238 -2
- package/lib/index.js.map +1 -1
- package/lib/utils/getPreviousHeadersWidth.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/table/Table.mdx +134 -0
- package/src/components/table/Table.stories.tsx +71 -2
- package/src/components/table/Table.tsx +16 -1
- package/src/components/table/components/HorizontalStickyHeader.tsx +57 -0
- package/src/components/table/components/__tests__/HorizontalStickyHeader.test.tsx +104 -0
- package/src/components/table/components/helpers.ts +90 -0
- package/src/components/table/hooks/usePinnedColumnsManager.ts +146 -0
- package/src/components/table/{sampleData.ts → sampleData.tsx} +156 -1
- package/src/components/table/styles/Table.scss +32 -15
- package/src/components/table/styles/_variables.scss +2 -0
- package/src/components/table/types.ts +13 -1
- package/src/components/table/utils/processColumns.tsx +35 -0
- package/src/setup/setupTests.ts +8 -0
- package/src/utils/getPreviousHeadersWidth.ts +12 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface HorizontalStickyHeaderProps {
|
|
2
|
+
children: React.ReactNode;
|
|
3
|
+
position: number;
|
|
4
|
+
onPinColumn?: (columnId: string) => void;
|
|
5
|
+
isPinned?: boolean;
|
|
6
|
+
forceUpdate?: number;
|
|
7
|
+
pinnedColumnIds: string[];
|
|
8
|
+
}
|
|
9
|
+
declare const HorizontalStickyHeader: ({ children, position, onPinColumn, isPinned, pinnedColumnIds, }: HorizontalStickyHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default HorizontalStickyHeader;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CSSObject } from 'styled-components';
|
|
2
|
+
export declare const getPreviousHeadersWidth: (position: number, pinnedColumnIds: string[]) => number;
|
|
3
|
+
export declare const applyStickyStylesToTableHeader: (position: number, left: number) => Promise<void>;
|
|
4
|
+
export declare const sortPinnedColumns: <T>(columns: T[], pinnedColumnIds: string[]) => T[];
|
|
5
|
+
export declare const getPinnedColumnStyles: (isPinned: boolean, index: number, pinnedColumnIds: string[]) => CSSObject;
|
|
6
|
+
export declare const clearStickyStyles: (header: HTMLElement) => void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { TableColumn } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Hook to manage pinned columns in a table
|
|
4
|
+
* Handles initialization, toggling, positioning and resizing of pinned columns
|
|
5
|
+
*/
|
|
6
|
+
export declare const usePinnedColumnsManager: <T>(columns: TableColumn<T>[], canPinColumns: boolean, onPinnedColumnsChange?: (pinnedColumnIds: string[]) => void) => {
|
|
7
|
+
columnsWithPinning: TableColumn<T>[];
|
|
8
|
+
};
|
|
@@ -6,6 +6,10 @@ export interface SampleDataRow {
|
|
|
6
6
|
weapon: string;
|
|
7
7
|
backstory: string;
|
|
8
8
|
favoriteMeal: string;
|
|
9
|
+
homeland: string;
|
|
10
|
+
alignment: string;
|
|
11
|
+
specialAbility: string;
|
|
12
|
+
test: string;
|
|
9
13
|
}
|
|
10
14
|
export declare const sampleData: SampleDataRow[];
|
|
11
15
|
export declare const columns: TableColumn<SampleDataRow>[];
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { Direction as RDTDirection, Alignment as RDTAlignment, TableColumn as RDTTableColumn, IDataTableProps } from 'react-data-table-component';
|
|
2
|
+
import { CSSObject } from 'styled-components';
|
|
2
3
|
export type Direction = `${RDTDirection}`;
|
|
3
4
|
export type Alignment = `${RDTAlignment}`;
|
|
4
|
-
export
|
|
5
|
+
export interface PinnableColumn<T> extends RDTTableColumn<T> {
|
|
6
|
+
id: string;
|
|
7
|
+
isPinned?: boolean;
|
|
8
|
+
style?: CSSObject;
|
|
9
|
+
position?: number;
|
|
10
|
+
}
|
|
11
|
+
export type TableColumn<T> = PinnableColumn<T>;
|
|
5
12
|
export interface TableProps<T> extends Omit<IDataTableProps<T>, 'paginationComponent' | 'direction' | 'subHeaderAlign'> {
|
|
13
|
+
columns: TableColumn<T>[];
|
|
6
14
|
isDisabled?: boolean;
|
|
7
15
|
isLoading?: boolean;
|
|
8
16
|
direction?: Direction;
|
|
9
17
|
subHeaderAlign?: 'left' | 'right' | 'center';
|
|
10
18
|
isFullHeight?: boolean;
|
|
11
19
|
totalEntriesText?: string;
|
|
20
|
+
canPinColumns?: boolean;
|
|
21
|
+
onPinnedColumnsChange?: (pinnedColumnIds: any[]) => void;
|
|
12
22
|
}
|
package/lib/index.css
CHANGED
|
@@ -804,6 +804,8 @@ a:hover,
|
|
|
804
804
|
--pf-table-highlighted-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4), 0 8px 16px rgba(0, 0, 0, 0.3);
|
|
805
805
|
--pf-table-font-size: var(--pf-font-size-body2);
|
|
806
806
|
--pf-table-pagination-background-color: var(--pf-primary-color-700);
|
|
807
|
+
--pf-table-pinned-column-border-color: var(--pf-primary-color-100);
|
|
808
|
+
--pf-table-pinned-column-background-color: var(--pf-table-background-color);
|
|
807
809
|
}
|
|
808
810
|
|
|
809
811
|
.table-loading {
|
|
@@ -856,6 +858,20 @@ a:hover,
|
|
|
856
858
|
.table-body::-webkit-scrollbar-thumb:hover {
|
|
857
859
|
background: var(--pf-primary-color);
|
|
858
860
|
}
|
|
861
|
+
.table .table__column__pin-action {
|
|
862
|
+
padding: 0;
|
|
863
|
+
padding-right: var(--pf-padding-1);
|
|
864
|
+
}
|
|
865
|
+
.table .table__column--is-pinned {
|
|
866
|
+
opacity: 1;
|
|
867
|
+
}
|
|
868
|
+
.table .table__column--is-not-pinned {
|
|
869
|
+
opacity: 0.3;
|
|
870
|
+
}
|
|
871
|
+
.table .table__header-cell {
|
|
872
|
+
display: flex;
|
|
873
|
+
align-items: center;
|
|
874
|
+
}
|
|
859
875
|
.table > *:nth-child(3) {
|
|
860
876
|
margin-top: auto;
|
|
861
877
|
background-color: transparent;
|
|
@@ -881,27 +897,26 @@ a:hover,
|
|
|
881
897
|
.table button:disabled svg {
|
|
882
898
|
fill: var(--pf-table-disabled-button-color);
|
|
883
899
|
}
|
|
900
|
+
.table .rdt_TableHead {
|
|
901
|
+
z-index: 3;
|
|
902
|
+
}
|
|
884
903
|
.table .rdt_TableHeader {
|
|
885
904
|
border-radius: var(--pf-rounded) 0;
|
|
886
905
|
border: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
887
906
|
border-bottom: none;
|
|
888
907
|
}
|
|
889
|
-
.table .rdt_TableHeadRow > :first-child,
|
|
890
|
-
.table .rdt_TableRow > :first-child {
|
|
891
|
-
padding-left: var(--pf-padding-4);
|
|
892
|
-
min-width: 60px;
|
|
893
|
-
justify-content: left;
|
|
894
|
-
}
|
|
895
908
|
.table .rdt_TableRow {
|
|
896
909
|
border-top: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
897
910
|
border-bottom: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
898
911
|
}
|
|
912
|
+
.table .rdt_TableRow:hover {
|
|
913
|
+
border-top: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
914
|
+
border-bottom: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
915
|
+
outline-color: var(--pf-table-border-color);
|
|
916
|
+
}
|
|
899
917
|
.table .rdt_TableRow:hover .rdt_TableCell {
|
|
900
918
|
background-color: var(--pf-table-hover-color) !important;
|
|
901
919
|
}
|
|
902
|
-
.table .rdt_TableRow:first-child .rdt_TableCell {
|
|
903
|
-
border-top: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
904
|
-
}
|
|
905
920
|
.table .rdt_TableCell,
|
|
906
921
|
.table .rdt_TableCol {
|
|
907
922
|
font-size: var(--pf-table-font-size);
|
|
@@ -910,6 +925,10 @@ a:hover,
|
|
|
910
925
|
.table .rdt_TableCol:not(:first-child) {
|
|
911
926
|
border-left: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
912
927
|
}
|
|
928
|
+
.table .rdt_TableCell:not(:last-of-type),
|
|
929
|
+
.table .rdt_TableCol:not(:last-of-type) {
|
|
930
|
+
border-bottom-width: 0;
|
|
931
|
+
}
|
|
913
932
|
.table .table--striped .rdt_TableRow:nth-child(odd) .rdt_TableCell {
|
|
914
933
|
background-color: var(--pf-table-stripe-color);
|
|
915
934
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export * from '@floating-ui/react-dom';
|
|
|
4
4
|
import React$1, { CSSProperties, MouseEventHandler, ReactElement } from 'react';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
import { ContainerProps, RowProps, ColProps } from 'react-grid-system';
|
|
7
|
-
import { IDataTableProps, Direction as Direction$1 } from 'react-data-table-component';
|
|
7
|
+
import { IDataTableProps, Direction as Direction$1, TableColumn as TableColumn$1 } from 'react-data-table-component';
|
|
8
|
+
import { CSSObject } from 'styled-components';
|
|
8
9
|
import { Props as Props$7 } from 'react-select';
|
|
9
10
|
import { DateRange, OnSelectHandler, Mode, CustomComponents, Matcher, Formatters, MonthChangeEventHandler, DayEventHandler } from 'react-day-picker';
|
|
10
11
|
|
|
@@ -184,13 +185,23 @@ type SelectOption = {
|
|
|
184
185
|
};
|
|
185
186
|
|
|
186
187
|
type Direction = `${Direction$1}`;
|
|
188
|
+
interface PinnableColumn<T> extends TableColumn$1<T> {
|
|
189
|
+
id: string;
|
|
190
|
+
isPinned?: boolean;
|
|
191
|
+
style?: CSSObject;
|
|
192
|
+
position?: number;
|
|
193
|
+
}
|
|
194
|
+
type TableColumn<T> = PinnableColumn<T>;
|
|
187
195
|
interface TableProps<T> extends Omit<IDataTableProps<T>, 'paginationComponent' | 'direction' | 'subHeaderAlign'> {
|
|
196
|
+
columns: TableColumn<T>[];
|
|
188
197
|
isDisabled?: boolean;
|
|
189
198
|
isLoading?: boolean;
|
|
190
199
|
direction?: Direction;
|
|
191
200
|
subHeaderAlign?: 'left' | 'right' | 'center';
|
|
192
201
|
isFullHeight?: boolean;
|
|
193
202
|
totalEntriesText?: string;
|
|
203
|
+
canPinColumns?: boolean;
|
|
204
|
+
onPinnedColumnsChange?: (pinnedColumnIds: any[]) => void;
|
|
194
205
|
}
|
|
195
206
|
|
|
196
207
|
type PillSize = 'sm' | 'md' | 'lg';
|
package/lib/index.esm.css
CHANGED
|
@@ -804,6 +804,8 @@ a:hover,
|
|
|
804
804
|
--pf-table-highlighted-box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4), 0 8px 16px rgba(0, 0, 0, 0.3);
|
|
805
805
|
--pf-table-font-size: var(--pf-font-size-body2);
|
|
806
806
|
--pf-table-pagination-background-color: var(--pf-primary-color-700);
|
|
807
|
+
--pf-table-pinned-column-border-color: var(--pf-primary-color-100);
|
|
808
|
+
--pf-table-pinned-column-background-color: var(--pf-table-background-color);
|
|
807
809
|
}
|
|
808
810
|
|
|
809
811
|
.table-loading {
|
|
@@ -856,6 +858,20 @@ a:hover,
|
|
|
856
858
|
.table-body::-webkit-scrollbar-thumb:hover {
|
|
857
859
|
background: var(--pf-primary-color);
|
|
858
860
|
}
|
|
861
|
+
.table .table__column__pin-action {
|
|
862
|
+
padding: 0;
|
|
863
|
+
padding-right: var(--pf-padding-1);
|
|
864
|
+
}
|
|
865
|
+
.table .table__column--is-pinned {
|
|
866
|
+
opacity: 1;
|
|
867
|
+
}
|
|
868
|
+
.table .table__column--is-not-pinned {
|
|
869
|
+
opacity: 0.3;
|
|
870
|
+
}
|
|
871
|
+
.table .table__header-cell {
|
|
872
|
+
display: flex;
|
|
873
|
+
align-items: center;
|
|
874
|
+
}
|
|
859
875
|
.table > *:nth-child(3) {
|
|
860
876
|
margin-top: auto;
|
|
861
877
|
background-color: transparent;
|
|
@@ -881,27 +897,26 @@ a:hover,
|
|
|
881
897
|
.table button:disabled svg {
|
|
882
898
|
fill: var(--pf-table-disabled-button-color);
|
|
883
899
|
}
|
|
900
|
+
.table .rdt_TableHead {
|
|
901
|
+
z-index: 3;
|
|
902
|
+
}
|
|
884
903
|
.table .rdt_TableHeader {
|
|
885
904
|
border-radius: var(--pf-rounded) 0;
|
|
886
905
|
border: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
887
906
|
border-bottom: none;
|
|
888
907
|
}
|
|
889
|
-
.table .rdt_TableHeadRow > :first-child,
|
|
890
|
-
.table .rdt_TableRow > :first-child {
|
|
891
|
-
padding-left: var(--pf-padding-4);
|
|
892
|
-
min-width: 60px;
|
|
893
|
-
justify-content: left;
|
|
894
|
-
}
|
|
895
908
|
.table .rdt_TableRow {
|
|
896
909
|
border-top: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
897
910
|
border-bottom: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
898
911
|
}
|
|
912
|
+
.table .rdt_TableRow:hover {
|
|
913
|
+
border-top: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
914
|
+
border-bottom: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
915
|
+
outline-color: var(--pf-table-border-color);
|
|
916
|
+
}
|
|
899
917
|
.table .rdt_TableRow:hover .rdt_TableCell {
|
|
900
918
|
background-color: var(--pf-table-hover-color) !important;
|
|
901
919
|
}
|
|
902
|
-
.table .rdt_TableRow:first-child .rdt_TableCell {
|
|
903
|
-
border-top: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
904
|
-
}
|
|
905
920
|
.table .rdt_TableCell,
|
|
906
921
|
.table .rdt_TableCol {
|
|
907
922
|
font-size: var(--pf-table-font-size);
|
|
@@ -910,6 +925,10 @@ a:hover,
|
|
|
910
925
|
.table .rdt_TableCol:not(:first-child) {
|
|
911
926
|
border-left: var(--pf-border-sm) solid var(--pf-table-border-color);
|
|
912
927
|
}
|
|
928
|
+
.table .rdt_TableCell:not(:last-of-type),
|
|
929
|
+
.table .rdt_TableCol:not(:last-of-type) {
|
|
930
|
+
border-bottom-width: 0;
|
|
931
|
+
}
|
|
913
932
|
.table .table--striped .rdt_TableRow:nth-child(odd) .rdt_TableCell {
|
|
914
933
|
background-color: var(--pf-table-stripe-color);
|
|
915
934
|
}
|
package/lib/index.esm.js
CHANGED
|
@@ -2603,6 +2603,16 @@ function __rest(s, e) {
|
|
|
2603
2603
|
return t;
|
|
2604
2604
|
}
|
|
2605
2605
|
|
|
2606
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
2607
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
2608
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
2609
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
2610
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
2611
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
2612
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2606
2616
|
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
2607
2617
|
var e = new Error(message);
|
|
2608
2618
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
@@ -7256,8 +7266,234 @@ const TablePagination = ({ rowsPerPage, rowCount, onChangePage, currentPage, tot
|
|
|
7256
7266
|
return (jsx("div", { className: "table__pagination", children: jsxs(Row, { align: "center", justify: "between", children: [jsx(Col, { xs: "content", children: totalEntriesText && (jsx("span", { "data-testid": "table-pagination-total-entries", className: "table__pagination-total-entries", children: totalEntriesText })) }), jsx(Col, { xs: "content", children: jsx(Pagination, { "data-testid": "table-pagination-component", totalPages: totalPages, currentPage: currentPage, onChange: (page) => onChangePage(page, rowsPerPage) }) })] }) }));
|
|
7257
7267
|
};
|
|
7258
7268
|
|
|
7269
|
+
// Gets the width of the previous pinned columns
|
|
7270
|
+
const getPreviousHeadersWidth = (position, pinnedColumnIds) => {
|
|
7271
|
+
let totalWidth = 0;
|
|
7272
|
+
// Add checkbox column width if it's pinned
|
|
7273
|
+
if (pinnedColumnIds.includes('checkbox-column')) {
|
|
7274
|
+
const checkboxCell = document.querySelector('.rdt_TableCol:not([data-column-id])');
|
|
7275
|
+
if (checkboxCell) {
|
|
7276
|
+
totalWidth += checkboxCell.offsetWidth;
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
// Add widths of other pinned columns before this position
|
|
7280
|
+
const previousHeaders = Array.from({ length: position }, (_, i) => {
|
|
7281
|
+
const header = document.querySelector(`[data-column-id="sticky-column-${i}"]`);
|
|
7282
|
+
if (header && pinnedColumnIds.includes(`sticky-column-${i}`)) {
|
|
7283
|
+
return header;
|
|
7284
|
+
}
|
|
7285
|
+
return null;
|
|
7286
|
+
}).filter((header) => header !== null);
|
|
7287
|
+
// Calculate base width from previous columns
|
|
7288
|
+
totalWidth = previousHeaders.reduce((acc, header) => {
|
|
7289
|
+
return acc + header.offsetWidth;
|
|
7290
|
+
}, totalWidth);
|
|
7291
|
+
// Leave this for if we ever try to fix the auto width columns
|
|
7292
|
+
// There is a bug where borders cause the offset to be wrong, this keeps it in sync.
|
|
7293
|
+
// Add offset that increases by 1 every two columns after index 1
|
|
7294
|
+
// if (position >= 2) {
|
|
7295
|
+
// const additionalOffset = Math.floor((position - 2) / 2) + 1;
|
|
7296
|
+
// totalWidth += additionalOffset;
|
|
7297
|
+
// }
|
|
7298
|
+
return totalWidth;
|
|
7299
|
+
};
|
|
7300
|
+
// Applies sticky styles to the column header
|
|
7301
|
+
const applyStickyStylesToTableHeader = (position, left) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7302
|
+
const header = document.querySelector(`[data-column-id="sticky-column-${position}"]`);
|
|
7303
|
+
if (header) {
|
|
7304
|
+
header.style.position = 'sticky';
|
|
7305
|
+
header.style.left = `${left}px`;
|
|
7306
|
+
header.style.zIndex = '3';
|
|
7307
|
+
header.style.backgroundColor =
|
|
7308
|
+
'var(--pf-table-pinned-column-background-color)';
|
|
7309
|
+
}
|
|
7310
|
+
});
|
|
7311
|
+
// Sorts the pinned columns so that any column that is pinned comes before any column that is not.
|
|
7312
|
+
const sortPinnedColumns = (columns, pinnedColumnIds) => {
|
|
7313
|
+
return [...columns].sort((a, b) => {
|
|
7314
|
+
const aIsPinned = pinnedColumnIds.includes(a.id);
|
|
7315
|
+
const bIsPinned = pinnedColumnIds.includes(b.id);
|
|
7316
|
+
if (aIsPinned && !bIsPinned)
|
|
7317
|
+
return -1; // a comes first
|
|
7318
|
+
if (!aIsPinned && bIsPinned)
|
|
7319
|
+
return 1; // b comes first
|
|
7320
|
+
return 0; // maintain relative order for columns with same pinned state
|
|
7321
|
+
});
|
|
7322
|
+
};
|
|
7323
|
+
// Gets the styles for the pinned columns
|
|
7324
|
+
const getPinnedColumnStyles = (isPinned, index, pinnedColumnIds) => {
|
|
7325
|
+
return isPinned
|
|
7326
|
+
? {
|
|
7327
|
+
position: 'sticky',
|
|
7328
|
+
left: `${getPreviousHeadersWidth(index, pinnedColumnIds)}px`,
|
|
7329
|
+
zIndex: 3,
|
|
7330
|
+
backgroundColor: 'var(--pf-table-pinned-column-background-color)',
|
|
7331
|
+
}
|
|
7332
|
+
: {
|
|
7333
|
+
position: undefined,
|
|
7334
|
+
left: undefined,
|
|
7335
|
+
zIndex: undefined,
|
|
7336
|
+
backgroundColor: undefined,
|
|
7337
|
+
};
|
|
7338
|
+
};
|
|
7339
|
+
const clearStickyStyles = (header) => {
|
|
7340
|
+
header.style.position = '';
|
|
7341
|
+
header.style.left = '';
|
|
7342
|
+
header.style.zIndex = '';
|
|
7343
|
+
header.style.backgroundColor = '';
|
|
7344
|
+
};
|
|
7345
|
+
|
|
7346
|
+
const HorizontalStickyHeader = ({ children, position, onPinColumn, isPinned = false, pinnedColumnIds, }) => {
|
|
7347
|
+
useEffect(() => {
|
|
7348
|
+
const calculateWidth = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
7349
|
+
yield new Promise((resolve) => setTimeout(resolve, 0));
|
|
7350
|
+
const header = document.querySelector(`[data-column-id="sticky-column-${position}"]`);
|
|
7351
|
+
if (header) {
|
|
7352
|
+
if (isPinned) {
|
|
7353
|
+
const width = getPreviousHeadersWidth(position, pinnedColumnIds);
|
|
7354
|
+
yield applyStickyStylesToTableHeader(position, width);
|
|
7355
|
+
}
|
|
7356
|
+
else {
|
|
7357
|
+
clearStickyStyles(header);
|
|
7358
|
+
}
|
|
7359
|
+
}
|
|
7360
|
+
});
|
|
7361
|
+
calculateWidth();
|
|
7362
|
+
}, [position, isPinned, pinnedColumnIds]);
|
|
7363
|
+
return (jsxs("div", { className: "table__header-cell", "data-testid": `sticky-column-${position}`, children: [jsx(Button$1, { "data-testid": `sticky-header-pin-button-${position}`, variant: "link", size: "sm", iconLeft: "pin", onClick: onPinColumn, ariaLabel: isPinned ? 'Unpin column' : 'Pin column', className: `table__column--${isPinned ? 'is-pinned' : 'is-not-pinned'} table__column__pin-action` }), jsx("div", { className: "table__header-content", children: children })] }));
|
|
7364
|
+
};
|
|
7365
|
+
|
|
7366
|
+
const processColumns = (columns, pinnedColumnIds, togglePinnedColumn) => {
|
|
7367
|
+
return columns.map((column, index) => {
|
|
7368
|
+
const dataColumnId = `sticky-column-${index}`;
|
|
7369
|
+
const isPinned = pinnedColumnIds.includes(dataColumnId);
|
|
7370
|
+
const headerContent = column.isPinned !== undefined ? (jsx(HorizontalStickyHeader, { position: index, isPinned: isPinned, onPinColumn: () => togglePinnedColumn(column.id), pinnedColumnIds: pinnedColumnIds, children: column.name })) : (jsx(Fragment, { children: column.name }));
|
|
7371
|
+
return Object.assign(Object.assign({}, column), { name: headerContent, id: dataColumnId, style: getPinnedColumnStyles(isPinned, index, pinnedColumnIds) });
|
|
7372
|
+
});
|
|
7373
|
+
};
|
|
7374
|
+
|
|
7375
|
+
/**
|
|
7376
|
+
* Hook to manage pinned columns in a table
|
|
7377
|
+
* Handles initialization, toggling, positioning and resizing of pinned columns
|
|
7378
|
+
*/
|
|
7379
|
+
const usePinnedColumnsManager = (columns, canPinColumns, onPinnedColumnsChange) => {
|
|
7380
|
+
const pinnedColumnIds = columns.filter((column) => column.isPinned).map((column) => column.id);
|
|
7381
|
+
// `dataColumnIds` is the list of IDs used as `data-column-id` attributes on the table headers and cells
|
|
7382
|
+
const dataColumnIds = useMemo(() => {
|
|
7383
|
+
const ids = columns
|
|
7384
|
+
.map((column, index) => (column.isPinned ? `sticky-column-${index}` : null))
|
|
7385
|
+
.filter((id) => id !== null);
|
|
7386
|
+
return ids.length > 0 ? ['checkbox-column', ...ids] : ids;
|
|
7387
|
+
}, [columns]);
|
|
7388
|
+
// Toggle individual column pin state
|
|
7389
|
+
const togglePinnedColumn = useCallback((columnId) => {
|
|
7390
|
+
const prevPinnedColumns = pinnedColumnIds;
|
|
7391
|
+
// Handle unpinning
|
|
7392
|
+
if (prevPinnedColumns.some((id) => id === columnId)) {
|
|
7393
|
+
onPinnedColumnsChange === null || onPinnedColumnsChange === void 0 ? void 0 : onPinnedColumnsChange(prevPinnedColumns.filter((id) => id !== columnId));
|
|
7394
|
+
}
|
|
7395
|
+
else {
|
|
7396
|
+
onPinnedColumnsChange === null || onPinnedColumnsChange === void 0 ? void 0 : onPinnedColumnsChange(prevPinnedColumns.concat(columnId));
|
|
7397
|
+
}
|
|
7398
|
+
}, [pinnedColumnIds, onPinnedColumnsChange]);
|
|
7399
|
+
// Handle resize events and recalculate pinned column positions
|
|
7400
|
+
useEffect(() => {
|
|
7401
|
+
if (!canPinColumns)
|
|
7402
|
+
return;
|
|
7403
|
+
const recalculatePositions = () => {
|
|
7404
|
+
// Reset all column styles and remove last-pinned-column class
|
|
7405
|
+
const allCells = document.querySelectorAll('.rdt_TableCol, .rdt_TableCell');
|
|
7406
|
+
allCells.forEach((cell) => {
|
|
7407
|
+
cell.style.position = '';
|
|
7408
|
+
cell.style.left = '';
|
|
7409
|
+
cell.style.zIndex = '';
|
|
7410
|
+
cell.style.backgroundColor = '';
|
|
7411
|
+
cell.style.borderRight = '';
|
|
7412
|
+
});
|
|
7413
|
+
// Apply styles to pinned columns
|
|
7414
|
+
dataColumnIds.forEach((column, index) => {
|
|
7415
|
+
const isLastPinnedColumn = index === dataColumnIds.length - 1;
|
|
7416
|
+
if (column === 'checkbox-column') {
|
|
7417
|
+
// Handle header checkbox
|
|
7418
|
+
const headerCheckbox = document.querySelector('.rdt_TableCol:not([data-column-id])');
|
|
7419
|
+
if (headerCheckbox) {
|
|
7420
|
+
headerCheckbox.style.position = 'sticky';
|
|
7421
|
+
headerCheckbox.style.left = '0';
|
|
7422
|
+
headerCheckbox.style.zIndex = '4';
|
|
7423
|
+
headerCheckbox.style.backgroundColor =
|
|
7424
|
+
'var(--pf-table-background-color)';
|
|
7425
|
+
}
|
|
7426
|
+
// Handle cell checkboxes
|
|
7427
|
+
const cellCheckboxes = document.querySelectorAll('.rdt_TableCell:first-child');
|
|
7428
|
+
cellCheckboxes.forEach((cell) => {
|
|
7429
|
+
cell.style.position = 'sticky';
|
|
7430
|
+
cell.style.left = '0';
|
|
7431
|
+
cell.style.zIndex = '2';
|
|
7432
|
+
cell.style.backgroundColor =
|
|
7433
|
+
'var(--pf-table-pinned-column-background-color)';
|
|
7434
|
+
if (isLastPinnedColumn) {
|
|
7435
|
+
cell.style.borderRight =
|
|
7436
|
+
`2px solid var(--pf-table-pinned-column-border-color)`;
|
|
7437
|
+
}
|
|
7438
|
+
});
|
|
7439
|
+
}
|
|
7440
|
+
else {
|
|
7441
|
+
const columnIndex = parseInt(column.split('-')[2]);
|
|
7442
|
+
const left = getPreviousHeadersWidth(columnIndex, dataColumnIds);
|
|
7443
|
+
// Headers
|
|
7444
|
+
const headers = document.querySelectorAll(`.rdt_TableCol[data-column-id="sticky-column-${columnIndex}"]`);
|
|
7445
|
+
headers.forEach((header) => {
|
|
7446
|
+
header.style.position = 'sticky';
|
|
7447
|
+
header.style.left = `${left}px`;
|
|
7448
|
+
header.style.zIndex = '2';
|
|
7449
|
+
header.style.backgroundColor =
|
|
7450
|
+
'var(--pf-table-pinned-column-background-color)';
|
|
7451
|
+
if (isLastPinnedColumn) {
|
|
7452
|
+
header.style.borderRight =
|
|
7453
|
+
`2px solid var(--pf-table-pinned-column-border-color)`;
|
|
7454
|
+
}
|
|
7455
|
+
});
|
|
7456
|
+
// Cells
|
|
7457
|
+
const cells = document.querySelectorAll(`.rdt_TableCell[data-column-id="sticky-column-${columnIndex}"]`);
|
|
7458
|
+
cells.forEach((cell) => {
|
|
7459
|
+
cell.style.position = 'sticky';
|
|
7460
|
+
cell.style.left = `${left}px`;
|
|
7461
|
+
cell.style.zIndex = '2';
|
|
7462
|
+
cell.style.backgroundColor =
|
|
7463
|
+
'var(--pf-table-pinned-column-background-color)';
|
|
7464
|
+
if (isLastPinnedColumn) {
|
|
7465
|
+
cell.style.borderRight =
|
|
7466
|
+
`2px solid var(--pf-table-pinned-column-border-color)`;
|
|
7467
|
+
}
|
|
7468
|
+
});
|
|
7469
|
+
}
|
|
7470
|
+
});
|
|
7471
|
+
};
|
|
7472
|
+
// Set up resize observers
|
|
7473
|
+
const table = document.querySelector('.rdt_Table');
|
|
7474
|
+
const resizeObserver = new ResizeObserver(recalculatePositions);
|
|
7475
|
+
if (table) {
|
|
7476
|
+
resizeObserver.observe(table);
|
|
7477
|
+
}
|
|
7478
|
+
window.addEventListener('resize', recalculatePositions);
|
|
7479
|
+
return () => {
|
|
7480
|
+
resizeObserver.disconnect();
|
|
7481
|
+
window.removeEventListener('resize', recalculatePositions);
|
|
7482
|
+
};
|
|
7483
|
+
}, [canPinColumns, dataColumnIds]);
|
|
7484
|
+
// Process columns for rendering with pin state
|
|
7485
|
+
const columnsWithPinning = canPinColumns
|
|
7486
|
+
? sortPinnedColumns(processColumns(columns, dataColumnIds, togglePinnedColumn), dataColumnIds)
|
|
7487
|
+
: columns;
|
|
7488
|
+
return {
|
|
7489
|
+
columnsWithPinning, // Columns with pin state and handlers applied
|
|
7490
|
+
};
|
|
7491
|
+
};
|
|
7492
|
+
|
|
7259
7493
|
const Table = (props) => {
|
|
7260
|
-
const { responsive = true, direction = 'auto', keyField = 'id', striped = false, noDataComponent = 'built-in', isDisabled, isLoading, isFullHeight = false, subHeaderAlign = 'left', className, paginationTotalRows, totalEntriesText } = props, rest = __rest(props, ["responsive", "direction", "keyField", "striped", "noDataComponent", "isDisabled", "isLoading", "isFullHeight", "subHeaderAlign", "className", "paginationTotalRows", "totalEntriesText"]);
|
|
7494
|
+
const { responsive = true, direction = 'auto', keyField = 'id', striped = false, noDataComponent = 'built-in', isDisabled, isLoading, isFullHeight = false, subHeaderAlign = 'left', className, paginationTotalRows, totalEntriesText, data, columns: initialColumns, canPinColumns = false, onPinnedColumnsChange } = props, rest = __rest(props, ["responsive", "direction", "keyField", "striped", "noDataComponent", "isDisabled", "isLoading", "isFullHeight", "subHeaderAlign", "className", "paginationTotalRows", "totalEntriesText", "data", "columns", "canPinColumns", "onPinnedColumnsChange"]);
|
|
7495
|
+
// Turns on/off column pinning.
|
|
7496
|
+
const { columnsWithPinning } = usePinnedColumnsManager(initialColumns, canPinColumns, onPinnedColumnsChange);
|
|
7261
7497
|
const combinedClassName = classNames(className, {
|
|
7262
7498
|
'table--striped': striped,
|
|
7263
7499
|
'table-body': true,
|
|
@@ -7265,7 +7501,7 @@ const Table = (props) => {
|
|
|
7265
7501
|
const tableWrapperClassName = classNames('table', {
|
|
7266
7502
|
'table--full-height': isFullHeight,
|
|
7267
7503
|
});
|
|
7268
|
-
return (jsx("div", { className: tableWrapperClassName, "data-testid": "table", children: jsx(Xe, Object.assign({ responsive: responsive, direction: direction, subHeaderAlign: subHeaderAlign, keyField: keyField, striped: striped, className: combinedClassName, disabled: isDisabled, noDataComponent: noDataComponent, progressPending: isLoading, progressComponent: jsx(LoadingComponent, {}), pagination: true, paginationComponent: (props) => (jsx(TablePagination, Object.assign({}, props, { totalEntriesText: totalEntriesText }))), paginationTotalRows: paginationTotalRows }, rest)) }));
|
|
7504
|
+
return (jsx("div", { className: tableWrapperClassName, "data-testid": "table", children: jsx(Xe, Object.assign({ data: data, columns: columnsWithPinning, responsive: responsive, direction: direction, subHeaderAlign: subHeaderAlign, keyField: keyField, striped: striped, className: combinedClassName, disabled: isDisabled, noDataComponent: noDataComponent, progressPending: isLoading, progressComponent: jsx(LoadingComponent, {}), pagination: true, paginationComponent: (props) => (jsx(TablePagination, Object.assign({}, props, { totalEntriesText: totalEntriesText }))), paginationTotalRows: paginationTotalRows, highlightOnHover: true, pointerOnHover: true }, rest)) }));
|
|
7269
7505
|
};
|
|
7270
7506
|
|
|
7271
7507
|
const Radio = React__default.forwardRef((_a, ref) => {
|