Skip to content

Commit d82b65c

Browse files
committed
fix(Collapse): hide disabled
1 parent 2d742a0 commit d82b65c

File tree

5 files changed

+58
-43
lines changed

5 files changed

+58
-43
lines changed

src/app/components/collapse/collapse.mdx

+5-6
Original file line numberDiff line numberDiff line change
@@ -98,27 +98,26 @@ Display large amounts of text in collapsible sections. Commonly referred to as a
9898
desc="Controlling multiple collapse components with the 'value' prop and tracking their state."
9999
scope={{ Collapse, Collapse, Text }}
100100
code={`
101-
<Collapse.Group multiple={true} value={[1, 4]}
101+
<Collapse.Group multiple={true} value={[0, 3]}
102102
onChange={(open) => console.log("Open collapses:", open)}>
103-
<Collapse title="Question A" index={1}>
103+
<Collapse title="Question A" index={0}>
104104
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
105105
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
106106
</Collapse>
107-
<Collapse title="Question B" index={2}>
107+
<Collapse title="Question B" index={1}>
108108
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
109109
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
110110
</Collapse>
111-
<Collapse title="Question C" index={3}>
111+
<Collapse title="Question C" index={2}>
112112
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
113113
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
114114
</Collapse>
115-
<Collapse title="Question D" index={4}>
115+
<Collapse title="Question D" index={3}>
116116
<Text>Lorem ipsum dolor sit amet, consectetur adipiscing elit,
117117
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam</Text>
118118
</Collapse>
119119
</Collapse.Group>
120120
`}
121121
/>
122122

123-
124123
<Attributes component="Collapse" edit="/app/components/collapse.mdx"></Attributes>

src/components/collapse/collapse-context.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import React from 'react';
44

55
export interface CollapseConfig {
6-
values: Array<number>;
7-
updateValues?: (currentIndex: number | undefined, nextState: boolean) => unknown;
6+
values: Array<number | string>;
7+
updateValues?: (currentIndex: number | string | undefined, nextState: boolean) => unknown;
88
}
99

