grafana/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
Torkel Ödegaard 49276f2c12
QueryTab: Design updates (#23906)
* WIP: first stage

* Another take

* argghhh

* Updated

* My brain is mush

* Minor progress

* Progres

* Starting to work

* Fixes

* fixed e2e
2020-04-26 21:59:14 +02:00

118 lines
3.3 KiB
TypeScript

import React, { useState } from 'react';
import { renderOrCallToRender, Icon, stylesFactory, useTheme, HorizontalGroup } from '@grafana/ui';
import { GrafanaTheme } from '@grafana/data';
import { css } from 'emotion';
import { useUpdateEffect } from 'react-use';
interface QueryOperationRowProps {
title?: ((props: { isOpen: boolean }) => React.ReactNode) | React.ReactNode;
headerElement?: React.ReactNode;
actions?:
| ((props: { isOpen: boolean; openRow: () => void; closeRow: () => void }) => React.ReactNode)
| React.ReactNode;
onOpen?: () => void;
onClose?: () => void;
children: React.ReactNode;
isOpen?: boolean;
}
export const QueryOperationRow: React.FC<QueryOperationRowProps> = ({
children,
actions,
title,
headerElement,
onClose,
onOpen,
isOpen,
}: QueryOperationRowProps) => {
const [isContentVisible, setIsContentVisible] = useState(isOpen !== undefined ? isOpen : true);
const theme = useTheme();
const styles = getQueryOperationRowStyles(theme);
useUpdateEffect(() => {
if (isContentVisible) {
if (onOpen) {
onOpen();
}
} else {
if (onClose) {
onClose();
}
}
}, [isContentVisible]);
const titleElement = title && renderOrCallToRender(title, { isOpen: isContentVisible });
const actionsElement =
actions &&
renderOrCallToRender(actions, {
isOpen: isContentVisible,
openRow: () => {
setIsContentVisible(true);
},
closeRow: () => {
setIsContentVisible(false);
},
});
return (
<div className={styles.wrapper}>
<div className={styles.header}>
<HorizontalGroup justify="space-between">
<div
className={styles.titleWrapper}
onClick={() => {
setIsContentVisible(!isContentVisible);
}}
aria-label="Query operation row title"
>
<Icon name={isContentVisible ? 'angle-down' : 'angle-right'} className={styles.collapseIcon} />
{title && <span className={styles.title}>{titleElement}</span>}
{headerElement}
</div>
{actions && actionsElement}
</HorizontalGroup>
</div>
{isContentVisible && <div className={styles.content}>{children}</div>}
</div>
);
};
const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => {
return {
wrapper: css`
margin-bottom: ${theme.spacing.md};
`,
header: css`
padding: 0 ${theme.spacing.sm};
border-radius: ${theme.border.radius.sm};
background: ${theme.colors.bg2};
height: ${theme.spacing.formInputHeight}px;
line-height: ${theme.spacing.formInputHeight}px;
display: flex;
align-items: center;
justify-content: space-between;
`,
collapseIcon: css`
color: ${theme.colors.textWeak};
&:hover {
color: ${theme.colors.text};
}
`,
titleWrapper: css`
display: flex;
align-items: center;
cursor: pointer;
`,
title: css`
font-weight: ${theme.typography.weight.semibold};
color: ${theme.colors.textBlue};
margin-left: ${theme.spacing.sm};
`,
content: css`
margin-top: ${theme.spacing.inlineFormMargin};
margin-left: ${theme.spacing.xl};
`,
};
});
QueryOperationRow.displayName = 'QueryOperationRow';