Skip to content

Commit

Permalink
collapsed state
Browse files Browse the repository at this point in the history
  • Loading branch information
sirineJ committed Mar 10, 2025
1 parent cbceaf0 commit dfb06a5
Show file tree
Hide file tree
Showing 6 changed files with 459 additions and 100 deletions.

This file was deleted.

37 changes: 3 additions & 34 deletions packages/circuit-ui/components/ComparisonTable/ComparisonTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@

'use client';

import { forwardRef, useCallback, useEffect, useState } from 'react';
import { Plus } from '@sumup-oss/icons';
import { forwardRef, useState } from 'react';

import { useMedia } from '../../hooks/useMedia/index.js';
import { clsx } from '../../styles/clsx.js';
import { Button } from '../Button/index.js';
import {
AccessibilityError,
isSufficientlyLabelled,
Expand All @@ -31,8 +28,6 @@ import {
PlanTable,
type PlanTableProps,
} from './components/PlanTable/PlanTable.js';
import classes from './ComparisonTable.module.css';


export interface ComparisonTableProps
extends Omit<PlanTableProps, 'activePlans' | 'isCollapsed'> {
Expand All @@ -50,7 +45,6 @@ export const ComparisonTable = forwardRef<
caption,
rows,
cols,
className,
showAllFeaturesLabel,
selectFirstPlanLabel,
selectSecondPlanLabel,
Expand Down Expand Up @@ -84,7 +78,6 @@ export const ComparisonTable = forwardRef<

const [activePlans, setActivePlans] = useState<number[]>([0, 1]);
const isMobile = useMedia('(max-width: 479px)');
const [isCollapsed, setIsCollapsed] = useState(true);

const planOptions = cols.map((col, index) => ({
label: col.label,
Expand All @@ -94,25 +87,8 @@ export const ComparisonTable = forwardRef<
setActivePlans(plans);
};

useEffect(() => {
setIsCollapsed(
rows.reduce(
(totalRows, section) => totalRows + section.features.length + 1,
0,
) > 8, // +1 for the section header
);
}, [rows]);

const showFeatures = useCallback(() => {
setIsCollapsed(false);
}, []);

return (
<div
ref={ref}
{...props}
className={clsx(isCollapsed && classes.collapsed, className)}
>
<div ref={ref} {...props}>
{isMobile && cols.length >= 3 && (
<PlanPicker
plans={planOptions}
Expand All @@ -127,15 +103,8 @@ export const ComparisonTable = forwardRef<
rows={rows}
cols={cols}
activePlans={isMobile ? activePlans : []}
isCollapsed={isCollapsed}
showAllFeaturesLabel={showAllFeaturesLabel}
/>
{isCollapsed && (
<div className={classes.expand}>
<Button onClick={showFeatures} icon={Plus} variant="tertiary">
{showAllFeaturesLabel}
</Button>
</div>
)}
</div>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
}

.wrapper {
position: relative;
width: 100%;
overflow-x: auto;
}

.offers {
Expand All @@ -21,3 +21,21 @@
z-index: 1;
background-color: var(--cui-bg-normal);
}

.expand {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
display: flex;
justify-content: center;
width: 100%;
min-height: 64px;
content: "";
background: linear-gradient(
color-mix(in sRGB, var(--cui-bg-normal) 0%, transparent),
color-mix(in sRGB, var(--cui-bg-normal) 73.5%, transparent),
color-mix(in sRGB, var(--cui-bg-normal) 100%, transparent)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
useRef,
useState,
} from 'react';
import { Plus } from '@sumup-oss/icons';

import { utilClasses } from '../../../../styles/utility.js';
import {
Expand All @@ -31,6 +32,9 @@ import {
} from '../TableHeader/TableHeader.js';
import { TableRow, type TableRowProps } from '../TableRow/TableRow.js';
import { SectionHeader } from '../SectionHeader/SectionHeader.js';
import { stopAtEight } from '../../utils.js';
import { Button } from '../../../Button/index.js';
import { applyMultipleRefs } from '../../../../util/refs.js';

import classes from './PlanTable.module.css';

Expand All @@ -45,16 +49,22 @@ export function generateFromIndex<T>(data: T[], positions: number[]): T[] {

export interface PlanTableProps extends HTMLAttributes<HTMLTableElement> {
caption: string;
showAllFeaturesLabel: string;
rows: FeatureSection[];
cols: TableHeaderProps[];
activePlans: number[];
isCollapsed: boolean;
}

export const PlanTable = forwardRef<HTMLTableElement, PlanTableProps>(
({ caption, cols, rows, activePlans, isCollapsed, ...props }, ref) => {
(
{ caption, showAllFeaturesLabel, cols, rows, activePlans, ...props },
ref,
) => {
const tableRef = useRef<HTMLTableElement>(null);
const [isCollapsed, setIsCollapsed] = useState(true);
const theadRef = useRef<HTMLTableSectionElement>(null);
const [headerHeight, setHeaderHeight] = useState(0);
const rowsToDisplay = isCollapsed ? stopAtEight(rows) : rows;

const updateHeaderHeight = useCallback(() => {
setHeaderHeight(theadRef.current?.getBoundingClientRect().height ?? 0);
Expand All @@ -71,49 +81,71 @@ export const PlanTable = forwardRef<HTMLTableElement, PlanTableProps>(
};
}, [updateHeaderHeight]);

return (
<table
style={{ position: 'relative' }}
className={classes.base}
ref={ref}
{...props}
>
<caption id="caption" className={utilClasses.hideVisually}>
{caption}
</caption>
<thead ref={theadRef}>
<tr className={classes.offers}>
<th id="features" />
{generateFromIndex(cols, activePlans).map((col) => (
<TableHeader key={col.id} {...col} />
))}
</tr>
</thead>
const showFeatures = useCallback(() => {
setIsCollapsed(false);
}, []);

useEffect(() => {
if (!isCollapsed) {
tableRef.current
?.querySelectorAll('tr')[9]
.focus({ preventScroll: true });
}
}, [isCollapsed]);

{rows.map((row) => (
<tbody style={{ position: 'relative' }} key={row.title}>
<tr>
<SectionHeader
scope="rowgroup"
headers="features"
colSpan={cols.length + 1}
style={{
top: `${headerHeight}px`,
}}
>
{row.title}
</SectionHeader>
return (
<div className={classes.wrapper}>
<table
style={{ position: 'relative' }}
className={classes.base}
ref={applyMultipleRefs(ref, tableRef)}
{...props}
>
<caption id="caption" className={utilClasses.hideVisually}>
{caption}
</caption>
<thead ref={theadRef}>
<tr className={classes.offers}>
<th id="features" />
{generateFromIndex(cols, activePlans).map((col) => (
<TableHeader key={col.id} {...col} />
))}
</tr>
{row.features.map((feature) => (
<TableRow
key={feature.featureDescription.title}
{...feature}
values={generateFromIndex(feature.values, activePlans)}
/>
))}
</tbody>
))}
</table>
</thead>

{rowsToDisplay.map((row) => (
<tbody style={{ position: 'relative' }} key={row.title}>
<tr tabIndex={0}>
<SectionHeader
scope="rowgroup"
headers="features"
colSpan={cols.length + 1}
style={{
top: `${headerHeight}px`,
}}
>
{row.title}
</SectionHeader>
</tr>
{row.features.map((feature) => (
<TableRow
key={feature.featureDescription.title}
tabIndex={0}
{...feature}
values={generateFromIndex(feature.values, activePlans)}
/>
))}
</tbody>
))}
</table>
{isCollapsed && (
<div className={classes.expand}>
<Button onClick={showFeatures} icon={Plus} variant="tertiary">
{showAllFeaturesLabel}
</Button>
</div>
)}
</div>
);
},
);
Loading

0 comments on commit dfb06a5

Please sign in to comment.