@popsure/dirty-swan 0.66.11 → 0.66.13

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 (48) hide show
  1. package/dist/cjs/index.js +50 -35
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/lib/components/table/Table.d.ts +3 -1
  4. package/dist/cjs/lib/components/table/Table.stories.d.ts +10 -2
  5. package/dist/cjs/lib/components/table/components/TableCell/TableCell.d.ts +3 -1
  6. package/dist/cjs/lib/components/table/components/TableContents/TableContents.d.ts +2 -1
  7. package/dist/cjs/lib/components/table/components/TableSection/TableSection.d.ts +2 -1
  8. package/dist/cjs/lib/models/styles.d.ts +1 -1
  9. package/dist/esm/{TableSection-CEhD4eoy.js → TableSection-Cm50RX-V.js} +28 -9
  10. package/dist/esm/TableSection-Cm50RX-V.js.map +1 -0
  11. package/dist/esm/components/table/Table.js +10 -10
  12. package/dist/esm/components/table/Table.js.map +1 -1
  13. package/dist/esm/components/table/Table.stories.js +79 -6
  14. package/dist/esm/components/table/Table.stories.js.map +1 -1
  15. package/dist/esm/components/table/Table.test.js +7 -1
  16. package/dist/esm/components/table/Table.test.js.map +1 -1
  17. package/dist/esm/components/table/components/TableCell/BaseCell/BaseCell.js +1 -1
  18. package/dist/esm/components/table/components/TableCell/BaseCell/BaseCell.js.map +1 -1
  19. package/dist/esm/components/table/components/TableCell/TableCell.js +6 -4
  20. package/dist/esm/components/table/components/TableCell/TableCell.js.map +1 -1
  21. package/dist/esm/components/table/components/TableContents/TableContents.js +10 -16
  22. package/dist/esm/components/table/components/TableContents/TableContents.js.map +1 -1
  23. package/dist/esm/components/table/components/TableContents/TableContents.test.js +14 -2
  24. package/dist/esm/components/table/components/TableContents/TableContents.test.js.map +1 -1
  25. package/dist/esm/components/table/components/TableSection/TableSection.js +1 -1
  26. package/dist/esm/components/table/components/TableSection/TableSection.test.js +1 -1
  27. package/dist/esm/index.js +1 -1
  28. package/dist/esm/lib/components/table/Table.d.ts +3 -1
  29. package/dist/esm/lib/components/table/Table.stories.d.ts +10 -2
  30. package/dist/esm/lib/components/table/components/TableCell/TableCell.d.ts +3 -1
  31. package/dist/esm/lib/components/table/components/TableContents/TableContents.d.ts +2 -1
  32. package/dist/esm/lib/components/table/components/TableSection/TableSection.d.ts +2 -1
  33. package/dist/esm/lib/models/styles.d.ts +1 -1
  34. package/package.json +1 -1
  35. package/src/lib/components/table/Table.module.scss +3 -0
  36. package/src/lib/components/table/Table.stories.tsx +92 -1
  37. package/src/lib/components/table/Table.test.tsx +15 -0
  38. package/src/lib/components/table/Table.tsx +27 -20
  39. package/src/lib/components/table/components/TableCell/BaseCell/BaseCell.tsx +1 -1
  40. package/src/lib/components/table/components/TableCell/TableCell.module.scss +9 -3
  41. package/src/lib/components/table/components/TableCell/TableCell.tsx +7 -1
  42. package/src/lib/components/table/components/TableContents/TableContents.module.scss +23 -24
  43. package/src/lib/components/table/components/TableContents/TableContents.test.tsx +22 -1
  44. package/src/lib/components/table/components/TableContents/TableContents.tsx +42 -33
  45. package/src/lib/components/table/components/TableSection/TableSection.module.scss +7 -0
  46. package/src/lib/components/table/components/TableSection/TableSection.tsx +32 -3
  47. package/src/lib/models/styles.ts +1 -0
  48. package/dist/esm/TableSection-CEhD4eoy.js.map +0 -1
@@ -2,7 +2,7 @@ import { TableProps } from './Table';
2
2
  import { TableData } from './types';
