Skip to content

Commit a881454

Browse files
committed
feat(Collapse): allow custom multiples & disabled
1 parent 2e29ba2 commit a881454

File tree

3 files changed

+79
-19
lines changed

3 files changed

+79
-19
lines changed

src/app/components/collapse/collapse.mdx

+39
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,43 @@ Display large amounts of text in collapsible sections. Commonly referred to as a
8282
`}
8383
/>
8484

85+
<Playground
86+
title="Disabled"
87+
desc="Disabled Collapse component where interactions are blocked."
88+
scope={{ Collapse, Text }}
89+
code={`
90+
<Collapse disabled title="Disabled Question" >
91+
<Text>This content is static and the collapse functionality is disabled. Users cannot expand or collapse this section.</Text>
92+
</Collapse>
93+
`}
94+
/>
95+
96+
<Playground
97+
title="Custom Multiple"
98+
desc="Controlling multiple collapse components with the 'value' prop and tracking their state."
99+
scope={{ Collapse, Collapse, Text }}
100+
code={`
101+
<Collapse.Group multiple={true} value={[1, 4]}
102+
onChange={(open) => console.log("Open collapses:", open)}>
103+
<Collapse title="Question A" index={1}>
104+
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
105+
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
106+
</Collapse>
107+
<Collapse title="Question B" index={2}>
108+
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
109+
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
110+
</Collapse>
111+
<Collapse title="Question C" index={3}>
112+
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
113+
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
114+
</Collapse>
115+
<Collapse title="Question D" index={4}>
116+
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
117+
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
118+
</Collapse>
119+
</Collapse.Group>
120+
`}
121+
/>
122+
123+
85124
<Attributes component="Collapse" edit="/app/components/collapse.mdx"></Attributes>

src/components/collapse/collapse-group.tsx

+31-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use client';
2-
import React, { useMemo } from 'react';
2+
import React, { useEffect, useMemo } from 'react';
33
import Collapse from './collapse';
44
import useCurrentState from '../utils/use-current-state';
55
import { setChildrenIndex } from '../utils/collections';
@@ -8,39 +8,53 @@ import useScale, { withScale } from '../use-scale';
88
import useClasses from '../use-classes';
99

1010
interface Props {
11-
accordion?: boolean;
11+
multiple?: boolean;
1212
className?: string;
13+
value?: number[];
14+
onChange?: (openIndices: number[]) => void;
1315
}
1416

1517
type NativeAttrs = Omit<React.HTMLAttributes<HTMLDivElement>, keyof Props>;
1618
export type CollapseGroupProps = Props & NativeAttrs;
1719

1820
const CollapseGroupComponent: React.FC<React.PropsWithChildren<CollapseGroupProps>> = ({
1921
children,
20-
accordion = true,
21-
className = '',
22+
multiple = true,
23+
className,
24+
value = [],
25+
onChange,
2226
...props
2327
}: React.PropsWithChildren<CollapseGroupProps>) => {
2428
const { SCALE, UNIT, CLASS_NAMES } = useScale();
2529

26-
const [state, setState, stateRef] = useCurrentState<Array<number>>([]);
30+
const [state, setState, stateRef] = useCurrentState<Array<number>>(value);
2731
const classes = useClasses('collapse-group', className, CLASS_NAMES);
2832

29-
const updateValues = (currentIndex: number, nextState: boolean) => {
30-
const hasChild = stateRef.current.find(val => val === currentIndex);
31-
if (accordion) {
32-
if (nextState) return setState([currentIndex]);
33-
return setState([]);
33+
useEffect(() => {
34+
setState(value);
35+
}, [value.join(',')]);
36+
37+
useEffect(() => {
38+
if (onChange) {
39+
onChange(state);
3440
}
41+
}, [state]);
3542

36-
if (nextState) {
37-
// In a few cases, the user will set Collapse Component state manually.
38-
// If the user incorrectly set the state, Group component should ignore it.
39-
/* istanbul ignore if */
40-
if (hasChild) return;
41-
return setState([...stateRef.current, currentIndex]);
43+
const updateValues = (currentIndex: number, nextState: boolean) => {
44+
if (!multiple) {
45+
if (nextState) {
46+
setState([currentIndex]);
47+
} else {
48+
setState([]);
49+
}
50+
} else {
51+
const currentIndexExists = state.includes(currentIndex);
52+
if (nextState && !currentIndexExists) {
53+
setState([...state, currentIndex]);
54+
} else if (!nextState && currentIndexExists) {
55+
setState(state.filter(item => item !== currentIndex));
56+
}
4257
}
43-
setState(stateRef.current.filter(item => item !== currentIndex));
4458
};
4559

4660
const initialValue = useMemo<CollapseConfig>(

src/components/collapse/collapse.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface Props {
1414
shadow?: boolean;
1515
className?: string;
1616
index?: number;
17+
disabled?: boolean;
1718
}
1819

1920
type NativeAttrs = Omit<React.HTMLAttributes<HTMLDivElement>, keyof Props>;
@@ -27,6 +28,7 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
2728
shadow = false,
2829
className = '',
2930
index,
31+
disabled = false,
3032
...props
3133
}: React.PropsWithChildren<CollapseProps>) => {
3234
const { SCALE, UNIT, CLASS_NAMES } = useScale();
@@ -39,6 +41,7 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
3941
shadow,
4042
},
4143
className,
44+
disabled && 'disabled',
4245
CLASS_NAMES,
4346
);
4447

@@ -53,6 +56,7 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
5356
}, [values.join(',')]);
5457

5558
const clickHandler = () => {
59+
if (disabled) return;
5660
const next = !visibleRef.current;
5761
setVisible(next);
5862
updateValues && updateValues(index, next);
@@ -73,6 +77,9 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
7377
.collapse {
7478
border-top: 1px solid var(--color-border-1000);
7579
border-bottom: 1px solid var(--color-border-1000);
80+
&.disabled {
81+
background: var(--color-background-900);
82+
}
7683
}
7784
7885
.shadow {
@@ -123,8 +130,8 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
123130
${SCALE.padding(
124131
{
125132
top: 1.2,
126-
right: 0,
127-
left: 0,
133+
right: 0.5,
134+
left: 0.5,
128135
bottom: 1.2,
129136
},
130137
value => `padding: ${value.top} ${value.right} ${value.bottom} ${value.left};`,

0 commit comments

Comments
 (0)