diff options
Diffstat (limited to 'src/components/molecules/layout/widget.tsx')
| -rw-r--r-- | src/components/molecules/layout/widget.tsx | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/components/molecules/layout/widget.tsx b/src/components/molecules/layout/widget.tsx new file mode 100644 index 0000000..f50fe80 --- /dev/null +++ b/src/components/molecules/layout/widget.tsx @@ -0,0 +1,66 @@ +import { FC, ReactNode, useState } from 'react'; +import HeadingButton, { + type HeadingButtonProps, +} from '../buttons/heading-button'; +import styles from './widget.module.scss'; + +export type WidgetProps = Pick< + HeadingButtonProps, + 'expanded' | 'level' | 'title' +> & { + /** + * The widget body. + */ + children: ReactNode; + /** + * Set additional classnames to the widget wrapper. + */ + className?: string; + /** + * Determine if the widget body should have borders. Default: false. + */ + withBorders?: boolean; + /** + * Determine if a vertical scrollbar should be displayed. Default: false. + */ + withScroll?: boolean; +}; + +/** + * Widget component + * + * Render an expandable widget. + */ +const Widget: FC<WidgetProps> = ({ + children, + className = '', + expanded = true, + level, + title, + withBorders = false, + withScroll = false, +}) => { + const [isExpanded, setIsExpanded] = useState<boolean>(expanded); + const stateClass = isExpanded ? 'widget--expanded' : 'widget--collapsed'; + const bordersClass = withBorders + ? 'widget--has-borders' + : 'widget--no-borders'; + const scrollClass = withScroll ? 'widget--has-scroll' : 'widget--no-scroll'; + + return ( + <div + className={`${styles.widget} ${styles[bordersClass]} ${styles[stateClass]} ${styles[scrollClass]} ${className}`} + > + <HeadingButton + level={level} + title={title} + expanded={isExpanded} + setExpanded={setIsExpanded} + className={styles.widget__header} + /> + <div className={styles.widget__body}>{children}</div> + </div> + ); +}; + +export default Widget; |
