Skip to content

Commit b8b2220

Browse files
ref(components): extracted a DragReorderButton component (#110982)
As noted in #110842 (comment), we have a lot of very similar drag-to-reorder buttons. This extracts a shared `DragReorderButton` component for all of them. One notable change: `style={{cursor: 'grab'}}` was only added in one existing component, under rules/uptime/assertions. Now it's in the shared one. ~I'm checking with design today and we might end up changing it - but I don't think the single cursor style should block review.~ Confirmed we prefer the grabby one. Fixes EXP-856
1 parent c57e28e commit b8b2220

File tree

12 files changed

+71
-96
lines changed

12 files changed

+71
-96
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {Button, type ButtonProps} from '@sentry/scraps/button';
2+
3+
import {IconGrabbable} from 'sentry/icons';
4+
import {t} from 'sentry/locale';
5+
import type {IconSize} from 'sentry/utils/theme';
6+
7+
type DragReorderButtonProps = Omit<ButtonProps, 'children'> & {
8+
iconSize?: IconSize;
9+
};
10+
11+
export function DragReorderButton({
12+
size = 'zero',
13+
iconSize = 'xs',
14+
ref,
15+
...props
16+
}: DragReorderButtonProps) {
17+
return (
18+
<Button
19+
aria-label={t('Drag to reorder')}
20+
priority="transparent"
21+
size={size}
22+
style={{cursor: 'grab'}}
23+
icon={<IconGrabbable size={iconSize} />}
24+
ref={ref}
25+
{...props}
26+
/>
27+
);
28+
}

static/app/views/alerts/rules/uptime/assertions/opCommon.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import type {SelectOption} from '@sentry/scraps/compactSelect';
77
import {Flex, Grid} from '@sentry/scraps/layout';
88
import {Text} from '@sentry/scraps/text';
99

10+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
1011
import {QuestionTooltip} from 'sentry/components/questionTooltip';
11-
import {IconDelete, IconGrabbable} from 'sentry/icons';
12+
import {IconDelete} from 'sentry/icons';
1213
import {t} from 'sentry/locale';
1314
import {AssertionFormError} from 'sentry/views/alerts/rules/uptime/formErrors';
1415
import {
@@ -85,13 +86,9 @@ export function OpContainer({
8586
<Text size="sm" bold>
8687
<label htmlFor={inputId}>{label}</label>
8788
</Text>
88-
<Button
89-
size="zero"
90-
priority="transparent"
91-
icon={<IconGrabbable size="xs" />}
89+
<DragReorderButton
9290
aria-label={t('Reorder assertion')}
9391
ref={setActivatorNodeRef}
94-
style={{cursor: 'grab'}}
9592
{...listeners}
9693
{...attributes}
9794
/>

static/app/views/alerts/rules/uptime/assertions/opGroup.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import {Container, Stack} from '@sentry/scraps/layout';
99
import {OverlayTrigger} from '@sentry/scraps/overlayTrigger';
1010
import {Text} from '@sentry/scraps/text';
1111

12-
import {IconAdd, IconDelete, IconGrabbable} from 'sentry/icons';
12+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
13+
import {IconAdd, IconDelete} from 'sentry/icons';
1314
import {t} from 'sentry/locale';
1415
import {uniqueId} from 'sentry/utils/guid';
1516
import {
@@ -231,10 +232,7 @@ export function AssertionOpGroup({
231232
options={[{value: 'negated', label: t('Negate result')}]}
232233
/>
233234
</CompositeSelect>
234-
<Button
235-
size="zero"
236-
priority="transparent"
237-
icon={<IconGrabbable size="xs" />}
235+
<DragReorderButton
238236
aria-label={t('Reorder assertion group')}
239237
ref={setActivatorNodeRef}
240238
{...listeners}

static/app/views/dashboards/widgetBuilder/buildSteps/groupByStep/queryField.tsx

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {Fragment, type ReactNode} from 'react';
2-
import type {DraggableSyntheticListeners, UseDraggableArguments} from '@dnd-kit/core';
2+
import type {DraggableAttributes, DraggableSyntheticListeners} from '@dnd-kit/core';
33
import styled from '@emotion/styled';
44

55
import {Button} from '@sentry/scraps/button';
66

7-
import {IconDelete, IconGrabbable} from 'sentry/icons';
7+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
8+
import {IconDelete} from 'sentry/icons';
89
import {t} from 'sentry/locale';
910
import type {QueryFieldValue} from 'sentry/utils/discover/fields';
1011
import {QueryField as TableQueryField} from 'sentry/views/discover/table/queryField';
@@ -14,7 +15,7 @@ export interface QueryFieldProps {
1415
fieldOptions: React.ComponentProps<typeof TableQueryField>['fieldOptions'];
1516
onChange: (newValue: QueryFieldValue) => void;
1617
value: QueryFieldValue;
17-
attributes?: UseDraggableArguments['attributes'];
18+
attributes?: DraggableAttributes;
1819
canDelete?: boolean;
1920
canDrag?: boolean;
2021
disabled?: boolean;
@@ -53,16 +54,7 @@ export function QueryField({
5354
<QueryFieldWrapper ref={ref} style={style}>
5455
{isDragging ? null : (
5556
<Fragment>
56-
{canDrag && (
57-
<DragAndReorderButton
58-
{...listeners}
59-
{...attributes}
60-
aria-label={t('Drag to reorder')}
61-
icon={<IconGrabbable size="xs" />}
62-
size="zero"
63-
priority="transparent"
64-
/>
65-
)}
57+
{canDrag && <StyledDragReorderButton {...listeners} {...attributes} />}
6658
<TableQueryField
6759
placeholder={t('Select group')}
6860
fieldValue={value}
@@ -91,7 +83,7 @@ export function QueryField({
9183
);
9284
}
9385

94-
const DragAndReorderButton = styled(Button)`
86+
const StyledDragReorderButton = styled(DragReorderButton)`
9587
height: ${p => p.theme.form.md.height};
9688
`;
9789

static/app/views/dashboards/widgetBuilder/components/common/sortableFieldWrapper.tsx

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import {CSS} from '@dnd-kit/utilities';
33
import {useTheme} from '@emotion/react';
44
import styled from '@emotion/styled';
55

6-
import {Button} from '@sentry/scraps/button';
7-
8-
import {IconGrabbable} from 'sentry/icons';
9-
import {t} from 'sentry/locale';
6+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
107

118
export function SortableVisualizeFieldWrapper({
129
dragId,
@@ -47,22 +44,14 @@ export function SortableVisualizeFieldWrapper({
4744
return (
4845
<div ref={setNodeRef} style={style}>
4946
{canDrag && (
50-
<DragAndReorderButton
51-
{...listeners}
52-
{...attributes}
53-
aria-label={t('Drag to reorder')}
54-
icon={<IconGrabbable size="xs" />}
55-
size="zero"
56-
priority="transparent"
57-
isDragging={isDragging}
58-
/>
47+
<StyledDragReorderButton {...listeners} {...attributes} isDragging={isDragging} />
5948
)}
6049
{children}
6150
</div>
6251
);
6352
}
6453

65-
const DragAndReorderButton = styled(Button)<{isDragging: boolean}>`
54+
const StyledDragReorderButton = styled(DragReorderButton)<{isDragging: boolean}>`
6655
height: ${p => p.theme.form.md.height};
6756
6857
${p => p.isDragging && p.theme.visuallyHidden}

static/app/views/dashboards/widgetBuilder/components/visualize/visualizeGhostField.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import styled from '@emotion/styled';
33

44
import {Button} from '@sentry/scraps/button';
55

6-
import {IconDelete, IconGrabbable} from 'sentry/icons';
6+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
7+
import {IconDelete} from 'sentry/icons';
78
import {t} from 'sentry/locale';
89
import type {SelectValue} from 'sentry/types/core';
910
import {
@@ -91,12 +92,7 @@ export function VisualizeGhostField({
9192
return (
9293
<Ghost>
9394
<FieldRow>
94-
<DragAndReorderButton
95-
aria-label={t('Drag to reorder')}
96-
icon={<IconGrabbable size="xs" />}
97-
size="zero"
98-
priority="transparent"
99-
/>
95+
<StyledDragReorderButton />
10096
<FieldBar>
10197
{draggingField?.kind === FieldValueKind.EQUATION ? (
10298
<StyledArithmeticInput
@@ -237,6 +233,6 @@ const Ghost = styled('div')`
237233
}
238234
`;
239235

240-
const DragAndReorderButton = styled(Button)`
236+
const StyledDragReorderButton = styled(DragReorderButton)`
241237
height: ${p => p.theme.form.md.height};
242238
`;

static/app/views/discover/table/columnEditCollection.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import {Tooltip} from '@sentry/scraps/tooltip';
1010

1111
import {parseArithmetic} from 'sentry/components/arithmeticInput/parser';
1212
import {SectionHeading} from 'sentry/components/charts/styles';
13+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
1314
import {getOffsetOfElement} from 'sentry/components/performance/waterfall/utils';
14-
import {IconAdd, IconDelete, IconGrabbable, IconWarning} from 'sentry/icons';
15+
import {IconAdd, IconDelete, IconWarning} from 'sentry/icons';
1516
import {t} from 'sentry/locale';
1617
import type {Organization} from 'sentry/types/organization';
1718
import {trackAnalytics} from 'sentry/utils/analytics';
@@ -484,13 +485,9 @@ class ColumnEditCollection extends Component<Props, State> {
484485
className={isGhost ? '' : DRAG_CLASS}
485486
>
486487
{canDrag ? (
487-
<DragAndReorderButton
488-
aria-label={t('Drag to reorder')}
488+
<StyledDragReorderButton
489489
onMouseDown={event => this.startDrag(event, i)}
490490
onTouchStart={event => this.startDrag(event, i)}
491-
icon={<IconGrabbable size="xs" />}
492-
size="zero"
493-
priority="transparent"
494491
/>
495492
) : singleColumn && showAliasField ? null : (
496493
<span />
@@ -789,7 +786,7 @@ const RemoveButton = styled(Button)`
789786
height: ${p => p.theme.form.md.height};
790787
`;
791788

792-
const DragAndReorderButton = styled(Button)`
789+
const StyledDragReorderButton = styled(DragReorderButton)`
793790
height: ${p => p.theme.form.md.height};
794791
`;
795792

static/app/views/explore/components/toolbar/toolbarGroupBy/index.tsx

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import {CompactSelect} from '@sentry/scraps/compactSelect';
99
import {OverlayTrigger} from '@sentry/scraps/overlayTrigger';
1010
import {Tooltip} from '@sentry/scraps/tooltip';
1111

12+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
1213
import {IconAdd} from 'sentry/icons/iconAdd';
1314
import {IconDelete} from 'sentry/icons/iconDelete';
14-
import {IconGrabbable} from 'sentry/icons/iconGrabbable';
1515
import {t} from 'sentry/locale';
1616
import {getFieldDefinition} from 'sentry/utils/fields';
1717
import {
@@ -83,15 +83,7 @@ export function ToolbarGroupByDropdown({
8383
style={{transform: CSS.Transform.toString(transform)}}
8484
{...attributes}
8585
>
86-
{canDelete ? (
87-
<Button
88-
aria-label={t('Drag to reorder')}
89-
priority="transparent"
90-
size="zero"
91-
icon={<IconGrabbable size="sm" />}
92-
{...listeners}
93-
/>
94-
) : null}
86+
{canDelete ? <DragReorderButton iconSize="sm" {...listeners} /> : null}
9587
<StyledCompactSelect
9688
data-test-id="editor-column"
9789
options={options}

static/app/views/explore/components/toolbar/toolbarVisualize/index.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import type {SelectKey, SelectOption} from '@sentry/scraps/compactSelect';
88
import {CompactSelect} from '@sentry/scraps/compactSelect';
99
import {Tooltip} from '@sentry/scraps/tooltip';
1010

11+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
1112
import {IconAdd} from 'sentry/icons';
1213
import {IconDelete} from 'sentry/icons/iconDelete';
13-
import {IconGrabbable} from 'sentry/icons/iconGrabbable';
1414
import {t} from 'sentry/locale';
1515
import type {ParsedFunction} from 'sentry/utils/discover/fields';
1616
import {getFieldDefinition} from 'sentry/utils/fields';
@@ -80,13 +80,7 @@ export function ToolbarVisualizeDropdown({
8080
{...attributes}
8181
>
8282
{dragColumnId === undefined ? null : (
83-
<Button
84-
aria-label={t('Drag to reorder')}
85-
priority="transparent"
86-
size="zero"
87-
icon={<IconGrabbable size="sm" />}
88-
{...listeners}
89-
/>
83+
<DragReorderButton iconSize="sm" {...listeners} />
9084
)}
9185
{label}
9286
<AggregateCompactSelect

static/app/views/explore/components/toolbar/toolbarVisualize/visualizeEquation.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import {Flex} from '@sentry/scraps/layout';
88
import {ArithmeticBuilder} from 'sentry/components/arithmeticBuilder';
99
import type {Expression} from 'sentry/components/arithmeticBuilder/expression';
1010
import type {FunctionArgument} from 'sentry/components/arithmeticBuilder/types';
11+
import {DragReorderButton} from 'sentry/components/dnd/dragReorderButton';
1112
import {IconDelete} from 'sentry/icons/iconDelete';
12-
import {IconGrabbable} from 'sentry/icons/iconGrabbable';
1313
import {t} from 'sentry/locale';
1414
import {EQUATION_PREFIX, stripEquationPrefix} from 'sentry/utils/discover/fields';
1515
import {
@@ -98,13 +98,7 @@ export function VisualizeEquation({
9898
{...attributes}
9999
>
100100
{dragColumnId === undefined ? null : (
101-
<Button
102-
aria-label={t('Drag to reorder')}
103-
priority="transparent"
104-
size="zero"
105-
icon={<IconGrabbable size="sm" />}
106-
{...listeners}
107-
/>
101+
<DragReorderButton iconSize="sm" {...listeners} />
108102
)}
109103
{label}
110104
<Flex flex={1}>

0 commit comments

Comments
 (0)