diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index c234399e4fc..e4420d9f7bd 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -39,6 +39,7 @@ "lodash": "4.17.15", "moment": "2.24.0", "papaparse": "4.6.3", + "rc-drawer": "3.0.2", "rc-time-picker": "^3.7.2", "react": "16.8.6", "react-calendar": "2.18.1", diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.mdx b/packages/grafana-ui/src/components/Drawer/Drawer.mdx new file mode 100644 index 00000000000..5bfaf6df884 --- /dev/null +++ b/packages/grafana-ui/src/components/Drawer/Drawer.mdx @@ -0,0 +1,4 @@ +import { Props } from '@storybook/addon-docs/blocks'; +import { Drawer } from './Drawer'; + + diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx new file mode 100644 index 00000000000..e812c545594 --- /dev/null +++ b/packages/grafana-ui/src/components/Drawer/Drawer.story.tsx @@ -0,0 +1,205 @@ +import React from 'react'; +import { text } from '@storybook/addon-knobs'; +import { Drawer } from './Drawer'; +import { UseState } from '../../utils/storybook/UseState'; +import { withCenteredStory } from '../../utils/storybook/withCenteredStory'; +import mdx from './Drawer.mdx'; + +export default { + title: 'UI/Drawer', + component: Drawer, + decorators: [withCenteredStory], + parameters: { + docs: { + page: mdx, + }, + }, +}; + +export const global = () => { + const drawerTitle = text('title', 'Storybook'); + + return ( + + {(state, updateValue) => { + return ( + <> +
updateValue({ isOpen: !state.isOpen })} + > + Open drawer +
+ {state.isOpen && ( + { + updateValue({ isOpen: !state.isOpen }); + }} + > +
    +
  • this
  • +
  • is
  • +
  • a
  • +
  • list
  • +
  • of
  • +
  • menu
  • +
  • items
  • +
+
+ )} + + ); + }} +
+ ); +}; + +export const longContent = () => { + return ( + + {(state, updateValue) => { + return ( + <> +
updateValue({ isOpen: !state.isOpen })} + > + Open drawer +
+ {state.isOpen && ( + { + updateValue({ isOpen: !state.isOpen }); + }} + > +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et + dolore magna aliqua. Iaculis nunc sed augue lacus viverra vitae. Malesuada pellentesque elit eget + gravida cum sociis. Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu. Cras + adipiscing enim eu turpis egestas. Ut lectus arcu bibendum at varius. Nulla pellentesque dignissim + enim sit amet venenatis urna. Tempus urna et pharetra pharetra massa massa ultricies mi quis. Vitae + congue mauris rhoncus aenean. Enim ut tellus elementum sagittis vitae et. +

+

+ Arcu non odio euismod lacinia at quis risus sed vulputate. Sit amet consectetur adipiscing elit ut. + Dictum fusce ut placerat orci nulla pellentesque dignissim. Lectus nulla at volutpat diam ut venenatis + tellus. Sed cras ornare arcu dui. Eget mauris pharetra et ultrices neque ornare aenean euismod. Mi + quis hendrerit dolor magna. Commodo viverra maecenas accumsan lacus vel facilisis. Eget mi proin sed + libero enim sed. Magna ac placerat vestibulum lectus mauris ultrices eros in. Mattis nunc sed blandit + libero volutpat. +

+

+ Cursus in hac habitasse platea dictumst quisque sagittis purus. Viverra adipiscing at in tellus. + Semper eget duis at tellus at urna condimentum. Egestas fringilla phasellus faucibus scelerisque + eleifend. Sem nulla pharetra diam sit amet nisl. Ut ornare lectus sit amet est placerat in egestas + erat. Id neque aliquam vestibulum morbi blandit cursus risus. In iaculis nunc sed augue. Eu volutpat + odio facilisis mauris sit. Quisque egestas diam in arcu cursus euismod. At quis risus sed vulputate + odio ut enim blandit volutpat. Cursus risus at ultrices mi tempus imperdiet nulla malesuada. Sed + adipiscing diam donec adipiscing tristique risus nec. Id neque aliquam vestibulum morbi. Pretium nibh + ipsum consequat nisl vel pretium lectus quam. Platea dictumst quisque sagittis purus sit. Nascetur + ridiculus mus mauris vitae ultricies leo. +

+

+ Cursus in hac habitasse platea dictumst quisque sagittis purus. Viverra adipiscing at in tellus. + Semper eget duis at tellus at urna condimentum. Egestas fringilla phasellus faucibus scelerisque + eleifend. Sem nulla pharetra diam sit amet nisl. Ut ornare lectus sit amet est placerat in egestas + erat. Id neque aliquam vestibulum morbi blandit cursus risus. In iaculis nunc sed augue. Eu volutpat + odio facilisis mauris sit. Quisque egestas diam in arcu cursus euismod. At quis risus sed vulputate + odio ut enim blandit volutpat. Cursus risus at ultrices mi tempus imperdiet nulla malesuada. Sed + adipiscing diam donec adipiscing tristique risus nec. Id neque aliquam vestibulum morbi. Pretium nibh + ipsum consequat nisl vel pretium lectus quam. Platea dictumst quisque sagittis purus sit. Nascetur + ridiculus mus mauris vitae ultricies leo. +

+

+ Cursus in hac habitasse platea dictumst quisque sagittis purus. Viverra adipiscing at in tellus. + Semper eget duis at tellus at urna condimentum. Egestas fringilla phasellus faucibus scelerisque + eleifend. Sem nulla pharetra diam sit amet nisl. Ut ornare lectus sit amet est placerat in egestas + erat. Id neque aliquam vestibulum morbi blandit cursus risus. In iaculis nunc sed augue. Eu volutpat + odio facilisis mauris sit. Quisque egestas diam in arcu cursus euismod. At quis risus sed vulputate + odio ut enim blandit volutpat. Cursus risus at ultrices mi tempus imperdiet nulla malesuada. Sed + adipiscing diam donec adipiscing tristique risus nec. Id neque aliquam vestibulum morbi. Pretium nibh + ipsum consequat nisl vel pretium lectus quam. Platea dictumst quisque sagittis purus sit. Nascetur + ridiculus mus mauris vitae ultricies leo. +

+

+ Cursus in hac habitasse platea dictumst quisque sagittis purus. Viverra adipiscing at in tellus. + Semper eget duis at tellus at urna condimentum. Egestas fringilla phasellus faucibus scelerisque + eleifend. Sem nulla pharetra diam sit amet nisl. Ut ornare lectus sit amet est placerat in egestas + erat. Id neque aliquam vestibulum morbi blandit cursus risus. In iaculis nunc sed augue. Eu volutpat + odio facilisis mauris sit. Quisque egestas diam in arcu cursus euismod. At quis risus sed vulputate + odio ut enim blandit volutpat. Cursus risus at ultrices mi tempus imperdiet nulla malesuada. Sed + adipiscing diam donec adipiscing tristique risus nec. Id neque aliquam vestibulum morbi. Pretium nibh + ipsum consequat nisl vel pretium lectus quam. Platea dictumst quisque sagittis purus sit. Nascetur + ridiculus mus mauris vitae ultricies leo. +

+

+ Cursus in hac habitasse platea dictumst quisque sagittis purus. Viverra adipiscing at in tellus. + Semper eget duis at tellus at urna condimentum. Egestas fringilla phasellus faucibus scelerisque + eleifend. Sem nulla pharetra diam sit amet nisl. Ut ornare lectus sit amet est placerat in egestas + erat. Id neque aliquam vestibulum morbi blandit cursus risus. In iaculis nunc sed augue. Eu volutpat + odio facilisis mauris sit. Quisque egestas diam in arcu cursus euismod. At quis risus sed vulputate + odio ut enim blandit volutpat. Cursus risus at ultrices mi tempus imperdiet nulla malesuada. Sed + adipiscing diam donec adipiscing tristique risus nec. Id neque aliquam vestibulum morbi. Pretium nibh + ipsum consequat nisl vel pretium lectus quam. Platea dictumst quisque sagittis purus sit. Nascetur + ridiculus mus mauris vitae ultricies leo. +

+
+ )} + + ); + }} +
+ ); +}; + +export const inLine = () => { + const drawerTitle = text('title', 'Storybook'); + + return ( + + {(state, updateValue) => { + return ( + <> +
+
updateValue({ isOpen: !state.isOpen })} + > + Open drawer +
+ {state.isOpen && ( + { + updateValue({ isOpen: !state.isOpen }); + }} + > +
    +
  • this
  • +
  • is
  • +
  • a
  • +
  • list
  • +
  • of
  • +
  • menu
  • +
  • items
  • +
+
+ )} +
+ + ); + }} +
+ ); +}; diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.tsx new file mode 100644 index 00000000000..1616b595594 --- /dev/null +++ b/packages/grafana-ui/src/components/Drawer/Drawer.tsx @@ -0,0 +1,94 @@ +import React, { CSSProperties, FC, ReactNode } from 'react'; +import { GrafanaTheme } from '@grafana/data'; +import RcDrawer from 'rc-drawer'; +import { css } from 'emotion'; +import { stylesFactory, useTheme, selectThemeVariant } from '../../themes'; + +interface Props { + children: ReactNode; + /** Title shown at the top of the drawer */ + title?: string; + /** Should the Drawer be closable by clicking on the mask */ + closeOnMaskClick?: boolean; + /** Render the drawer inside a container on the page */ + inline?: boolean; + /** Either a number in px or a string with unit postfix */ + width?: number | string; + + onClose: () => void; +} + +const getStyles = stylesFactory((theme: GrafanaTheme) => { + const closeButtonWidth = '50px'; + const borderColor = selectThemeVariant( + { + light: theme.colors.gray4, + dark: theme.colors.dark9, + }, + theme.type + ); + return { + drawer: css` + .drawer-content { + background-color: ${theme.colors.bodyBg}; + } + `, + titleWrapper: css` + font-size: ${theme.typography.size.lg}; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid ${borderColor}; + padding: ${theme.spacing.sm} 0 ${theme.spacing.sm} ${theme.spacing.md}; + background-color: ${theme.colors.bodyBg}; + position: sticky; + top: 0; + `, + close: css` + cursor: pointer; + width: ${closeButtonWidth}; + height: 100%; + display: flex; + flex-shrink: 0; + justify-content: center; + `, + content: css` + padding: ${theme.spacing.md}; + `, + }; +}); + +export const Drawer: FC = ({ + children, + inline = false, + onClose, + closeOnMaskClick = false, + title, + width = '40%', +}) => { + const theme = useTheme(); + const drawerStyles = getStyles(theme); + + return ( + +
+
{title}
+
+ +
+
+
{children}
+
+ ); +}; diff --git a/packages/grafana-ui/src/components/Drawer/_Drawer.scss b/packages/grafana-ui/src/components/Drawer/_Drawer.scss new file mode 100644 index 00000000000..cad924f0b2e --- /dev/null +++ b/packages/grafana-ui/src/components/Drawer/_Drawer.scss @@ -0,0 +1,2 @@ +// Need to import this to get default styles from rc-drawer +@import '../../node_modules/rc-drawer/assets/index.css'; diff --git a/packages/grafana-ui/src/components/index.scss b/packages/grafana-ui/src/components/index.scss index 0a9adb3650e..87dbb7fc435 100644 --- a/packages/grafana-ui/src/components/index.scss +++ b/packages/grafana-ui/src/components/index.scss @@ -15,3 +15,4 @@ @import 'RefreshPicker/RefreshPicker'; @import 'TimePicker/TimePicker'; @import 'TimePicker/TimeOfDayPicker'; +@import 'Drawer/Drawer'; diff --git a/yarn.lock b/yarn.lock index 96919b7b99d..6c96274b142 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5862,6 +5862,11 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" +caniuse-db@1.0.30000772: + version "1.0.30000772" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000772.tgz#51aae891768286eade4a3d8319ea76d6a01b512b" + integrity sha1-UarokXaChureSj2DGep21qAbUSs= + caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30000947, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30000999: version "1.0.30000999" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000999.tgz#427253a69ad7bea4aa8d8345687b8eec51ca0e43" @@ -16835,6 +16840,16 @@ rc-cascader@0.17.5: shallow-equal "^1.0.0" warning "^4.0.1" +rc-drawer@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-3.0.2.tgz#1c42b2b7790040344f8f05f1d132b1ef0e97b783" + integrity sha512-oPScGXB/8/ov9gEFLxPH8RBv/9jLTZboZtyF/GgrrnCAvbFwUxXdELH6n6XIowmuDKKvTGIMgZdnao0T46Yv3A== + dependencies: + babel-runtime "^6.26.0" + classnames "^2.2.6" + rc-util "^4.11.2" + react-lifecycles-compat "^3.0.4" + rc-time-picker@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/rc-time-picker/-/rc-time-picker-3.7.2.tgz#fabe5501adf1374d31a2d3b47f1ba89fc2dc2467" @@ -16860,7 +16875,7 @@ rc-trigger@^2.2.0: rc-util "^4.4.0" react-lifecycles-compat "^3.0.4" -rc-util@^4.0.4, rc-util@^4.4.0, rc-util@^4.8.0: +rc-util@^4.0.4, rc-util@^4.11.2, rc-util@^4.4.0, rc-util@^4.8.0: version "4.13.0" resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.13.0.tgz#75682e50a934e7d32ada7ee48fc9f5b20fc0143f" integrity sha512-rjfPy+afc2n40APHp6GYScXfgwHuUnYLz/4SCEWRaF8CHXKR8xw598LtPA36J3fEXENuMm6liO/CoKBoSrYCDw==