Skip to content

Commit 2849b28

Browse files
authored
Open grid template row/col inspector menu with right click on title (#6573)
**Problem:** It should be possible to open the dropdown/context menu for grid template rows/cols in the inspector by right-clicking the item's title. **Fix:** Add an invisible context menu in the title component and trigger it conditionally by right clicking the title itself. This solution works better than conditionally opening the same dropdown menu as the three dots button because it will correctly position it. https://github.com/user-attachments/assets/2c25fc94-b039-4423-9a3f-0c6e0f71b562 Fixes #6572
1 parent 5195936 commit 2849b28

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

editor/src/components/inspector/flex-section.tsx

+33-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import { jsx } from '@emotion/react'
55
import React from 'react'
66
import { createSelector } from 'reselect'
7-
import { unless, when } from '../../utils/react-conditionals'
7+
import { when } from '../../utils/react-conditionals'
88
import { Substores, useEditorState, useRefEditorState } from '../editor/store/store-hook'
99
import { AddRemoveLayoutSystemControl } from './add-remove-layout-system-control'
1010
import { FlexDirectionToggle } from './flex-direction-control'
@@ -554,9 +554,15 @@ function AxisDimensionControl({
554554
opener: (isOpen: boolean) => React.ReactElement
555555
}) {
556556
const testId = `grid-dimension-${axis}-${index}`
557-
const [isOpen, setIsOpen] = React.useState(false)
558-
const onOpenChange = React.useCallback((isDropdownOpen: boolean) => {
559-
setIsOpen(isDropdownOpen)
557+
const [isDotsMenuOpen, setDotsMenuOpen] = React.useState(false)
558+
const [isTitleMenuOpen, setTitleMenuOpen] = React.useState(false)
559+
560+
const onOpenChangeDotsMenu = React.useCallback((isDropdownOpen: boolean) => {
561+
setDotsMenuOpen(isDropdownOpen)
562+
}, [])
563+
564+
const onOpenChangeTitleMenu = React.useCallback(() => {
565+
setTitleMenuOpen(false)
560566
}, [])
561567

562568
const isDynamic = React.useMemo(() => {
@@ -584,6 +590,14 @@ function AxisDimensionControl({
584590
setIsHovered(false)
585591
}, [])
586592

593+
const onContextMenuTitle = React.useCallback((e: React.MouseEvent) => {
594+
e.preventDefault()
595+
e.stopPropagation()
596+
setTitleMenuOpen(true)
597+
}, [])
598+
599+
const invisibleOpener = React.useCallback(() => null, [])
600+
587601
return (
588602
<div
589603
key={`col-${value}-${index}`}
@@ -611,8 +625,16 @@ function AxisDimensionControl({
611625
whiteSpace: 'nowrap',
612626
}}
613627
title={isDynamic ? dynamicIndexTitle : undefined}
628+
onContextMenu={onContextMenuTitle}
614629
>
615630
{title}
631+
<DropdownMenu
632+
align='start'
633+
items={items}
634+
opener={invisibleOpener}
635+
onOpenChange={onOpenChangeTitleMenu}
636+
forceOpen={isTitleMenuOpen}
637+
/>
616638
</Subdued>
617639
<GridExpressionInput
618640
testId={testId}
@@ -625,9 +647,14 @@ function AxisDimensionControl({
625647
defaultValue={gridCSSKeyword(cssKeyword('auto'), null)}
626648
/>
627649
{when(
628-
(isHovered && !gridExpressionInputFocused.focused) || isOpen,
650+
(isHovered && !gridExpressionInputFocused.focused) || isDotsMenuOpen,
629651
<SquareButton>
630-
<DropdownMenu align='end' items={items} opener={opener} onOpenChange={onOpenChange} />
652+
<DropdownMenu
653+
align='end'
654+
items={items}
655+
opener={opener}
656+
onOpenChange={onOpenChangeDotsMenu}
657+
/>
631658
</SquareButton>,
632659
)}
633660
</div>

editor/src/uuiui/radix-components.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Icons, SmallerIcons } from './icons'
1111
import { when } from '../utils/react-conditionals'
1212
import { Icn, type IcnProps } from './icn'
1313
import { forceNotNull } from '../core/shared/optional-utils'
14+
import { usePropControlledStateV2 } from '../components/inspector/common/inspector-utils'
1415

1516
// Keep this in sync with the radix-components-portal div in index.html.
1617
export const RadixComponentsPortalId = 'radix-components-portal'
@@ -90,6 +91,7 @@ export interface DropdownMenuProps {
9091
alignOffset?: number
9192
onOpenChange?: (open: boolean) => void
9293
style?: CSSProperties
94+
forceOpen?: boolean
9395
}
9496

9597
export const ItemContainerTestId = (id: string) => `item-container-${id}`
@@ -103,7 +105,7 @@ export const DropdownMenu = React.memo<DropdownMenuProps>((props) => {
103105
}, [])
104106
const onEscapeKeyDown = React.useCallback((e: KeyboardEvent) => e.stopPropagation(), [])
105107

106-
const [open, setOpen] = React.useState(false)
108+
const [open, setOpen] = usePropControlledStateV2(props.forceOpen || false)
107109

108110
const shouldShowCheckboxes = props.items.some(
109111
(i) => !isSeparatorDropdownMenuItem(i) && i.checked != null,

0 commit comments

Comments
 (0)