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,
- },
- }),
});