diff --git a/.betterer.results b/.betterer.results index 4dfb3a57bb4..484b913ab67 100644 --- a/.betterer.results +++ b/.betterer.results @@ -1053,11 +1053,6 @@ exports[`better eslint`] = { "public/app/core/components/SharedPreferences/SharedPreferences.tsx:5381": [ [0, 0, 0, "Styles should be written using objects.", "0"] ], - "public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"], - [0, 0, 0, "Styles should be written using objects.", "2"] - ], "public/app/core/components/TagFilter/TagFilter.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], diff --git a/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx b/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx new file mode 100644 index 00000000000..f0a5c8c5ecf --- /dev/null +++ b/packages/grafana-ui/src/components/DragHandle/DragHandle.tsx @@ -0,0 +1,83 @@ +import { css, cx } from '@emotion/css'; + +import { GrafanaTheme2 } from '@grafana/data'; + +export const getDragStyles = (theme: GrafanaTheme2) => { + const baseColor = theme.colors.emphasize(theme.colors.background.secondary, 0.15); + const hoverColor = theme.colors.primary.border; + const clickTargetSize = theme.spacing(2); + const handlebarThickness = 4; + const handlebarWidth = 200; + + const dragHandleBase = css({ + position: 'relative', + + '&:before': { + content: '""', + position: 'absolute', + transition: theme.transitions.create('border-color'), + }, + + '&:after': { + background: baseColor, + content: '""', + position: 'absolute', + left: '50%', + top: '50%', + transition: theme.transitions.create('background'), + transform: 'translate(-50%, -50%)', + borderRadius: theme.shape.radius.pill, + }, + + '&:hover': { + '&:before': { + borderColor: hoverColor, + }, + + '&:after': { + background: hoverColor, + }, + }, + }); + + return { + dragHandleVertical: cx( + dragHandleBase, + css({ + cursor: 'col-resize', + width: clickTargetSize, + + '&:before': { + borderRight: '1px solid transparent', + height: '100%', + left: '50%', + transform: 'translateX(-50%)', + }, + + '&:after': { + height: handlebarWidth, + width: handlebarThickness, + }, + }) + ), + dragHandleHorizontal: cx( + dragHandleBase, + css({ + height: clickTargetSize, + cursor: 'row-resize', + + '&:before': { + borderTop: '1px solid transparent', + top: '50%', + transform: 'translateY(-50%)', + width: '100%', + }, + + '&:after': { + height: handlebarThickness, + width: handlebarWidth, + }, + }) + ), + }; +}; diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.tsx index ee8116d0ed8..3459c21ba59 100644 --- a/packages/grafana-ui/src/components/Drawer/Drawer.tsx +++ b/packages/grafana-ui/src/components/Drawer/Drawer.tsx @@ -11,6 +11,7 @@ import { selectors } from '@grafana/e2e-selectors'; import { useStyles2 } from '../../themes'; import { t } from '../../utils/i18n'; import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar'; +import { getDragStyles } from '../DragHandle/DragHandle'; import { IconButton } from '../IconButton/IconButton'; import { Text } from '../Text/Text'; @@ -65,6 +66,7 @@ export function Drawer({ const styles = useStyles2(getStyles); const sizeStyles = useStyles2(getSizeStyles, size, drawerWidth ?? width); + const dragStyles = useStyles2(getDragStyles); const overlayRef = React.useRef(null); const { dialogProps, titleProps } = useDialog({}, overlayRef); @@ -116,7 +118,11 @@ export function Drawer({ ref={overlayRef} > {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} -
+
{typeof title === 'string' && (
@@ -338,46 +344,11 @@ const getStyles = (theme: GrafanaTheme2) => { margin: theme.spacing(1, -1, -3, -3), }), resizer: css({ - width: 8, top: 0, - left: -4, + left: theme.spacing(-1), bottom: 0, position: 'absolute', - cursor: 'col-resize', zIndex: theme.zIndex.modal, - - '&::after': { - background: theme.colors.emphasize(theme.colors.background.secondary, 0.15), - content: '""', - position: 'absolute', - left: '50%', - top: '50%', - transition: '0.2s background ease-in-out', - transform: 'translate(-50%, -50%)', - borderRadius: theme.shape.radius.default, - height: '200px', - width: '4px', - }, - - '&::before': { - content: '""', - position: 'absolute', - transition: '0.2s border-color ease-in-out', - borderRight: '2px solid transparent', - height: '100%', - left: '50%', - transform: 'translateX(-50%)', - }, - - '&:hover': { - '&::before': { - borderColor: theme.colors.primary.border, - }, - - '&::after': { - background: theme.colors.primary.border, - }, - }, }), }; }; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index c72282e0940..706175a2ee6 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -264,6 +264,7 @@ export { Avatar } from './UsersIndicator/Avatar'; // Export this until we've figured out a good approach to inline form styles. export { InlineFormLabel } from './FormLabel/FormLabel'; export { Divider } from './Divider/Divider'; +export { getDragStyles } from './DragHandle/DragHandle'; export { LayoutItemContext, type LayoutItemContextProps } from './Layout/LayoutItemContext'; diff --git a/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx b/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx index a282feb0f3b..9605b6e7721 100644 --- a/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx +++ b/public/app/core/components/SplitPaneWrapper/SplitPaneWrapper.tsx @@ -3,6 +3,7 @@ import React, { createRef, MutableRefObject, PureComponent } from 'react'; import SplitPane, { Split } from 'react-split-pane'; import { GrafanaTheme2 } from '@grafana/data'; +import { getDragStyles } from '@grafana/ui'; import { config } from 'app/core/config'; interface Props { @@ -74,6 +75,7 @@ export class SplitPaneWrapper extends PureComponent this.onDragStarted()} onDragFinished={(size) => this.onDragFinished(size)} style={parentStyle} @@ -109,83 +114,12 @@ export class SplitPaneWrapper extends PureComponent { - const handleColor = theme.v1.palette.blue95; - const paneSpacing = theme.spacing(2); - - const resizer = css` - position: relative; - display: ${hasSplit ? 'block' : 'none'}; - - &::before { - content: ''; - position: absolute; - transition: 0.2s border-color ease-in-out; - } - - &::after { - background: ${theme.components.panel.borderColor}; - content: ''; - position: absolute; - left: 50%; - top: 50%; - transition: 0.2s background ease-in-out; - transform: translate(-50%, -50%); - border-radius: ${theme.shape.radius.default}; - } - - &:hover { - &::before { - border-color: ${handleColor}; - } - - &::after { - background: ${handleColor}; - } - } - `; - return { splitPane: css({ overflow: 'visible !important', }), - resizerV: cx( - resizer, - css` - cursor: col-resize; - width: ${paneSpacing}; - - &::before { - border-right: 1px solid transparent; - height: 100%; - left: 50%; - transform: translateX(-50%); - } - - &::after { - height: 200px; - width: 4px; - } - ` - ), - resizerH: cx( - resizer, - css` - height: ${paneSpacing}; - cursor: row-resize; - margin-left: ${paneSpacing}; - - &::before { - border-top: 1px solid transparent; - top: 50%; - transform: translateY(-50%); - width: 100%; - } - - &::after { - height: 4px; - width: 200px; - } - ` - ), + resizer: css({ + display: hasSplit ? 'block' : 'none', + }), }; }; diff --git a/public/app/features/explore/ExploreDrawer.tsx b/public/app/features/explore/ExploreDrawer.tsx index d04fc46fcac..3e6fac27359 100644 --- a/public/app/features/explore/ExploreDrawer.tsx +++ b/public/app/features/explore/ExploreDrawer.tsx @@ -5,7 +5,7 @@ import React from 'react'; // Services & Utils import { GrafanaTheme2 } from '@grafana/data'; -import { useStyles2, useTheme2 } from '@grafana/ui'; +import { getDragStyles, useStyles2, useTheme2 } from '@grafana/ui'; export interface Props { width: number; @@ -17,13 +17,14 @@ export function ExploreDrawer(props: Props) { const { width, children, onResize } = props; const theme = useTheme2(); const styles = useStyles2(getStyles); + const dragStyles = getDragStyles(theme); const drawerWidth = `${width + 31.5}px`; return ( ({ opacity: 1, animation: `0.5s ease-out ${drawerSlide(theme)}`, }), - rzHandle: css({ - background: theme.colors.secondary.main, - transition: '0.3s background ease-in-out', - position: 'relative', - width: '200px !important', - height: '7px !important', - left: 'calc(50% - 100px) !important', - top: '-4px !important', - cursor: 'grab', - borderRadius: theme.shape.radius.pill, - ['&:hover']: { - background: theme.colors.secondary.shade, - }, - }), });