@purpurds/table 7.1.0 → 7.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpurds/table",
3
- "version": "7.1.0",
3
+ "version": "7.3.0",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "./dist/table.cjs.js",
6
6
  "types": "./dist/table.d.ts",
@@ -17,22 +17,22 @@
17
17
  "dependencies": {
18
18
  "@tanstack/react-table": "~8.21.2",
19
19
  "classnames": "~2.5.0",
20
- "@purpurds/badge": "7.1.0",
21
- "@purpurds/button": "7.1.0",
22
- "@purpurds/checkbox": "7.1.0",
23
- "@purpurds/cta-link": "7.1.0",
24
- "@purpurds/drawer": "7.1.0",
25
- "@purpurds/heading": "7.1.0",
26
- "@purpurds/icon": "7.1.0",
27
- "@purpurds/link": "7.1.0",
28
- "@purpurds/paragraph": "7.1.0",
29
- "@purpurds/select": "7.1.0",
30
- "@purpurds/skeleton": "7.1.0",
31
- "@purpurds/text-field": "7.1.0",
32
- "@purpurds/toggle": "7.1.0",
33
- "@purpurds/tokens": "7.1.0",
34
- "@purpurds/tooltip": "7.1.0",
35
- "@purpurds/visually-hidden": "7.1.0"
20
+ "@purpurds/badge": "7.3.0",
21
+ "@purpurds/button": "7.3.0",
22
+ "@purpurds/checkbox": "7.3.0",
23
+ "@purpurds/cta-link": "7.3.0",
24
+ "@purpurds/drawer": "7.3.0",
25
+ "@purpurds/heading": "7.3.0",
26
+ "@purpurds/icon": "7.3.0",
27
+ "@purpurds/link": "7.3.0",
28
+ "@purpurds/paragraph": "7.3.0",
29
+ "@purpurds/select": "7.3.0",
30
+ "@purpurds/skeleton": "7.3.0",
31
+ "@purpurds/text-field": "7.3.0",
32
+ "@purpurds/toggle": "7.3.0",
33
+ "@purpurds/tokens": "7.3.0",
34
+ "@purpurds/tooltip": "7.3.0",
35
+ "@purpurds/visually-hidden": "7.3.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@rushstack/eslint-patch": "~1.10.0",
@@ -57,13 +57,13 @@
57
57
  "vitest": "^3.1.2",
58
58
  "vitest-axe": "~0.1.0",
59
59
  "vitest-canvas-mock": "~0.3.3",
60
- "@purpurds/autocomplete": "7.1.0",
60
+ "@purpurds/autocomplete": "7.3.0",
61
61
  "@purpurds/component-rig": "1.0.0",
62
- "@purpurds/grid": "7.1.0",
63
- "@purpurds/illustrative-icon": "7.1.0",
64
- "@purpurds/listbox": "7.1.0",
65
- "@purpurds/pagination": "7.1.0",
66
- "@purpurds/label": "7.1.0"
62
+ "@purpurds/grid": "7.3.0",
63
+ "@purpurds/illustrative-icon": "7.3.0",
64
+ "@purpurds/pagination": "7.3.0",
65
+ "@purpurds/listbox": "7.3.0",
66
+ "@purpurds/label": "7.3.0"
67
67
  },
68
68
  "scripts": {
69
69
  "build:dev": "vite",
@@ -156,6 +156,14 @@ const meta = {
156
156
  control: "boolean",
157
157
  description: "Full width of the table",
158
158
  },
159
+ stickyFirstColumn: {
160
+ control: "boolean",
161
+ description: "Sticky first column",
162
+ },
163
+ stickyHeaders: {
164
+ control: "boolean",
165
+ description: "Sticky headers",
166
+ },
159
167
  },
160
168
  } satisfies Meta<typeof Table<TableData>>;
161
169
 
@@ -280,6 +288,8 @@ export const Showcase: StoryTableData = {
280
288
  columns: columnDef,
281
289
  loading: true,
282
290
  fullWidth: true,
291
+ stickyFirstColumn: true,
292
+ stickyHeaders: true,
283
293
  },
284
294
  parameters: {
285
295
  docs: {
@@ -392,6 +402,8 @@ manages filtering, sorting and pagination internally.
392
402
  onSecondaryButtonClick={() => console.log("Secondary button clicked")}
393
403
  rowSelectionAriaLabels={args.rowSelectionAriaLabels}
394
404
  fullWidth={args.fullWidth}
405
+ stickyFirstColumn={args.stickyFirstColumn}
406
+ stickyHeaders={args.stickyHeaders}
395
407
  />
396
408
  );
397
409
  },
