From 63c725bec4bf44406a1622caffdf759be184bbbc Mon Sep 17 00:00:00 2001 From: Super Snager Date: Sat, 4 Feb 2023 20:20:16 +0100 Subject: [PATCH] feat(expansion-panel): added controlled opening state --- .../ExpansionPanel/ExpansionPanel.d.ts | 8 +++- .../ExpansionPanel/ExpansionPanel.jsx | 37 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/components/ExpansionPanel/ExpansionPanel.d.ts b/src/components/ExpansionPanel/ExpansionPanel.d.ts index 37aaf5d..c921599 100644 --- a/src/components/ExpansionPanel/ExpansionPanel.d.ts +++ b/src/components/ExpansionPanel/ExpansionPanel.d.ts @@ -1,9 +1,13 @@ -import type {ReactElement} from "react"; +import type {ReactElement, MouseEvent} from "react"; import type {ChatComponentPropsChildren} from "../../types"; -export interface ExpansionPanelProps { +export type ExpansionPanelOnChangeHandler = IsOpened extends boolean ? (evt: MouseEvent) => void : (state: boolean, evt: MouseEvent ) => void; + +export interface ExpansionPanelProps { title?:string; open?:boolean; + isOpened?: IsOpened; + onChange?: ExpansionPanelOnChangeHandler; } export declare const ExpansionPanel: (props:ChatComponentPropsChildren) => ReactElement; diff --git a/src/components/ExpansionPanel/ExpansionPanel.jsx b/src/components/ExpansionPanel/ExpansionPanel.jsx index 2914510..b56f124 100644 --- a/src/components/ExpansionPanel/ExpansionPanel.jsx +++ b/src/components/ExpansionPanel/ExpansionPanel.jsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useCallback, useMemo } from "react"; import PropTypes from "prop-types"; import { prefix } from "../settings"; import classNames from "classnames"; @@ -10,6 +10,8 @@ export const ExpansionPanel = ({ children, title, open: defaultOpen, + isOpened, + onChange, className, ...rest }) => { @@ -19,12 +21,29 @@ export const ExpansionPanel = ({ const [open, setOpen] = useState(defaultOpenFlag); - const openModifier = open === true ? `${cName}--open` : ""; - const icon = open === true ? faChevronDown : faChevronLeft; + const opened = useMemo( + () => (typeof isOpened === "boolean" ? isOpened : open), + [isOpened, open] + ); + + const openModifier = opened === true ? `${cName}--open` : ""; + const icon = opened === true ? faChevronDown : faChevronLeft; + + const handleOpen = useCallback( + (e) => { + if (typeof isOpened === "boolean") { + onChange?.(e); + } else { + setOpen(!opened); + onChange?.(!opened, e); + } + }, + [onChange, open, opened, isOpened] + ); return (
-
setOpen(!open)}> +
{title}
@@ -35,6 +54,8 @@ export const ExpansionPanel = ({ ); }; +ExpansionPanel.displayName = "ExpansionPanel"; + ExpansionPanel.propTypes = { /** Primary content. */ children: PropTypes.node, @@ -42,11 +63,17 @@ ExpansionPanel.propTypes = { /** Title. */ title: PropTypes.string, - /** Default open state. */ + /** Default open state (uncontrolled mode). */ open: PropTypes.bool, + /** If panel is opened (controlled mode). */ + isOpened: PropTypes.bool, + /** Additional classes. */ className: PropTypes.string, + + /** Called when the opening state changes. */ + onChange: PropTypes.func, }; ExpansionPanel.defaultProps = {