3
3
  declare const story: {
4
4
  title: string;
5
- component: ({ cellReplacements, className, collapsibleSections, hideColumns, hideDetails, hideRows, imageComponent, modalContentRenderer, onModalOpen, onSelectionChanged, scrollOnOpen, scrollTopOffset, stickyHeaderTopOffset, tableData, textOverrides: definedTextOverrides, title, activeSection: externalActiveSection, hideTableNavigation, }: TableProps) => JSX.Element;
5
+ component: ({ cellReplacements, className, collapsibleSections, hideColumns, hideDetails, hideRows, imageComponent, modalContentRenderer, onModalOpen, onSelectionChanged, scrollOnOpen, scrollTopOffset, stickyHeaderTopOffset, tableData, textOverrides: definedTextOverrides, title, activeSection: externalActiveSection, hideTableNavigation, hideStickyHeader, showSelectedColumn, }: TableProps) => JSX.Element;
6
6
  argTypes: {
7
7
  tableData: {
8
8
  subContent: string;
@@ -22,6 +22,9 @@ declare const story: {
22
22
  hideDetails: {
23
23
  subContent: string;
24
24
  };
25
+ hideStickyHeader: {
26
+ subContent: string;
27
+ };
25
28
  stickyHeaderTopOffset: {
26
29
  subContent: string;
27
30
  };
@@ -69,10 +72,15 @@ declare const story: {
69
72
  hideColumns: never[];
70
73
  hideRows: never[];
71
74
  hideTableNavigation: boolean;
75
+ showSelectedColumn: boolean;
72
76
  };
73
77
  };
74
78
  export declare const TableStory: {
75
- render: ({ collapsibleSections, scrollOnOpen, scrollTopOffset, tableData, hideColumns, hideDetails, hideRows, stickyHeaderTopOffset, textOverrides, title, activeSection, hideTableNavigation, }: TableProps) => JSX.Element;
79
+ render: ({ collapsibleSections, scrollOnOpen, scrollTopOffset, tableData, hideColumns, hideDetails, hideRows, stickyHeaderTopOffset, textOverrides, title, activeSection, hideTableNavigation, showSelectedColumn, }: TableProps) => JSX.Element;
80
+ name: string;
81
+ };
82
+ export declare const SinglePlanQuoteTable: {
83
+ render: () => JSX.Element;
76
84
  name: string;
77
85
  };
78
86
  export declare const TableDataType: () => JSX.Element;
@@ -5,9 +5,11 @@ type ExtraTableCellProps = {
5
5
  isFirstCellInRow?: boolean;
6
6
  isTopLeftCell?: boolean;
7
7
  isNavigation?: boolean;
8
+ isSelectedColumn?: boolean;
9
+ selectedColumnPosition?: 'top' | 'bottom' | 'middle';
8
10
  imageComponent?: (args: any) => JSX.Element;
9
11
  isBelowDesktop?: boolean;
10
12
  };
11
13
  export type TableCellProps = TableCellData & ExtraTableCellProps;
12
- declare const TableCell: React.MemoExoticComponent<({ isFirstCellInRow, isHeader, isNavigation, isTopLeftCell, colSpan, isBelowDesktop, ...cellProps }: TableCellProps) => JSX.Element>;
14
+ declare const TableCell: React.MemoExoticComponent<({ isFirstCellInRow, isHeader, isNavigation, isSelectedColumn, selectedColumnPosition, isTopLeftCell, colSpan, isBelowDesktop, ...cellProps }: TableCellProps) => JSX.Element>;
13
15
  export { TableCell };
@@ -16,6 +16,7 @@ export interface TableContentsProps {
16
16
  title: string;
17
17
  cellReplacements?: CellReplacements;
18
18
  imageComponent?: (args: any) => JSX.Element;
19
+ selectedColumn?: number;
19
20
  }
20
- declare const TableContents: ({ className, collapsibleSections, scrollOnOpen, scrollTopOffset, stickyHeaderRef, tableData, hideColumns, hideDetails, hideRows, isMobile, openModal, shouldHideDetails, title, cellReplacements, imageComponent, }: TableContentsProps) => JSX.Element;
21
+ declare const TableContents: ({ className, collapsibleSections, scrollOnOpen, scrollTopOffset, stickyHeaderRef, tableData, hideColumns, hideDetails, hideRows, isMobile, openModal, shouldHideDetails, title, cellReplacements, imageComponent, selectedColumn, }: TableContentsProps) => JSX.Element;
21
22
  export { TableContents };
@@ -10,6 +10,7 @@ export interface TableSectionProps {
10
10
  width?: number | string;
11
11
  cellReplacements?: CellReplacements;
12
12
  imageComponent?: (args: any) => JSX.Element;
13
+ selectedColumn?: number;
13
14
  }
14
- declare const TableSection: ({ className, tableCellRows, hideColumns, hideRows, hideHeader, openModal, title, width, cellReplacements, imageComponent, }: TableSectionProps) => JSX.Element;
15
+ declare const TableSection: ({ className, tableCellRows, hideColumns, hideRows, hideHeader, openModal, title, width, cellReplacements, imageComponent, selectedColumn, }: TableSectionProps) => JSX.Element;
15
16
  export { TableSection };
@@ -1,2 +1,2 @@
1
- export type Color = 'transparent' | 'blue-100' | 'blue-300' | 'blue-500' | 'blue-700' | 'blue-900' | 'purple-50' | 'purple-100' | 'purple-200' | 'purple-300' | 'purple-400' | 'purple-500' | 'purple-600' | 'purple-700' | 'purple-800' | 'purple-900' | 'red-100' | 'red-300' | 'red-500' | 'red-700' | 'red-900' | 'neutral-50' | 'neutral-100' | 'neutral-300' | 'neutral-400' | 'neutral-600' | 'neutral-700' | 'neutral-800' | 'neutral-900' | 'green-100' | 'green-300' | 'green-500' | 'green-700' | 'green-900' | 'yellow-100' | 'yellow-300' | 'yellow-500' | 'yellow-700' | 'yellow-900';
1
+ export type Color = 'transparent' | 'blue-100' | 'blue-300' | 'blue-500' | 'blue-700' | 'blue-900' | 'purple-50' | 'purple-100' | 'purple-200' | 'purple-300' | 'purple-400' | 'purple-500' | 'purple-600' | 'purple-700' | 'purple-800' | 'purple-900' | 'red-100' | 'red-300' | 'red-500' | 'red-700' | 'red-900' | 'neutral-50' | 'neutral-100' | 'neutral-300' | 'neutral-400' | 'neutral-500' | 'neutral-600' | 'neutral-700' | 'neutral-800' | 'neutral-900' | 'green-100' | 'green-300' | 'green-500' | 'green-700' | 'green-900' | 'yellow-100' | 'yellow-300' | 'yellow-500' | 'yellow-700' | 'yellow-900';
2
2
  export type Size = 0 | 4 | 8 | 12 | 14 | 16 | 20 | 24 | 28 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popsure/dirty-swan",
3
- "version": "0.66.11",
3
+ "version": "0.66.13",
4
4
  "author": "Vincent Audoire <vincent@getpopsure.com>",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -4,6 +4,9 @@
4
4
 
5
5
  .wrapper {
6
6
  position: relative;
7
+ border: 1px solid $ds-neutral-200;
8
+ border-radius: 12px;
9
+ padding: 24px 24px 0;
7
10
  }
8
11
 
9
12
  .container {
@@ -118,7 +118,6 @@ const initialData: TableData = [
118
118
  },
119
119
  {
120
120
  section: {
121
- icon: <DentalPlusIcon size={20} noMargin />,
122
121
  title: 'Dental',
123
122
  },
124
123
  rows: [
@@ -256,6 +255,10 @@ const story = {
256
255
  hideDetails: {
257
256
  subContent: 'This property allows to hide the details of the table.',
258
257
  },
258
+ hideStickyHeader: {
259
+ subContent:
260
+ 'This property allows to hide the sticky header row on desktop, e.g. for single plan tables without a plan selector.',
261
+ },
259
262
  stickyHeaderTopOffset: {
260
263
  subContent:
261
264
  'This property allows to set the offset of the sticky header.',
@@ -308,6 +311,7 @@ const story = {
308
311
  hideColumns: [],
309
312
  hideRows: [],
310
313
  hideTableNavigation: true,
314
+ showSelectedColumn: false,
311
315
  },
312
316
  };
313
317
 
@@ -325,6 +329,7 @@ export const TableStory = {
325
329
  title,
326
330
  activeSection,
327
331
  hideTableNavigation,
332
+ showSelectedColumn,
328
333
  }: TableProps) => {
329
334
  const [price, setPrice] = useState(999);
330
335
  return (
@@ -368,6 +373,7 @@ export const TableStory = {
368
373
  title={title}
369
374
  activeSection={activeSection}
370
375
  hideTableNavigation={hideTableNavigation}
376
+ showSelectedColumn={showSelectedColumn}
371
377
  />
372
378
  </div>
373
379
  );
@@ -376,6 +382,91 @@ export const TableStory = {
376
382
  name: 'Table',
377
383
  };
378
384
 
385
+ const singlePlanData: TableData = [
386
+ {
387
+ rows: [
388
+ [{ text: '' }, { text: '' }],
389
+ [
390
+ { text: 'Price' },
391
+ {
392
+ text: '€9.99',
393
+ description: 'With monthly cancellation',
394
+ fontVariant: 'PRICE',
395
+ },
396
+ ],
397
+ [
398
+ {
399
+ text: 'Regular vet visits & medication',
400
+ modalContent: 'Some stories about vets',
401
+ },
402
+ { text: 'Up to €1 million' },
403
+ ],
404
+ [
405
+ {
406
+ text: 'Specialist visits',
407
+ modalContent: 'Some stories about specialists',
408
+ },
409
+ { text: '4 visits per year' },
410
+ ],
411
+ [{ text: 'Medication' }, { text: '80% covered' }],
412
+ [{ text: 'Grooming' }, { checkmarkValue: false }],
413
+ [{ text: 'Boarding fees' }, { checkmarkValue: false }],
414
+ [
415
+ {
416
+ text: 'Alternative treatments',
417
+ description: 'E.g. physiotherapy, hydrotherapy',
418
+ },
419
+ { checkmarkValue: false },
420
+ ],
421
+ ],
422
+ },
423
+ {
424
+ section: {
425
+ title: 'Dental',
426
+ },
427
+ rows: [
428
+ [{ text: 'Dental cleanings' }, { text: 'Up to €500' }],
429
+ [{ text: 'Dental treatments' }, { text: 'Up to €500' }],
430
+ [{ text: 'Operations' }, { checkmarkValue: true }],
431
+ ],
432
+ },
433
+ {
434
+ section: {
435
+ title: 'Travel',
436
+ },
437
+ rows: [
438
+ [{ text: 'Trips abroad' }, { checkmarkValue: true }],
439
+ [{ text: 'Emergency care abroad' }, { checkmarkValue: true }],
440
+ ],
441
+ },
442
+ {
443
+ section: {
444
+ title: 'Add-ons',
445
+ },
446
+ rows: [
447
+ [{ text: 'Extended coverage' }, { checkmarkValue: true }],
448
+ [{ text: 'Equipment protection' }, { checkmarkValue: true }],
449
+ ],
450
+ },
451
+ ];
452
+
453
+ export const SinglePlanQuoteTable = {
454
+ render: () => (
455
+ <div style={{ maxWidth: 756 }}>
456
+ <Table
457
+ tableData={singlePlanData}
458
+ title="Single plan quote"
459
+ collapsibleSections
460
+ hideTableNavigation
461
+ hideStickyHeader
462
+ showSelectedColumn
463
+ />
464
+ </div>
465
+ ),
466
+
467
+ name: 'Single Plan Quote',
468
+ };
469
+
379
470
  export const TableDataType = () => {
380
471
  return (
381
472
  <pre>
@@ -75,6 +75,21 @@ describe('Table', () => {
75
75
  expect(screen.getByText('Hide details')).toBeVisible();
76
76
  });
77
77
 
78
+ it('does not render the sticky header row when hideStickyHeader is true', () => {
79
+ const { rerender } = render(
80
+ <Table tableData={tableData} title="Test Table" />
81
+ );
82
+ const countWithStickyHeader = screen.getAllByText('Item 1').length;
83
+
84
+ rerender(
85
+ <Table tableData={tableData} hideStickyHeader title="Test Table" />
86
+ );
87
+
88
+ expect(screen.getAllByText('Item 1')).toHaveLength(
89
+ countWithStickyHeader - 1
90
+ );
91
+ });
92
+
78
93
  it('shows a modal when clicking on info icon', async () => {
79
94
  const { user } = render(<Table tableData={tableData} title="Test Table" />);
80
95
 
@@ -47,6 +47,8 @@ export interface TableProps {
47
47
  title: string;
48
48
  activeSection?: number;
49
49
  hideTableNavigation?: boolean;
50
+ hideStickyHeader?: boolean;
51
+ showSelectedColumn?: boolean;
50
52
  }
51
53
 
52
54
  const defaultTextOverrides = {
@@ -73,6 +75,8 @@ const Table = ({
73
75
  title,
74
76
  activeSection: externalActiveSection,
75
77
  hideTableNavigation = false,
78
+ hideStickyHeader = false,
79
+ showSelectedColumn = false,
76
80
  }: TableProps) => {
77
81
  const textOverrides = { ...defaultTextOverrides, ...definedTextOverrides };
78
82
  const isMobile = useMediaQuery('BELOW_MOBILE');
@@ -99,7 +103,7 @@ const Table = ({
99
103
  };
100
104
  const currentActiveSection = tableData?.[0]?.rows?.[0]?.[activeSection];
101
105
  const currentActiveSectionReplacements =
102
- (currentActiveSection.cellId &&
106
+ (currentActiveSection?.cellId &&
103
107
  cellReplacements?.[currentActiveSection.cellId]) ||
104
108
  {};
105
109
 
@@ -133,7 +137,7 @@ const Table = ({
133
137
  />
134
138
  )}
135
139
 
136
- {!hideTableNavigation && (
140
+ {!hideTableNavigation && currentActiveSection && (
137
141
  <TableControls
138
142
  activeSection={activeSection}
139
143
  columnsLength={columnsLength}
@@ -158,25 +162,27 @@ const Table = ({
158
162
  )}
159
163
  </>
160
164
  ) : (
161
- <div
162
- ref={stickyHeaderRef}
163
- aria-hidden
164
- className={styles.stickyHeader}
165
- style={{ top: `${stickyHeaderTopOffset}px` }}
166
- >
167
- <div className={styles.container} ref={headerRef}>
168
- <TableSection
169
- cellReplacements={cellReplacements}
170
- className={className}
171
- hideColumns={hideColumns}
172
- hideRows={hideRows}
173
- openModal={handleOpenModal}
174
- tableCellRows={[tableData?.[0]?.rows?.[0]]}
175
- title={title}
176
- imageComponent={imageComponent}
177
- />
165
+ !hideStickyHeader && (
166
+ <div
167
+ ref={stickyHeaderRef}
168
+ aria-hidden
169
+ className={styles.stickyHeader}
170
+ style={{ top: `${stickyHeaderTopOffset}px` }}
171
+ >
172
+ <div className={styles.container} ref={headerRef}>
173
+ <TableSection
174
+ cellReplacements={cellReplacements}
175
+ className={className}
176
+ hideColumns={hideColumns}
177
+ hideRows={hideRows}
178
+ openModal={handleOpenModal}
179
+ tableCellRows={[tableData?.[0]?.rows?.[0]]}
180
+ title={title}
181
+ imageComponent={imageComponent}
182
+ />
183
+ </div>
178
184
  </div>
179
- </div>
185
+ )
180
186
  )}
181
187
 
182
188
  <div ref={containerRef} className={classNames(styles.container, 'pb8')}>
@@ -196,6 +202,7 @@ const Table = ({
196
202
  openModal={handleOpenModal}
197
203
  cellReplacements={cellReplacements}
198
204
  imageComponent={imageComponent}
205
+ selectedColumn={showSelectedColumn ? activeSection : undefined}
199
206
  />
200
207
  </div>
201
208
 
@@ -121,7 +121,7 @@ export const BaseCell = ({
121
121
  data-testid="table-cell-boolean-no"
122
122
  size={24}
123
123
  aria-hidden
124
- color="neutral-400"
124
+ color="neutral-500"
125
125
  />
126
126
  )}
127
127
  </span>
@@ -5,6 +5,7 @@
5
5
  vertical-align: middle;
6
6
  scroll-snap-align: end;
7
7
  width: 50%;
8
+ padding: 28px 24px;
8
9
 
9
10
  @include p-size-tablet {
10
11
  width: auto;
@@ -26,6 +27,7 @@
26
27
  position: sticky;
27
28
  left: 0;
28
29
  z-index: 2;
30
+ padding-left: 0;
29
31
 
30
32
  &:after {
31
33
  content: '';
@@ -36,10 +38,14 @@
36
38
  width: 1px;
37
39
  background-color: $ds-neutral-100;
38
40
  }
41
+ }
39
42
 
40
- @include p-size-tablet {
41
- padding-left: 16px;
42
- }
43
+ .selectedColumnTop {
44
+ border-radius: 16px 16px 0 0;
45
+ }
46
+
47
+ .selectedColumnBottom {
48
+ border-radius: 0 0 16px 16px;
43
49
  }
44
50
 
45
51
  .fixedCard {
@@ -13,6 +13,8 @@ type ExtraTableCellProps = {
13
13
  isFirstCellInRow?: boolean;
14
14
  isTopLeftCell?: boolean;
15
15
  isNavigation?: boolean;
16
+ isSelectedColumn?: boolean;
17
+ selectedColumnPosition?: 'top' | 'bottom' | 'middle';
16
18
  imageComponent?: (args: any) => JSX.Element;
17
19
  isBelowDesktop?: boolean;
18
20
  };
@@ -24,6 +26,8 @@ const TableCell = React.memo(
24
26
  isFirstCellInRow = false,
25
27
  isHeader = false,
26
28
  isNavigation = false,
29
+ isSelectedColumn = false,
30
+ selectedColumnPosition,
27
31
  isTopLeftCell = false,
28
32
  colSpan = 0,
29
33
  isBelowDesktop,
@@ -46,11 +50,13 @@ const TableCell = React.memo(
46
50
  return (
47
51
  <Tag
48
52
  {...scope}
49
- className={classNames('bg-white py24 px8', styles.th, {
53
+ className={classNames(isSelectedColumn ? 'bg-orange-50' : 'bg-white', styles.th, {
50
54
  'ta-left': isFirstCellInRow,
51
55
  [styles.thNavigation]: isNavigation,
52
56
  [styles.fixedCell]: isFirstCellInRow && colSpan < 1 ,
53
57
  [styles.fixedCard]: cellProps.type === 'CARD',
58
+ [styles.selectedColumnTop]: selectedColumnPosition === 'top',
59
+ [styles.selectedColumnBottom]: selectedColumnPosition === 'bottom',
54
60
  })}
55
61
  colSpan={isBelowDesktop && cellProps.type === 'CARD' ? 2 : colSpan}
56
62
  >
@@ -1,34 +1,33 @@
1
1
  @use "../../../../scss/public/colors" as *;
2
2
 
3
- .cardWrapper {
4
- height: 88px;
3
+ .sectionButtonWrapper {
4
+ height: 74px;
5
5
  }
6
6
 
7
- .cardButton {
8
- div {
9
- background-color: $ds-orange-50;
10
- }
7
+ .sectionButton {
8
+ position: absolute;
9
+ left: 24px;
10
+ right: 24px;
11
+ z-index: 3;
12
+ height: 74px;
13
+ border: none;
14
+ border-bottom: 1px solid $ds-neutral-300;
15
+ color: $ds-neutral-900;
16
+ padding: 0;
17
+ }
11
18
 
12
- &:hover div {
13
- border-color: transparent!important;
14
- outline-color: transparent!important;
15
- box-shadow: none!important;
16
- background-color: $ds-orange-100!important;
17
- }
19
+ button.sectionButton {
20
+ cursor: pointer;
18
21
 
19
- &:focus-visible div {
20
- background-color: $ds-orange-100!important;
22
+ &:hover {
23
+ color: $ds-neutral-700;
24
+
25
+ :global(.p-h3) {
26
+ color: $ds-neutral-700;
27
+ }
21
28
  }
22
29
  }
23
30
 
24
- .card {
25
- position: absolute;
26
- left: 0;
27
- right: 0;
28
- z-index: 3;
31
+ div:last-child > .sectionButtonWrapper > .sectionButton {
32
+ border-bottom: none;
29
33
  }
30
-
31
- .cardIcon {
32
- width: 20px;
33
- margin-right: 8px;
34
- }
@@ -1,4 +1,4 @@
1
- import { render, screen } from '../../../../util/testUtils';
1
+ import { fireEvent, render, screen } from '../../../../util/testUtils';
2
2
  import { TableContents, TableContentsProps } from './TableContents';
3
3
 
4
4
  const mockData: TableContentsProps['tableData'] = [
@@ -39,6 +39,27 @@ describe('TableContents', () => {
39
39
  expect(screen.getByText('Item 2.2.1')).toBeInTheDocument();
40
40
  });
41
41
 
42
+ it('renders collapsible section headers as buttons and toggles them', () => {
43
+ render(
44
+ <TableContents collapsibleSections tableData={mockData} title="Table" />
45
+ );
46
+
47
+ const sectionButton = screen.getByRole('button', { name: 'Section 2' });
48
+ expect(sectionButton).toHaveAttribute('aria-expanded', 'false');
49
+
50
+ fireEvent.click(sectionButton);
51
+ expect(sectionButton).toHaveAttribute('aria-expanded', 'true');
52
+ });
53
+
54
+ it('renders section headers without a button when not collapsible', () => {
55
+ render(<TableContents tableData={mockData} title="Table" />);
56
+
57
+ expect(
58
+ screen.queryByRole('button', { name: 'Section 2' })
59
+ ).not.toBeInTheDocument();
60
+ expect(screen.getByText('Section 2')).toBeInTheDocument();
61
+ });
62
+
42
63
  it('hides the table sections when hideDetails and shouldHideDetails is true', () => {
43
64
  render(
44
65
  <TableContents
@@ -1,7 +1,6 @@
1
1
  import { MutableRefObject, useCallback, useRef, useState } from 'react';
2
2
  import { TableSection } from '../TableSection/TableSection';
3
3
  import { ChevronDownIcon, ChevronUpIcon } from '../../../icon';
4
- import { Card } from '../../../cards/card';
5
4
 
6
5
  import styles from './TableContents.module.scss';
7
6
  import classNames from 'classnames';
@@ -25,6 +24,7 @@ export interface TableContentsProps {
25
24
  title: string;
26
25
  cellReplacements?: CellReplacements;
27
26
  imageComponent?: (args: any) => JSX.Element;
27
+ selectedColumn?: number;
28
28
  }
29
29
 
30
30
  const TableContents = ({
@@ -43,6 +43,7 @@ const TableContents = ({
43
43
  title,
44
44
  cellReplacements,
45
45
  imageComponent,
46
+ selectedColumn,
46
47
  }: TableContentsProps) => {
47
48
  const [isSectionOpen, setOpenSection] = useState<number | null>(null);
48
49
  const lastToggledSection = useRef<number | null>(null);
@@ -84,9 +85,9 @@ const TableContents = ({
84
85
  : isSectionOpen === index || isFirstSection;
85
86
  const isVisible = hideDetails ? !shouldHideDetails : true;
86
87
 
87
- const renderedIcon = (
88
+ const renderedIcon = section.icon ? (
88
89
  <IconRenderer icon={section.icon} imageComponent={imageComponent} width={20} />
89
- );
90
+ ) : null;
90
91
 
91
92
  // Calculate section-specific hideRows based on global offset
92
93
  const sectionHideRows = hideRows
@@ -96,35 +97,40 @@ const TableContents = ({
96
97
  const result = (isFirstSection || isVisible) && (
97
98
  <div key={index} ref={(el) => { sectionRefs.current[index] = el; }}>
98
99
  {section?.title && (
99
- <div className={styles.cardWrapper}>
100
- <div className={classNames(styles.card, 'p0')}>
101
- <Card
102
- actionIcon={
103
- isExpanded ? (
104
- <ChevronUpIcon size={24} />
105
- ) : (
106
- <ChevronDownIcon size={24} />
107
- )
108
- }
109
- aria-expanded={isExpanded ? 'true' : 'false'}
110
- aria-hidden
111
- classNames={{
112
- wrapper: 'pl16',
113
- buttonWrapper: styles.cardButton,
114
- icon: classNames(styles.cardIcon, 'tc-neutral-900'),
115
- }}
116
- dropShadow={false}
117
- icon={renderedIcon}
118
- title={section.title}
119
- titleVariant="medium"
120
- variant="primary"
121
- {...(collapsibleSections
122
- ? {
123
- onClick: () => handleToggleSection(index),
124
- }
125
- : {})}
126
- />
127
- </div>
100
+ <div className={styles.sectionButtonWrapper}>
101
+ {collapsibleSections ? (
102
+ <button
103
+ type="button"
104
+ aria-expanded={isExpanded}
105
+ className={classNames(
106
+ 'd-flex ai-center jc-between ta-left bg-white',
107
+ styles.sectionButton
108
+ )}
109
+ onClick={() => handleToggleSection(index)}
110
+ >
111
+ <span className="d-flex ai-center gap8">
112
+ {renderedIcon}
113
+ <span className="p-h3">{section.title}</span>
114
+ </span>
115
+ {isExpanded ? (
116
+ <ChevronUpIcon size={20} />
117
+ ) : (
118
+ <ChevronDownIcon size={20} />
119
+ )}
120
+ </button>
121
+ ) : (
122
+ <div
123
+ className={classNames(
124
+ 'd-flex ai-center jc-between ta-left bg-white',
125
+ styles.sectionButton
126
+ )}
127
+ >
128
+ <span className="d-flex ai-center gap8">
129
+ {renderedIcon}
130
+ <span className="p-h3">{section.title}</span>
131
+ </span>
132
+ </div>
133
+ )}
128
134
  </div>
129
135
  )}
130
136
 
@@ -133,7 +139,9 @@ const TableContents = ({
133
139
  onTransitionEnd={() => handleScrollToSection(index)}
134
140
  >
135
141
  <TableSection
136
- className={classNames(className, 'mb24')}
142
+ className={classNames(className, 'mb16', {
143
+ mt16: !!section?.title,
144
+ })}
137
145
  tableCellRows={
138
146
  isFirstSection ? rows : [firstHeadRow, ...rows]
139
147
  }
@@ -147,6 +155,7 @@ const TableContents = ({
147
155
  width={tableWidth}
148
156
  cellReplacements={cellReplacements}
149
157
  imageComponent={imageComponent}
158
+ selectedColumn={selectedColumn}
150
159
  />
151
160
  </Collapsible>
152
161
  </div>
@@ -4,7 +4,9 @@
4
4
  .table {
5
5
  border-collapse: collapse;
6
6
  table-layout: fixed;
7
+ }
7
8
 
9
+ .tableMultiplePlans {
8
10
  @include p-size-tablet {
9
11
  min-width: 845px;
10
12
  }
@@ -12,4 +14,9 @@
12
14
 
13
15
  .tr {
14
16
  min-height: 72px;
17
+ border-bottom: 1px solid $ds-neutral-300;
18
+
19
+ &:last-child {
20
+ border-bottom: none;
21
+ }
15
22
  }