1010
const defaultContext = {

src/components/collapse/collapse-group.tsx

+35-25
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
'use client';
2-
import React, { useEffect, useMemo } from 'react';
2+
import React, { useCallback, useEffect, useMemo } from 'react';
33
import Collapse from './collapse';
44
import useCurrentState from '../utils/use-current-state';
55
import { setChildrenIndex } from '../utils/collections';
66
import { CollapseContext, CollapseConfig } from './collapse-context';
77
import useScale, { withScale } from '../use-scale';
88
import useClasses from '../use-classes';
9+
import { isArray } from 'lodash';
910

1011
interface Props {
1112
multiple?: boolean;
1213
className?: string;
13-
value?: number[];
14-
onChange?: (openIndices: number[]) => void;
14+
value?: Array<number | string>;
15+
onChange?: (openIndices: Array<number | string>) => void;
1516
}
1617

1718
type NativeAttrs = Omit<React.HTMLAttributes<HTMLDivElement>, keyof Props>;
@@ -27,8 +28,9 @@ const CollapseGroupComponent: React.FC<React.PropsWithChildren<CollapseGroupProp
2728
}: React.PropsWithChildren<CollapseGroupProps>) => {
2829
const { SCALE, UNIT, CLASS_NAMES } = useScale();
2930

30-
const [state, setState, stateRef] = useCurrentState<Array<number>>(value);
31+
const [state, setState, stateRef] = useCurrentState<Array<number | string>>(value);
3132
const classes = useClasses('collapse-group', className, CLASS_NAMES);
33+
const hasIndexChildren = useMemo(() => setChildrenIndex(children, [Collapse]), [children]);
3234

3335
useEffect(() => {
3436
setState(value);
@@ -37,32 +39,41 @@ const CollapseGroupComponent: React.FC<React.PropsWithChildren<CollapseGroupProp
3739
useEffect(() => {
3840
if (onChange) {
3941
const openIndices = stateRef.current.filter(index => {
40-
if (!Array.isArray(hasIndexChildren)) {
41-
return true;
42-
}
43-
const isDisabled = hasIndexChildren.find((child: React.ReactElement) => child.props.index === index)?.props.disabled;
44-
return !isDisabled;
42+
if (!Array.isArray(hasIndexChildren)) return true;
43+
const child = hasIndexChildren.find((child: React.ReactElement) => child.props.index === index);
44+
return child && !child.props.disabled;
4545
});
4646
onChange(openIndices);
4747
}
48-
}, [state]);
48+
}, [state, hasIndexChildren]);
4949

50-
const updateValues = (currentIndex: number, nextState: boolean) => {
51-
if (!multiple) {
52-
if (nextState) {
53-
setState([currentIndex]);
50+
const updateValues = useCallback(
51+
(currentIndex: number | string, nextState: boolean) => {
52+
if (!multiple) {
53+
if (nextState) {
54+
const isDisabled =
55+
isArray(hasIndexChildren) && hasIndexChildren.find((child: React.ReactElement) => child.props.index === currentIndex)?.props.disabled;
56+
if (!isDisabled) {
57+
setState([currentIndex]);
58+
} else {
59+
setState([]);
60+
}
61+
} else {
62+
setState([]);
63+
}
5464
} else {
55-
setState([]);
56-
}
57-
} else {
58-
const currentIndexExists = stateRef.current.includes(currentIndex);
59-
if (nextState && !currentIndexExists) {
60-
setState([...stateRef.current, currentIndex]);
61-
} else if (!nextState && currentIndexExists) {
62-
setState(stateRef.current.filter(item => item !== currentIndex));
65+
const currentIndexExists = stateRef.current.includes(currentIndex);
66+
const isDisabled =
67+
isArray(hasIndexChildren) && hasIndexChildren.find((child: React.ReactElement) => child.props.index === currentIndex)?.props.disabled;
68+
if (nextState && !currentIndexExists && !isDisabled) {
69+
setState([...stateRef.current, currentIndex]);
70+
} else if (!nextState && currentIndexExists) {
71+
setState(stateRef.current.filter(item => item !== currentIndex));
72+
}
6373
}
64-
}
65-
};
74+
},
75+
[hasIndexChildren, multiple],
76+
);
6677

6778
const initialValue = useMemo<CollapseConfig>(
6879
() => ({
@@ -71,7 +82,6 @@ const CollapseGroupComponent: React.FC<React.PropsWithChildren<CollapseGroupProp
7182
}),
7283
[state.join(',')],
7384
);
74-
const hasIndexChildren = useMemo(() => setChildrenIndex(children, [Collapse]), [children]);
7585

7686
return (
7787
<CollapseContext.Provider value={initialValue}>

src/components/collapse/collapse.tsx

+11-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ interface Props {
1313
initialVisible?: boolean;
1414
shadow?: boolean;
1515
className?: string;
16-
index?: number;
16+
index?: number | string;
1717
disabled?: boolean;
1818
}
1919

@@ -49,11 +49,17 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
4949
useWarning('"title" is required.', 'Collapse');
5050
}
5151

52+
useEffect(() => {
53+
if (disabled) {
54+
setVisible(false);
55+
}
56+
}, [disabled]);
57+
5258
useEffect(() => {
5359
if (!values.length || disabled) return;
54-
const isActive = !!values.find(item => item === index);
60+
const isActive = values.some(item => (item === 0 ? index === 0 : item === index));
5561
setVisible(isActive);
56-
}, [values.join(',')]);
62+
}, [values.join(','), index, disabled]);
5763

5864
const clickHandler = () => {
5965
if (disabled) return;
@@ -136,8 +142,8 @@ const CollapseComponent: React.FC<React.PropsWithChildren<CollapseProps>> = ({
136142
${SCALE.padding(
137143
{
138144
top: 1.2,
139-
right: 0.5,
140-
left: 0.5,
145+
right: 0,
146+
left: 0,
141147
bottom: 1.2,
142148
},
143149
value => `padding: ${value.top} ${value.right} ${value.bottom} ${value.left};`,

src/components/utils/collections.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,18 @@ export const setChildrenProps = (
8888

8989
export const setChildrenIndex = (children: ReactNode | undefined, targetComponents: Array<React.ElementType> = []): ReactNode | undefined => {
9090
if (React.Children.count(children) === 0) return [];
91+
9192
const allowAll = targetComponents.length === 0;
9293
const clone = (child: React.ReactElement, props = {}) => React.cloneElement(child, props);
93-
let index = 0;
9494

9595
return React.Children.map(children, item => {
9696
if (!React.isValidElement(item)) return item;
97-
index = index + 1;
98-
if (allowAll) return clone(item, { index });
97+
98+
if (allowAll) return clone(item, { index: item.props.index });
9999

100100
const isAllowed = targetComponents.find(child => child === item.type);
101-
if (isAllowed) return clone(item, { index });
102-
index = index - 1;
101+
if (isAllowed) return clone(item, { index: item.props.index });
102+
103103
return item;
104104
});
105105
};

0 commit comments

Comments
 (0)