Skip to content

Commit 17fb869

Browse files
committed
chore: adjust step widths, change cursor (#1216)
## TL;DR CSS improvements: * Use `grab` and `grabbing` cursor for the DragHandle * Keep step widths the same as others when drag handle is shown Fix: * Make "Only continue if" deletable ## Screenshots * Condition Step width matches child step with in If-then branches ![Screenshot 2025-09-18 at 12.36.39 PM.png](https://app.graphite.dev/user-attachments/assets/c3620535-adbc-4813-a52e-8921690d7490.png) * If-then width matches for-each step widths ![Screenshot 2025-09-18 at 12.36.56 PM.png](https://app.graphite.dev/user-attachments/assets/89150639-61bd-4f34-b1b8-58e0bbcd5fcf.png) ![Screenshot 2025-09-18 at 12.37.16 PM.png](https://app.graphite.dev/user-attachments/assets/4c5345d4-a312-4c66-8e63-fed3180402b0.png)
1 parent e2f8d7f commit 17fb869

File tree

14 files changed

+115
-37
lines changed

14 files changed

+115
-37
lines changed

packages/frontend/src/components/FlowStep/FlowStepWrapper.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
import { Flex } from '@chakra-ui/react'
22
import { useIsMobile } from '@opengovsg/design-system-react'
33

4-
import { MIN_FLOW_STEP_WIDTH } from '@/components/Editor/constants'
4+
import { NESTED_DRAG_HANDLE_WIDTH } from '../SortableList/components/SortableItem'
55

66
interface FlowStepWrapperProps {
77
children: React.ReactNode
8-
isNested?: boolean
8+
canChildStepsReorder?: boolean
9+
allowReorder?: boolean
910
}
1011

1112
export default function FlowStepWrapper(props: FlowStepWrapperProps) {
12-
const { children, isNested } = props
13+
const { children, canChildStepsReorder, allowReorder } = props
1314
const isMobile = useIsMobile()
1415

1516
return (
1617
<Flex
1718
alignItems="center"
1819
display={isMobile ? 'block' : 'flex'}
1920
flexDir="column"
20-
w="100%"
21-
minW={isNested ? '100%' : MIN_FLOW_STEP_WIDTH}
21+
w={
22+
canChildStepsReorder && !allowReorder && !isMobile
23+
? `calc(100% - ${NESTED_DRAG_HANDLE_WIDTH}px)`
24+
: '100%'
25+
}
2226
>
2327
{children}
2428
</Flex>

packages/frontend/src/components/FlowStep/index.tsx

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,20 @@ type FlowStepProps = {
3535
isLastStep: boolean
3636
isNested?: boolean
3737
allowReorder?: boolean
38+
// we use this to control the width of condition steps in if-then and for-each
39+
canChildStepsReorder?: boolean
3840
}
3941

4042
export default function FlowStep(
4143
props: FlowStepProps,
4244
): React.ReactElement | null {
43-
const { step, isLastStep, isNested, allowReorder = true } = props
45+
const {
46+
step,
47+
isLastStep,
48+
isNested,
49+
allowReorder = true,
50+
canChildStepsReorder = false,
51+
} = props
4452

4553
const {
4654
isOpen: isModalOpen,
@@ -67,11 +75,11 @@ export default function FlowStep(
6775
app,
6876
caption,
6977
isCompleted,
70-
isIfThenStep,
7178
isTrigger,
7279
selectedActionOrTrigger,
7380
substeps,
74-
} = useStepMetadata(allApps, step)
81+
shouldShowDragHandle,
82+
} = useStepMetadata(allApps, step, readOnly, allowReorder, isMobile)
7583

7684
const {
7785
cancelRef,
@@ -140,19 +148,6 @@ export default function FlowStep(
140148
}
141149
}
142150

143-
/**
144-
* NOTE: there are various conditions that determine whether the drag handle
145-
* should be shown.
146-
*
147-
* - not read only
148-
* - not in mobile view
149-
* - step is not a trigger
150-
* - step is not an if-then condition step
151-
* - allowReorder is true
152-
*/
153-
const shouldShowDragHandle =
154-
!readOnly && !isTrigger && !isMobile && !isIfThenStep && allowReorder
155-
156151
const headerWidth = getFlowStepHeaderWidth(isDrawerOpen, isMobile, isNested)
157152

158153
// generate help message only if template config exists
@@ -178,7 +173,10 @@ export default function FlowStep(
178173
}
179174

180175
return (
181-
<FlowStepWrapper isNested={isNested}>
176+
<FlowStepWrapper
177+
canChildStepsReorder={canChildStepsReorder}
178+
allowReorder={allowReorder}
179+
>
182180
{!app ? (
183181
<EmptyFlowStepHeader
184182
isNested={isNested}
@@ -191,9 +189,7 @@ export default function FlowStep(
191189
) : (
192190
<Flex flexDir="row" w="100%">
193191
<Flex
194-
alignItems={
195-
isNested && !shouldShowDragHandle ? 'flex-start' : 'center'
196-
}
192+
alignItems={isNested ? 'flex-start' : 'center'}
197193
justifyContent="center"
198194
flexDir="column"
199195
flex="1"

packages/frontend/src/components/FlowStepGroup/Content/ForEach/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export default function ForEach(props: ForEachProps) {
7272
isLastStep={false}
7373
allowReorder={false}
7474
showEmptyAction={hasNoActionSteps}
75+
canChildStepsReorder={actionSteps.length > 1}
7576
/>
7677
<SortableList
7778
items={actionSteps.map((step, index) => ({
@@ -92,7 +93,7 @@ export default function ForEach(props: ForEachProps) {
9293
canAddStep={true}
9394
isLastStep={isLastStep}
9495
isOverlay={isOverlay}
95-
allowReorder={true}
96+
allowReorder={actionSteps.length > 1}
9697
/>
9798
</Flex>
9899
</SortableList.Item>

packages/frontend/src/components/FlowStepGroup/Content/IfThen/Branch.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ export default function Branch(props: BranchProps) {
203203
step={conditionStep}
204204
canAddStep={canAddStep}
205205
isLastStep={false}
206+
allowReorder={false}
207+
canChildStepsReorder={actionSteps.length > 1}
206208
/>
207209
<SortableList
208210
items={actionSteps.map((step, index) => ({

packages/frontend/src/components/FlowStepGroup/Content/IfThen/HoverAddStepButton.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
import { useState } from 'react'
1+
import { IStep } from '@plumber/types'
2+
3+
import { useContext, useState } from 'react'
24
import { BiPlus } from 'react-icons/bi'
35
import { Divider, Flex, IconButton, useDisclosure } from '@chakra-ui/react'
46

57
import UnsavedChangesAlert from '@/components/Editor/UnsavedChangesAlert'
68
import EmptyFlowStepHeader from '@/components/EmptyFlowStepHeader'
79
import FlowStepConfigurationModal from '@/components/FlowStepConfigurationModal'
10+
import { NESTED_DRAG_HANDLE_WIDTH } from '@/components/SortableList/components/SortableItem'
11+
import { EditorContext } from '@/contexts/Editor'
12+
import { useStepMetadata } from '@/hooks/useStepMetadata'
813
import { useUnsavedChanges } from '@/hooks/useUnsavedChanges'
914

1015
import { hoverAddStepButtonStyles as styles } from './styles'
@@ -15,15 +20,35 @@ interface HoverAddStepButtonProps {
1520
isLastStep: boolean
1621
prevStepId: string
1722
showEmptyAction?: boolean
23+
step: IStep
24+
allowReorder?: boolean
25+
canChildStepsReorder?: boolean
1826
}
1927

2028
export function HoverAddStepButton(
2129
props: HoverAddStepButtonProps,
2230
): JSX.Element {
23-
const { isDisabled, isLastStep, prevStepId, showEmptyAction } = props
31+
const {
32+
isDisabled,
33+
isLastStep,
34+
prevStepId,
35+
showEmptyAction,
36+
step,
37+
allowReorder,
38+
canChildStepsReorder,
39+
} = props
2440
const { isOpen, onOpen, onClose } = useDisclosure()
2541
const [isHovered, setIsHovered] = useState(false)
2642

43+
const { allApps, readOnly, isMobile } = useContext(EditorContext)
44+
const { shouldShowDragHandle } = useStepMetadata(
45+
allApps,
46+
step,
47+
readOnly,
48+
allowReorder,
49+
isMobile,
50+
)
51+
2752
const {
2853
cancelRef,
2954
isWarningOpen,
@@ -55,6 +80,11 @@ export function HoverAddStepButton(
5580
pointerEvents={isDisabled ? 'none' : 'auto'}
5681
onMouseEnter={() => setIsHovered(true)}
5782
onMouseLeave={() => setIsHovered(false)}
83+
w={
84+
(shouldShowDragHandle || canChildStepsReorder) && !isMobile
85+
? `calc(100% - ${NESTED_DRAG_HANDLE_WIDTH}px)`
86+
: 'full'
87+
}
5888
>
5989
{/* vertical line */}
6090
{!isLastStep && (

packages/frontend/src/components/FlowStepGroup/Content/IfThen/styles.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,6 @@ export const hoverAddStepButtonStyles = {
6262
variant: 'clear',
6363
size: 'xs',
6464
borderRadius: 'lg',
65+
left: 0,
6566
},
6667
}

packages/frontend/src/components/FlowStepGroup/components/GroupStepWithAddButton.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useContext } from 'react'
44

55
import { EditorContext } from '@/contexts/Editor'
66
import { FlowStep } from '@/exports/components'
7-
import { TOOLBOX_ACTIONS, TOOLBOX_APP_KEY } from '@/helpers/toolbox'
7+
import { TOOLBOX_ACTIONS } from '@/helpers/toolbox'
88

99
import { HoverAddStepButton } from '../Content/IfThen/HoverAddStepButton'
1010

@@ -15,6 +15,7 @@ interface GroupStepWithAddButtonProps {
1515
isOverlay?: boolean
1616
allowReorder?: boolean
1717
showEmptyAction?: boolean
18+
canChildStepsReorder?: boolean
1819
}
1920

2021
export default function GroupStepWithAddButton(
@@ -27,14 +28,13 @@ export default function GroupStepWithAddButton(
2728
isOverlay,
2829
allowReorder,
2930
showEmptyAction,
31+
canChildStepsReorder,
3032
} = props
3133
const { isDrawerOpen, readOnly } = useContext(EditorContext)
3234

3335
// cannot delete the condition step
3436
const isDeletable =
35-
step.appKey !== TOOLBOX_APP_KEY &&
36-
step.key !== TOOLBOX_ACTIONS.IfThen &&
37-
step.key !== TOOLBOX_ACTIONS.ForEach
37+
step.key !== TOOLBOX_ACTIONS.IfThen && step.key !== TOOLBOX_ACTIONS.ForEach
3838

3939
return (
4040
<>
@@ -45,6 +45,7 @@ export default function GroupStepWithAddButton(
4545
isNested={true}
4646
isLastStep={isLastStep}
4747
allowReorder={allowReorder}
48+
canChildStepsReorder={canChildStepsReorder}
4849
/>
4950
{!isOverlay && (
5051
<HoverAddStepButton
@@ -53,6 +54,9 @@ export default function GroupStepWithAddButton(
5354
isLastStep={isLastStep}
5455
prevStepId={step.id}
5556
showEmptyAction={showEmptyAction}
57+
step={step}
58+
allowReorder={allowReorder}
59+
canChildStepsReorder={canChildStepsReorder}
5660
/>
5761
)}
5862
</>

packages/frontend/src/components/FlowStepGroup/index.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { BiTrash } from 'react-icons/bi'
55
import { Box, Flex, Icon, Text } from '@chakra-ui/react'
66
import { IconButton } from '@opengovsg/design-system-react'
77

8+
import { NESTED_DRAG_HANDLE_WIDTH } from '@/components/SortableList/components/SortableItem'
89
import { EditorContext } from '@/contexts/Editor'
910
import { getFlowStepHeaderWidth, getToolboxIcon } from '@/helpers/editor'
1011
import { TOOLBOX_ACTIONS } from '@/helpers/toolbox'
@@ -62,9 +63,20 @@ export default function FlowStepGroup(props: FlowStepGroupProps) {
6263
onDrawerClose()
6364
}, [deleteForEach, onDrawerClose])
6465

66+
// NOTE: we check if its inside the for-each
67+
// so that if-then steps follow the same width of the nested actions
68+
// when the drag handle is shown
69+
const isInsideForEach = stepsBeforeGroup.some(
70+
(step) => step.key === TOOLBOX_ACTIONS.ForEach,
71+
)
72+
6573
return (
6674
<Flex
67-
w="100%"
75+
w={
76+
isInsideForEach && stepsBeforeGroup.length > 2
77+
? `calc(100% - ${NESTED_DRAG_HANDLE_WIDTH}px)`
78+
: '100%'
79+
}
6880
alignItems="center"
6981
justifyContent={isDrawerOpen ? 'flex-start' : 'center'}
7082
>

packages/frontend/src/components/SortableList/SortableList.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@
44
padding: 0;
55
list-style: none;
66
}
7+
8+
/* Force cursor during active drag */
9+
body.is-dragging,
10+
body.is-dragging * {
11+
cursor: grabbing !important;
12+
}

packages/frontend/src/components/SortableList/components/SortableItem/SortableItem.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
justify-content: center;
2020
flex: 0 0 auto;
2121
touch-action: none;
22-
cursor: var(--cursor, pointer);
22+
cursor: var(--cursor, grab);
2323
border-radius: 5px;
2424
border: none;
2525
outline: none;

0 commit comments

Comments
 (0)