From 91794f550d67f6afb742f98a770f1235a745fe9d Mon Sep 17 00:00:00 2001 From: Cole Lawrence Date: Wed, 27 Apr 2022 14:38:13 -0400 Subject: [PATCH] refactor/docs: Minor identifier tweaks for RightClick/ContextMenu --- .../propEditors/utils/SingleRowPropEditor.tsx | 2 +- .../BasicKeyframedTrack.tsx | 5 ++- .../KeyframeEditor/Connector.tsx | 4 +- .../{Dot.tsx => KeyframeDot.tsx} | 42 ++++++++++++------- .../KeyframeEditor/KeyframeEditor.tsx | 10 +++-- .../KeyframeEditor/Curve.tsx | 2 +- .../KeyframeEditor/CurveHandle.tsx | 2 +- .../GraphEditorDotNonScalar.tsx | 2 +- .../KeyframeEditor/GraphEditorDotScalar.tsx | 2 +- .../FocusRangeZone/FocusRangeStrip.tsx | 3 +- .../RightOverlay/HorizontalScrollbar.tsx | 2 +- .../ContextMenu.tsx} | 28 ++++++++----- .../{RightClickMenu => ContextMenu}/Item.tsx | 10 ++--- .../simpleContextMenu/useContextMenu.tsx | 32 ++++++++------ .../useRequestContextMenu.ts | 15 ++++--- 15 files changed, 99 insertions(+), 62 deletions(-) rename theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/{Dot.tsx => KeyframeDot.tsx} (88%) rename theatre/studio/src/uiComponents/simpleContextMenu/{RightClickMenu/RightClickMenu.tsx => ContextMenu/ContextMenu.tsx} (83%) rename theatre/studio/src/uiComponents/simpleContextMenu/{RightClickMenu => ContextMenu}/Item.tsx (85%) diff --git a/theatre/studio/src/panels/DetailPanel/propEditors/utils/SingleRowPropEditor.tsx b/theatre/studio/src/panels/DetailPanel/propEditors/utils/SingleRowPropEditor.tsx index 8c93d11..bb31e1a 100644 --- a/theatre/studio/src/panels/DetailPanel/propEditors/utils/SingleRowPropEditor.tsx +++ b/theatre/studio/src/panels/DetailPanel/propEditors/utils/SingleRowPropEditor.tsx @@ -119,7 +119,7 @@ export const SingleRowPropEditor: React.FC<{ useRefAndState(null) const [contextMenu] = useContextMenu(propNameContainer, { - items: stuff.contextMenuItems, + menuItems: stuff.contextMenuItems, }) const color = shadeToColor[stuff.shade] diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/BasicKeyframedTrack.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/BasicKeyframedTrack.tsx index c35f0a0..e843d6d 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/BasicKeyframedTrack.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/BasicKeyframedTrack.tsx @@ -8,6 +8,7 @@ import {val} from '@theatre/dataverse' import React from 'react' import styled from 'styled-components' import KeyframeEditor from './KeyframeEditor/KeyframeEditor' +import type {IContextMenuItem} from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu' import useContextMenu from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu' import useRefAndState from '@theatre/studio/utils/useRefAndState' import getStudio from '@theatre/studio/getStudio' @@ -85,7 +86,7 @@ function useBasicKeyframedTrackContextMenu( props: BasicKeyframedTracksProps, ) { return useContextMenu(node, { - items: () => { + menuItems: () => { const selectionKeyframes = val(getStudio()!.atomP.ahistoric.clipboard.keyframes) || [] @@ -101,7 +102,7 @@ function useBasicKeyframedTrackContextMenu( function pasteKeyframesContextMenuItem( props: BasicKeyframedTracksProps, keyframes: Keyframe[], -) { +): IContextMenuItem { return { label: 'Paste Keyframes', callback: () => { diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Connector.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Connector.tsx index ae2dbc0..ff83b56 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Connector.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Connector.tsx @@ -12,7 +12,7 @@ import type { SequenceEditorPanelLayout, DopeSheetSelection, } from '@theatre/studio/panels/SequenceEditorPanel/layout/layout' -import {DOT_SIZE_PX} from './Dot' +import {DOT_SIZE_PX} from './KeyframeDot' import type KeyframeEditor from './KeyframeEditor' import type Sequence from '@theatre/core/sequences/Sequence' import usePopover from '@theatre/studio/uiComponents/Popover/usePopover' @@ -250,7 +250,7 @@ function useConnectorContextMenu( ) { const maybeKeyframeIds = selectedKeyframeIdsIfInSingleTrack(props.selection) return useContextMenu(node, { - items: () => { + menuItems: () => { return [ { label: maybeKeyframeIds ? 'Copy Selection' : 'Copy both Keyframes', diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeDot.tsx similarity index 88% rename from theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx rename to theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeDot.tsx index 6eee3fe..1188ebe 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/Dot.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeDot.tsx @@ -5,13 +5,14 @@ import type { import getStudio from '@theatre/studio/getStudio' import type {CommitOrDiscard} from '@theatre/studio/StudioStore/StudioStore' import useContextMenu from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu' +import type {IContextMenuItem} from '@theatre/studio/uiComponents/simpleContextMenu/useContextMenu' import useDrag from '@theatre/studio/uiComponents/useDrag' +import type {UseDragOpts} from '@theatre/studio/uiComponents/useDrag' import useRefAndState from '@theatre/studio/utils/useRefAndState' import {val} from '@theatre/dataverse' import {lighten} from 'polished' import React, {useMemo, useRef, useState} from 'react' import styled from 'styled-components' -import type KeyframeEditor from './KeyframeEditor' import {useLockFrameStampPosition} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' import {attributeNameThatLocksFramestamp} from '@theatre/studio/panels/SequenceEditorPanel/FrameStampPositionProvider' import { @@ -20,6 +21,7 @@ import { } from '@theatre/studio/uiComponents/PointerEventsHandler' import SnapCursor from './SnapCursor.svg' import selectedKeyframeIdsIfInSingleTrack from '@theatre/studio/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/selectedKeyframeIdsIfInSingleTrack' +import type {IKeyframeEditorProps} from './KeyframeEditor' export const DOT_SIZE_PX = 6 const HIT_ZONE_SIZE_PX = 12 @@ -42,6 +44,8 @@ const dotTheme = { const Square = styled.div<{isSelected: boolean}>` position: absolute; + ${dims(DOT_SIZE_PX)} + background: ${(props) => props.isSelected ? dotTheme.selectedColor : dotTheme.normalColor}; transform: rotateZ(45deg); @@ -85,13 +89,14 @@ const HitZone = styled.div` } ` -type IProps = Parameters[0] +type IKeyframeDotProps = IKeyframeEditorProps -const Dot: React.FC = (props) => { +/** The ◆ you can grab onto in "keyframe editor" (aka "dope sheet" in other programs) */ +const KeyframeDot: React.FC = (props) => { const [ref, node] = useRefAndState(null) - const [contextMenu] = useKeyframeContextMenu(node, props) const [isDragging] = useDragKeyframe(node, props) + const [contextMenu] = useKeyframeContextMenu(node, props) return ( <> @@ -110,9 +115,12 @@ const Dot: React.FC = (props) => { ) } -export default Dot +export default KeyframeDot -function useKeyframeContextMenu(node: HTMLDivElement | null, props: IProps) { +function useKeyframeContextMenu( + target: HTMLDivElement | null, + props: IKeyframeDotProps, +) { const maybeSelectedKeyframeIds = selectedKeyframeIdsIfInSingleTrack( props.selection, ) @@ -123,8 +131,8 @@ function useKeyframeContextMenu(node: HTMLDivElement | null, props: IProps) { const deleteItem = deleteSelectionOrKeyframeContextMenuItem(props) - return useContextMenu(node, { - items: () => { + return useContextMenu(target, { + menuItems: () => { return [keyframeSelectionItem, deleteItem] }, }) @@ -132,7 +140,7 @@ function useKeyframeContextMenu(node: HTMLDivElement | null, props: IProps) { function useDragKeyframe( node: HTMLDivElement | null, - props: IProps, + props: IKeyframeDotProps, ): [isDragging: boolean] { const [isDragging, setIsDragging] = useState(false) useLockFrameStampPosition(isDragging, props.keyframe.position) @@ -140,10 +148,10 @@ function useDragKeyframe( const propsRef = useRef(props) propsRef.current = props - const gestureHandlers = useMemo[1]>(() => { + const useDragOpts = useMemo(() => { let toUnitSpace: SequenceEditorPanelLayout['scaledSpace']['toUnitSpace'] let tempTransaction: CommitOrDiscard | undefined - let propsAtStartOfDrag: IProps + let propsAtStartOfDrag: IKeyframeDotProps let selectionDragHandlers: | ReturnType @@ -151,6 +159,7 @@ function useDragKeyframe( return { debugName: 'Dot/useDragKeyframe', + onDragStart(event) { setIsDragging(true) const props = propsRef.current @@ -241,14 +250,16 @@ function useDragKeyframe( } }, []) - useDrag(node, gestureHandlers) + useDrag(node, useDragOpts) useCssCursorLock(isDragging, 'draggingPositionInSequenceEditor', 'ew-resize') return [isDragging] } -function deleteSelectionOrKeyframeContextMenuItem(props: IProps) { +function deleteSelectionOrKeyframeContextMenuItem( + props: IKeyframeDotProps, +): IContextMenuItem { return { label: props.selection ? 'Delete Selection' : 'Delete Keyframe', callback: () => { @@ -269,7 +280,10 @@ function deleteSelectionOrKeyframeContextMenuItem(props: IProps) { } } -function copyKeyFrameContextMenuItem(props: IProps, keyframeIds: string[]) { +function copyKeyFrameContextMenuItem( + props: IKeyframeDotProps, + keyframeIds: string[], +): IContextMenuItem { return { label: keyframeIds.length > 1 ? 'Copy selection' : 'Copy keyframe', callback: () => { diff --git a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeEditor.tsx b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeEditor.tsx index 3d62159..ec283e0 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeEditor.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/DopeSheet/Right/BasicKeyframedTrack/KeyframeEditor/KeyframeEditor.tsx @@ -12,7 +12,7 @@ import {val} from '@theatre/dataverse' import React from 'react' import styled from 'styled-components' import Connector from './Connector' -import Dot from './Dot' +import KeyframeDot from './KeyframeDot' const Container = styled.div` position: absolute; @@ -20,14 +20,16 @@ const Container = styled.div` const noConnector = <> -const KeyframeEditor: React.FC<{ +export type IKeyframeEditorProps = { index: number keyframe: Keyframe trackData: TrackData layoutP: Pointer leaf: SequenceEditorTree_PrimitiveProp selection: undefined | DopeSheetSelection -}> = (props) => { +} + +const KeyframeEditor: React.FC = (props) => { const {index, trackData} = props const cur = trackData.keyframes[index] const next = trackData.keyframes[index + 1] @@ -45,7 +47,7 @@ const KeyframeEditor: React.FC<{ }px))`, }} > - + {connected ? : noConnector} ) diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Curve.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Curve.tsx index 2ab29e2..f313995 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Curve.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/Curve.tsx @@ -109,7 +109,7 @@ function useConnectorContextMenu(node: SVGElement | null, props: IProps) { const next = trackData.keyframes[index + 1] return useContextMenu(node, { - items: () => { + menuItems: () => { return [ { label: 'Delete', diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/CurveHandle.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/CurveHandle.tsx index 9ac66a2..4d7f9ea 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/CurveHandle.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/CurveHandle.tsx @@ -243,7 +243,7 @@ function useOurDrags(node: SVGCircleElement | null, props: IProps): void { function useOurContextMenu(node: SVGCircleElement | null, props: IProps) { return useContextMenu(node, { - items: () => { + menuItems: () => { return [ { label: 'Delete', diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx index cfdb22e..972bdb3 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotNonScalar.tsx @@ -181,7 +181,7 @@ function useDragKeyframe( function useKeyframeContextMenu(node: SVGCircleElement | null, props: IProps) { return useContextMenu(node, { - items: () => { + menuItems: () => { return [ { label: 'Delete', diff --git a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx index eabd276..b1b04d8 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/GraphEditor/BasicKeyframedTrack/KeyframeEditor/GraphEditorDotScalar.tsx @@ -235,7 +235,7 @@ function useDragKeyframe( function useKeyframeContextMenu(node: SVGCircleElement | null, props: IProps) { return useContextMenu(node, { - items: () => { + menuItems: () => { return [ { label: 'Delete', diff --git a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FocusRangeZone/FocusRangeStrip.tsx b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FocusRangeZone/FocusRangeStrip.tsx index e353b7a..b8ae20a 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FocusRangeZone/FocusRangeStrip.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/FocusRangeZone/FocusRangeStrip.tsx @@ -132,9 +132,8 @@ const FocusRangeStrip: React.FC<{ ) const [contextMenu] = useContextMenu(rangeStripNode, { - items: () => { + menuItems: () => { const sheet = val(layoutP.sheet) - const existingRange = existingRangeD.getValue() return [ { diff --git a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/HorizontalScrollbar.tsx b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/HorizontalScrollbar.tsx index 5c08758..f5b04ca 100644 --- a/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/HorizontalScrollbar.tsx +++ b/theatre/studio/src/panels/SequenceEditorPanel/RightOverlay/HorizontalScrollbar.tsx @@ -21,8 +21,8 @@ const Container = styled.div` width: 100%; left: 12px; /* bottom: 8px; */ - ${pointerEventsAutoInNormalMode}; z-index: ${() => zIndexes.horizontalScrollbar}; + ${pointerEventsAutoInNormalMode} ` const TimeThread = styled.div` diff --git a/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx b/theatre/studio/src/uiComponents/simpleContextMenu/ContextMenu/ContextMenu.tsx similarity index 83% rename from theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx rename to theatre/studio/src/uiComponents/simpleContextMenu/ContextMenu/ContextMenu.tsx index 8bfc560..f2faaf8 100644 --- a/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/RightClickMenu.tsx +++ b/theatre/studio/src/uiComponents/simpleContextMenu/ContextMenu/ContextMenu.tsx @@ -18,7 +18,7 @@ const minWidth = 190 */ const pointerDistanceThreshold = 20 -const Container = styled.ul` +const MenuContainer = styled.ul` position: absolute; min-width: ${minWidth}px; z-index: 10000; @@ -34,6 +34,10 @@ const Container = styled.ul` border-radius: 3px; ` +export type IContextMenuItemCustomNodeRenderFn = (controls: { + closeMenu(): void +}) => React.ReactChild + export type IContextMenuItem = { label: string | ElementType callback?: (e: React.MouseEvent) => void @@ -41,9 +45,13 @@ export type IContextMenuItem = { // subs?: Item[] } -const RightClickMenu: React.FC<{ - items: IContextMenuItem[] | (() => IContextMenuItem[]) - rightClickPoint: {clientX: number; clientY: number} +export type IContextMenuItemsValue = + | IContextMenuItem[] + | (() => IContextMenuItem[]) + +const ContextMenu: React.FC<{ + items: IContextMenuItemsValue + clickPoint: {clientX: number; clientY: number} onRequestClose: () => void }> = (props) => { const [container, setContainer] = useState(null) @@ -59,8 +67,8 @@ const RightClickMenu: React.FC<{ } const pos = { - left: props.rightClickPoint.clientX - preferredAnchorPoint.left, - top: props.rightClickPoint.clientY - preferredAnchorPoint.top, + left: props.clickPoint.clientX - preferredAnchorPoint.left, + top: props.clickPoint.clientY - preferredAnchorPoint.top, } if (pos.left < 0) { @@ -94,7 +102,7 @@ const RightClickMenu: React.FC<{ return () => { window.removeEventListener('mousemove', onMouseMove) } - }, [rect, container, props.rightClickPoint, windowSize, props.onRequestClose]) + }, [rect, container, props.clickPoint, windowSize, props.onRequestClose]) const portalLayer = useContext(PortalContext) useOnKeyDown((ev) => { @@ -104,7 +112,7 @@ const RightClickMenu: React.FC<{ const items = Array.isArray(props.items) ? props.items : props.items() return createPortal( - + {items.map((item, i) => ( ))} - , + , portalLayer!, ) } -export default RightClickMenu +export default ContextMenu diff --git a/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/Item.tsx b/theatre/studio/src/uiComponents/simpleContextMenu/ContextMenu/Item.tsx similarity index 85% rename from theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/Item.tsx rename to theatre/studio/src/uiComponents/simpleContextMenu/ContextMenu/Item.tsx index b7991cf..3312456 100644 --- a/theatre/studio/src/uiComponents/simpleContextMenu/RightClickMenu/Item.tsx +++ b/theatre/studio/src/uiComponents/simpleContextMenu/ContextMenu/Item.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components' export const height = 26 -const Container = styled.li<{enabled: boolean}>` +const ItemContainer = styled.li<{enabled: boolean}>` height: ${height}px; padding: 0 12px; margin: 0; @@ -32,7 +32,7 @@ const Container = styled.li<{enabled: boolean}>` } ` -const Label = styled.span`` +const ItemLabel = styled.span`` const Item: React.FC<{ label: string | ElementType @@ -40,12 +40,12 @@ const Item: React.FC<{ enabled: boolean }> = (props) => { return ( - - - + {props.label} + ) } diff --git a/theatre/studio/src/uiComponents/simpleContextMenu/useContextMenu.tsx b/theatre/studio/src/uiComponents/simpleContextMenu/useContextMenu.tsx index eb25d10..904401f 100644 --- a/theatre/studio/src/uiComponents/simpleContextMenu/useContextMenu.tsx +++ b/theatre/studio/src/uiComponents/simpleContextMenu/useContextMenu.tsx @@ -1,28 +1,36 @@ import type {VoidFn} from '@theatre/shared/utils/types' import React from 'react' -import RightClickMenu from './RightClickMenu/RightClickMenu' +import ContextMenu from './ContextMenu/ContextMenu' +import type { + IContextMenuItemsValue, + IContextMenuItem, +} from './ContextMenu/ContextMenu' import useRequestContextMenu from './useRequestContextMenu' -export type {IContextMenuItem} from './RightClickMenu/RightClickMenu' +import type {IRequestContextMenuOptions} from './useRequestContextMenu' + +// re-exports +export type { + IContextMenuItemsValue, + IContextMenuItem, + IRequestContextMenuOptions, +} const emptyNode = <> -type IProps = Omit< - Parameters[0], - 'rightClickPoint' | 'onRequestClose' -> - export default function useContextMenu( target: HTMLElement | SVGElement | null, - props: IProps, + opts: IRequestContextMenuOptions & { + menuItems: IContextMenuItemsValue + }, ): [node: React.ReactNode, close: VoidFn, isOpen: boolean] { - const [status, close] = useRequestContextMenu(target) + const [status, close] = useRequestContextMenu(target, opts) const node = !status.isOpen ? ( emptyNode ) : ( - ) diff --git a/theatre/studio/src/uiComponents/simpleContextMenu/useRequestContextMenu.ts b/theatre/studio/src/uiComponents/simpleContextMenu/useRequestContextMenu.ts index 37d892e..66b0a68 100644 --- a/theatre/studio/src/uiComponents/simpleContextMenu/useRequestContextMenu.ts +++ b/theatre/studio/src/uiComponents/simpleContextMenu/useRequestContextMenu.ts @@ -5,28 +5,33 @@ type IState = {isOpen: true; event: MouseEvent} | {isOpen: false} type CloseMenuFn = () => void +export type IRequestContextMenuOptions = { + disabled?: boolean +} + const useRequestContextMenu = ( target: HTMLElement | SVGElement | null, + opts: IRequestContextMenuOptions, ): [state: IState, close: CloseMenuFn] => { const [state, setState] = useState({isOpen: false}) const close = useCallback(() => setState({isOpen: false}), []) useEffect(() => { - if (!target) { + if (!target || opts.disabled === true) { setState({isOpen: false}) return } - const onContextMenu = (event: MouseEvent) => { + const onTrigger = (event: MouseEvent) => { setState({isOpen: true, event}) event.preventDefault() event.stopPropagation() } - target.addEventListener('contextmenu', onContextMenu as $FixMe) + target.addEventListener('contextmenu', onTrigger as $FixMe) return () => { - target.removeEventListener('contextmenu', onContextMenu as $FixMe) + target.removeEventListener('contextmenu', onTrigger as $FixMe) } - }, [target]) + }, [target, opts.disabled]) return [state, close] }