From f7bb82dd8ca195fe35aeb2816742714791730b39 Mon Sep 17 00:00:00 2001 From: Dalton <daltojohnso@users.noreply.github.com> Date: Mon, 29 Mar 2021 11:14:39 -0700 Subject: [PATCH] Add CollapseSection UI component (#15358) * Add CollapseSection component * Replace header string prop with header node prop * update nounage open/closed --> expanded/collapsed * add className prop --- .../components/CollapseSection.info.js | 63 +++++++++++++++++ .../metabase/components/CollapseSection.jsx | 70 +++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 frontend/src/metabase/components/CollapseSection.info.js create mode 100644 frontend/src/metabase/components/CollapseSection.jsx diff --git a/frontend/src/metabase/components/CollapseSection.info.js b/frontend/src/metabase/components/CollapseSection.info.js new file mode 100644 index 00000000000..e44df34673c --- /dev/null +++ b/frontend/src/metabase/components/CollapseSection.info.js @@ -0,0 +1,63 @@ +import React from "react"; +import CollapseSection from "metabase/components/CollapseSection"; +import Icon from "metabase/components/Icon"; + +export const component = CollapseSection; +export const category = "layout"; +export const description = ` +A collapsible section with a clickable header. +`; + +export const examples = { + "Collapsed by default": ( + <CollapseSection header="Section header"> + foo foo foo foo foo foo foo foo + </CollapseSection> + ), + "Settable collpased/expanded initial state": ( + <CollapseSection initialState="expanded" header="Foo"> + foo foo foo foo foo + </CollapseSection> + ), + "Components in header": ( + <CollapseSection + header={ + <div> + <Icon className="mr1" name="folder" size={12} /> + Component header + </div> + } + > + foo foo foo foo foo + </CollapseSection> + ), + "Header and body classes": ( + <CollapseSection + initialState="expanded" + header="Section header" + headerClass="text-brand flex-reverse justify-between p1 border-bottom" + bodyClass="p2" + > + <div> + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus neque + tellus, mattis ut felis non, tempus mollis lacus. Vivamus nulla massa, + accumsan non ligula eu, dapibus volutpat libero. Mauris sollicitudin + dolor et ipsum fringilla auctor. Praesent et diam non nisi consequat + ornare. Aenean et risus vel dolor maximus dapibus a id massa. Nam + finibus quis libero eu finibus. Sed vehicula ac enim pellentesque + luctus. Phasellus vehicula et ipsum porttitor mollis. Fusce blandit + lacus a elit pretium, vestibulum porta nisi vehicula. Aliquam vel ligula + enim. Orci varius natoque penatibus et magnis dis parturient montes, + nascetur ridiculus mus. Pellentesque eget porta mi. Duis et lectus eget + dolor convallis mollis. Sed commodo nec urna eget egestas. + <br /> + <br /> + Mauris in ante sit amet ipsum tempus consequat. Curabitur auctor massa + vitae dui auctor scelerisque. Donec in leo a libero commodo sodales. + Integer egestas lacinia elit, vitae cursus sem mollis ut. Proin ut + dapibus metus, vel accumsan justo. Pellentesque eget finibus elit, ut + commodo felis. Ut non lacinia metus. Maecenas eget bibendum nisl. + </div> + </CollapseSection> + ), +}; diff --git a/frontend/src/metabase/components/CollapseSection.jsx b/frontend/src/metabase/components/CollapseSection.jsx new file mode 100644 index 00000000000..f5cafd214ad --- /dev/null +++ b/frontend/src/metabase/components/CollapseSection.jsx @@ -0,0 +1,70 @@ +/* eslint "react/prop-types": 2 */ + +import React, { useState } from "react"; +import PropTypes from "prop-types"; +import cx from "classnames"; + +import Icon from "metabase/components/Icon"; + +function CollapseSection({ + children, + className, + header, + headerClass, + bodyClass, + initialState = "collapsed", +}) { + const [isExpanded, setIsExpanded] = useState(initialState === "expanded"); + + return ( + <div + className={cx( + "collapse-section", + isExpanded && "collapse-section--expanded", + className, + )} + role="tab" + aria-expanded={isExpanded} + > + <div + role="button" + tabIndex="0" + className={cx( + "collapse-section__header cursor-pointer flex align-center", + headerClass, + )} + onClick={() => setIsExpanded(isExpanded => !isExpanded)} + onKeyDown={e => + e.key === "Enter" && setIsExpanded(isExpanded => !isExpanded) + } + > + <Icon + className="mr1" + name={isExpanded ? "chevrondown" : "chevronright"} + size={12} + /> + <span className="collapse-section__header-text flex align-center"> + {header} + </span> + </div> + <div role="tabpanel" className="collapse-section__body-container"> + {isExpanded && ( + <div className={cx("collapse-section__body-container", bodyClass)}> + {children} + </div> + )} + </div> + </div> + ); +} + +CollapseSection.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + header: PropTypes.node, + headerClass: PropTypes.string, + bodyClass: PropTypes.string, + initialState: PropTypes.oneOf(["expanded", "collapsed"]), +}; + +export default CollapseSection; -- GitLab