@@ -282,7 +282,14 @@ describe("Data Table", () => {
282
282
 
283
283
  describe("When loading is false", () => {
284
284
  beforeEach(() => {
285
- rerender(<Table columns={createColumnDefSmall()} data={tableDataSmall} loading={false} />);
285
+ rerender(
286
+ <Table
287
+ columns={createColumnDefSmall()}
288
+ data={tableDataSmall}
289
+ loading={false}
290
+ skeletonRows={5}
291
+ />
292
+ );
286
293
  });
287
294
 
288
295
  it("should show table data", () => {
@@ -304,6 +311,92 @@ describe("Data Table", () => {
304
311
  });
305
312
  });
306
313
 
314
+ describe("Sticky Table Features", () => {
315
+ describe("Default values", () => {
316
+ beforeEach(() => {
317
+ render(<Table columns={createColumnDefSmall()} data={tableDataSmall} />);
318
+
319
+ table = screen.getByRole("table");
320
+ });
321
+
322
+ it("should have sticky header by default", () => {
323
+ const tableHeader = getTableHead(table);
324
+ const headerCells = within(tableHeader).getAllByRole("columnheader");
325
+
326
+ headerCells.forEach((cell) => {
327
+ expect(cell.className).toContain("purpur-table-column-header-cell__sticky-header");
328
+ });
329
+ });
330
+
331
+ it("should have sticky first column by default", () => {
332
+ const tableBody = getTableBody(table);
333
+ const rows = within(tableBody).getAllByRole("row");
334
+
335
+ rows.forEach((row) => {
336
+ const firstCell = within(row).getAllByRole("cell")[0];
337
+ expect(firstCell.className).toContain("purpur-table-row-cell__sticky-column");
338
+ });
339
+ });
340
+ });
341
+
342
+ it("should disable sticky headers when stickyHeaders is false", () => {
343
+ render(
344
+ <Table
345
+ columns={createColumnDefSmall()}
346
+ data={tableDataSmall}
347
+ enableToolbar={true}
348
+ stickyHeaders={false}
349
+ settingsDrawerCopy={copy.settingsDrawer}
350
+ toolbarCopy={{
351
+ buttons: {
352
+ settings: copy.toolbar.buttons.settings,
353
+ },
354
+ ariaLabels: {
355
+ settings: copy.toolbar.ariaLabels.settings,
356
+ },
357
+ }}
358
+ />
359
+ );
360
+
361
+ table = screen.getByRole("table");
362
+ const tableHeader = getTableHead(table);
363
+ const headerCells = within(tableHeader).getAllByRole("columnheader");
364
+
365
+ headerCells.forEach((cell) => {
366
+ expect(cell.className).not.toContain("purpur-table-column-header-cell__sticky-header");
367
+ });
368
+ });
369
+
370
+ it("should disable sticky first column when stickyFirstColumn is false", () => {
371
+ render(
372
+ <Table
373
+ columns={createColumnDefSmall()}
374
+ data={tableDataSmall}
375
+ enableToolbar={true}
376
+ stickyFirstColumn={false}
377
+ settingsDrawerCopy={copy.settingsDrawer}
378
+ toolbarCopy={{
379
+ buttons: {
380
+ settings: copy.toolbar.buttons.settings,
381
+ },
382
+ ariaLabels: {
383
+ settings: copy.toolbar.ariaLabels.settings,
384
+ },
385
+ }}
386
+ />
387
+ );
388
+
389
+ table = screen.getByRole("table");
390
+ const tableBody = getTableBody(table);
391
+ const rows = within(tableBody).getAllByRole("row");
392
+
393
+ rows.forEach((row) => {
394
+ const firstCell = within(row).getAllByRole("cell")[0];
395
+ expect(firstCell).not.toHaveClass("purpur-table__row-cell--sticky");
396
+ });
397
+ });
398
+ });
399
+
307
400
  describe("Accessibility", () => {
308
401
  it("is accessible", async () => {
309
402
  const { container } = render(
package/src/table.tsx CHANGED
@@ -71,6 +71,8 @@ export type TableProps<TData extends RowData> = {
71
71
  data: TData[];
72
72
  paginationComponent?: ReactElement<PaginationProps>;
73
73
  fullWidth?: boolean;
74
+ stickyHeaders?: boolean;
75
+ stickyFirstColumn?: boolean;
74
76
  onRowsCountChange?: (rowsCount: number) => void;
75
77
  } & (WithToolbarProps | WithoutToolbarProps) &
76
78
  (WithSortingProps | WithoutSortingProps) &
@@ -104,6 +106,8 @@ export const Table = <TData extends RowData>({
104
106
  skeletonRows,
105
107
  sortingAriaLabels,
106
108
  state,
109
+ stickyFirstColumn: stickyFirstColumnProp = true,
110
+ stickyHeaders: stickyHeadersProp = true,
107
111
  toolbarCopy,
108
112
  toolbarTotalRowCount,
109
113
  variant = "primary",
@@ -123,8 +127,8 @@ export const Table = <TData extends RowData>({
123
127
  const [showColumnFiltersEnabled, setShowColumnFiltersEnabled] = useState(
124
128
  Boolean(props.enableFilters)
125
129
  );
126
- const [stickyFirstColumn, setStickyFirstColumn] = useState(true);
127
- const [stickyHeaders, setStickyHeaders] = useState(true);
130
+ const [stickyFirstColumn, setStickyFirstColumn] = useState(stickyFirstColumnProp);
131
+ const [stickyHeaders, setStickyHeaders] = useState(stickyHeadersProp);
128
132
  const prevShowOnlySelectedRows = useRef(showOnlySelectedRows);
129
133
  const [isScrolled, setIsScrolled] = useState(false);
130
134
  const tableContainerRef = useRef<HTMLTableElement>(null);