mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
70 lines
1.7 KiB
TypeScript
70 lines
1.7 KiB
TypeScript
import React, { useCallback, type PropsWithChildren } from "react";
|
|
|
|
import {
|
|
AccordionItem,
|
|
type AccordionItemPropsPublic,
|
|
} from "./components/AccordionItem";
|
|
import { cn } from "../../shared/utils/cn";
|
|
import type { BaseProps, HTMLProps } from "../../shared/types";
|
|
|
|
export type AccordionProps = HTMLProps<"div"> & {
|
|
expandedKeys: string[];
|
|
type?: "multi" | "single";
|
|
setExpandedKeys(keys: string[]): void;
|
|
} & BaseProps;
|
|
|
|
type AccordionType = React.FC<PropsWithChildren<AccordionProps>> & {
|
|
Item: React.FC<PropsWithChildren<AccordionItemPropsPublic>>;
|
|
};
|
|
|
|
const Accordion: AccordionType = ({
|
|
className,
|
|
expandedKeys,
|
|
setExpandedKeys,
|
|
children,
|
|
type = "multi",
|
|
testId,
|
|
...props
|
|
}) => {
|
|
const onChange = useCallback(
|
|
(key: string, expanded: boolean) => {
|
|
if (type === "multi") {
|
|
setExpandedKeys(
|
|
expanded
|
|
? [...expandedKeys, key]
|
|
: [...expandedKeys].filter((k) => k !== key)
|
|
);
|
|
} else {
|
|
setExpandedKeys(expanded ? [key] : []);
|
|
}
|
|
},
|
|
[expandedKeys, type]
|
|
);
|
|
|
|
const reactChildren = React.Children.toArray(children);
|
|
const items =
|
|
React.Children.map(reactChildren, (child: any) => {
|
|
const value = child.props.value;
|
|
const expanded = expandedKeys.some((key) => key === value);
|
|
return React.cloneElement(child, {
|
|
expanded,
|
|
onExpandedChange: () => onChange(value, !expanded),
|
|
className: "flex-1",
|
|
});
|
|
}) ?? [];
|
|
return (
|
|
<div
|
|
className={cn("flex flex-col gap-y-2.5 items-start", className)}
|
|
data-testid={testId}
|
|
{...props}
|
|
>
|
|
{items}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
Accordion.Item = AccordionItem as React.FC<
|
|
PropsWithChildren<AccordionItemPropsPublic>
|
|
>;
|
|
export { Accordion };
|