Skip to content

Commit

Permalink
feat(vscode): add context menu in preview panel
Browse files Browse the repository at this point in the history
  • Loading branch information
davydkov committed Sep 15, 2023
1 parent 92c3dbd commit 8b19661
Show file tree
Hide file tree
Showing 14 changed files with 193 additions and 94 deletions.
4 changes: 3 additions & 1 deletion packages/diagrams/src/diagram/Compounds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ type CompoundsProps = {
animate: boolean
diagram: DiagramView
theme: LikeC4Theme
onNodeContextMenu?: OnNodeClick | undefined
onNodeClick?: OnNodeClick | undefined
}

const keyOf = (node: DiagramNode) => node.id

export function Compounds({ animate, theme, diagram, onNodeClick }: CompoundsProps) {
export function Compounds({ animate, theme, diagram, onNodeClick, onNodeContextMenu }: CompoundsProps) {
const nodes = diagram.nodes.filter(isCompound)
const compoundTransitions = useTransition(nodes, {
initial: nodeSprings(),
Expand Down Expand Up @@ -60,6 +61,7 @@ export function Compounds({ animate, theme, diagram, onNodeClick }: CompoundsPro
theme={theme}
springs={springs}
onNodeClick={onNodeClick}
onNodeContextMenu={onNodeContextMenu}
/>
))
}
22 changes: 20 additions & 2 deletions packages/diagrams/src/diagram/Diagram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ export const Diagram = /* @__PURE__ */ forwardRef<DiagramApi, DiagramProps>(
initialPosition,
onEdgeClick,
onNodeClick,
onNodeContextMenu,
onStageClick,
onStageContextMenu,
width: _width,
height: _height,
...props
Expand Down Expand Up @@ -176,6 +178,11 @@ export const Diagram = /* @__PURE__ */ forwardRef<DiagramApi, DiagramProps>(
theme,
diagram
}
const nodeSharedProps = {
...sharedProps,
onNodeClick,
onNodeContextMenu
}

return (
<AnimatedStage
Expand All @@ -188,6 +195,17 @@ export const Diagram = /* @__PURE__ */ forwardRef<DiagramApi, DiagramProps>(
y={stageProps.y}
scaleX={stageProps.scale}
scaleY={stageProps.scale}
{...(onStageContextMenu && {
onContextMenu: e => {
if (KonvaCore.isDragging() || !stageRef.current) {
return
}
if (e.target === stageRef.current) {
e.cancelBubble = true
onStageContextMenu(stageRef.current, e)
}
}
})}
{...(onStageClick && {
onPointerClick: e => {
if (KonvaCore.isDragging() || !stageRef.current) {
Expand All @@ -213,11 +231,11 @@ export const Diagram = /* @__PURE__ */ forwardRef<DiagramApi, DiagramProps>(
{...props}
>
<Layer>
<Compounds {...sharedProps} onNodeClick={onNodeClick} />
<Compounds {...nodeSharedProps} />
<Edges {...sharedProps} onEdgeClick={onEdgeClick} />
</Layer>
<Layer>
<Nodes {...sharedProps} onNodeClick={onNodeClick} />
<Nodes {...nodeSharedProps} />
</Layer>
</AnimatedStage>
)
Expand Down
9 changes: 5 additions & 4 deletions packages/diagrams/src/diagram/Nodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ type NodesProps = {
animate: boolean
diagram: DiagramView
theme: LikeC4Theme
onNodeContextMenu?: OnNodeClick | undefined
onNodeClick?: OnNodeClick | undefined
}

const keyOf = (node: DiagramNode) =>
(node.parent ? node.parent + '-' : '') + node.id + '-' + node.shape
const keyOf = (node: DiagramNode) => (node.parent ? node.parent + '-' : '') + node.id + '-' + node.shape

export function Nodes({ animate, theme, diagram, onNodeClick }: NodesProps) {
export function Nodes({ animate, theme, diagram, onNodeClick, onNodeContextMenu }: NodesProps) {
const nodes = diagram.nodes.filter(hasNoChildren)
const nodeTransitions = useTransition(nodes, {
initial: nodeSprings(),
Expand Down Expand Up @@ -66,7 +66,8 @@ export function Nodes({ animate, theme, diagram, onNodeClick }: NodesProps) {
{...nodeListeners({
node,
ctrl,
onNodeClick
onNodeClick,
onNodeContextMenu
})}
/>
)
Expand Down
30 changes: 24 additions & 6 deletions packages/diagrams/src/diagram/shapes/Compound.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ interface CompoundProps {
node: DiagramNode
theme: DiagramTheme
springs: NodeSpringValues
onNodeContextMenu?: OnNodeClick | undefined
onNodeClick?: OnNodeClick | undefined
}

export function CompoundShape({ id, node, theme, springs, onNodeClick }: CompoundProps) {
export function CompoundShape({ id, node, theme, springs, onNodeClick, onNodeContextMenu }: CompoundProps) {
const { color, labels } = node
const colors = theme.colors[color]

Expand All @@ -26,9 +27,17 @@ export function CompoundShape({ id, node, theme, springs, onNodeClick }: Compoun
l: -15
})

const listeners = {}
if (onNodeClick) {
Object.assign(listeners, {
const listeners = Object.assign(
{},
onNodeContextMenu && {
onContextMenu: (e: KonvaPointerEvent) => {
if (KonvaCore.isDragging()) {
return
}
onNodeContextMenu(node, e)
}
},
onNodeClick && {
onPointerEnter: (e: KonvaPointerEvent) => {
mousePointer(e)
},
Expand All @@ -42,8 +51,9 @@ export function CompoundShape({ id, node, theme, springs, onNodeClick }: Compoun
evt.cancelBubble = true
onNodeClick(node, evt)
}
})
}
}
)

return (
<AnimatedGroup id={id} {...springs}>
<AnimatedRect
Expand All @@ -58,6 +68,14 @@ export function CompoundShape({ id, node, theme, springs, onNodeClick }: Compoun
height={springs.height}
fill={fill}
strokeEnabled={false}
{...(onNodeContextMenu && {
onContextMenu: (e: KonvaPointerEvent) => {
if (KonvaCore.isDragging()) {
return
}
onNodeContextMenu(node, e)
}
})}
/>
{labels.map(label => (
<Text
Expand Down
83 changes: 47 additions & 36 deletions packages/diagrams/src/diagram/shapes/nodeEvents.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,62 @@
import { config } from '@react-spring/konva'
import { KonvaCore } from '../../konva'
import type { OnNodeClick, KonvaPointerEvent, DiagramNode } from '../types'
import { mouseDefault, mousePointer } from './utils'
import type { NodeSpringsCtrl } from '../springs'
import { config } from '@react-spring/konva'
import type { DiagramNode, KonvaPointerEvent, OnNodeClick } from '../types'
import { mouseDefault, mousePointer } from './utils'
import type { KonvaNodeEvents } from 'react-konva'

export function nodeListeners({
node,
ctrl,
onNodeContextMenu,
onNodeClick
}: {
node: DiagramNode
ctrl: NodeSpringsCtrl
onNodeContextMenu?: OnNodeClick | undefined
onNodeClick?: OnNodeClick | undefined
}) {
if (!onNodeClick) {
return {} as const
}
return {
onPointerEnter: (e: KonvaPointerEvent) => {
mousePointer(e)
void ctrl.start({
to: {
scaleX: 1.08,
scaleY: 1.08
},
default: false,
config: config.stiff
})
},
onPointerLeave: (e: KonvaPointerEvent) => {
mouseDefault(e)
void ctrl.start({
to: {
scaleX: 1,
scaleY: 1
},
default: false,
delay: 120,
config: config.slow
})
}): KonvaNodeEvents {
return Object.assign(
{},
onNodeContextMenu && {
onContextMenu: (e: KonvaPointerEvent) => {
if (KonvaCore.isDragging()) {
return
}
onNodeContextMenu(node, e)
}
},
onPointerClick: (e: KonvaPointerEvent) => {
if (KonvaCore.isDragging()) {
return
onNodeClick && {
onPointerEnter: (e: KonvaPointerEvent) => {
mousePointer(e)
void ctrl.start({
to: {
scaleX: 1.08,
scaleY: 1.08
},
default: false,
config: config.stiff
})
},
onPointerLeave: (e: KonvaPointerEvent) => {
mouseDefault(e)
void ctrl.start({
to: {
scaleX: 1,
scaleY: 1
},
default: false,
delay: 120,
config: config.slow
})
},
onPointerClick: (e: KonvaPointerEvent) => {
if (KonvaCore.isDragging()) {
return
}
e.cancelBubble = true
onNodeClick(node, e)
}
e.cancelBubble = true
onNodeClick(node, e)
}
} as const
)
}
2 changes: 2 additions & 0 deletions packages/diagrams/src/diagram/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ export interface DiagramProps extends Pick<HTMLAttributes<HTMLDivElement>, 'clas
initialPosition?: DiagramInitialPosition | undefined

onNodeClick?: OnNodeClick | undefined
onNodeContextMenu?: OnNodeClick | undefined
onStageClick?: OnStageClick | undefined
onStageContextMenu?: OnStageClick | undefined
onEdgeClick?: OnEdgeClick | undefined
}
21 changes: 5 additions & 16 deletions packages/diagrams/src/konva.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,7 @@
/* eslint-disable @typescript-eslint/prefer-ts-expect-error */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
Rect,
Stage,
Text,
Group,
Path,
Circle,
Line,
Layer,
Image
} from 'react-konva/es/ReactKonvaCore'
import { Rect, Stage, Text, Group, Path, Circle, Line, Layer, Image } from 'react-konva/es/ReactKonvaCore'
import KonvaCore from 'konva/lib/Core'

import 'konva/lib/shapes/Rect'
Expand All @@ -35,7 +25,7 @@ import type { ForwardRefExoticComponent, RefAttributes } from 'react'
// so it triggers touchmove correctly
KonvaCore.hitOnDragEnabled = true
KonvaCore.capturePointerEventsEnabled = true
KonvaCore.dragButtons = [0, 2]
// KonvaCore.dragButtons = [0, 2]

export { KonvaCore, Stage, Group, Layer, Text, Circle, Rect, Image }

Expand Down Expand Up @@ -68,10 +58,9 @@ type AnimatedProps<Props extends object> = {
[P in keyof Props]: P extends 'ref' | 'key' ? Props[P] : AnimatedProp<Props[P]>
}

type AnimatedNode<
Node extends Konva.Node,
Props extends Konva.NodeConfig
> = ForwardRefExoticComponent<KonvaNodeEvents & AnimatedProps<Props> & RefAttributes<Node>>
type AnimatedNode<Node extends Konva.Node, Props extends Konva.NodeConfig> = ForwardRefExoticComponent<
KonvaNodeEvents & AnimatedProps<Props> & RefAttributes<Node>
>

export type AnimatedStageComponent = AnimatedNode<Konva.Stage, StageProps>
export type AnimatedGroupComponent = AnimatedNode<Konva.Group, Konva.GroupConfig>
Expand Down
12 changes: 8 additions & 4 deletions packages/vscode-preview/protocol.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import type { DiagramView, Fqn, RelationID, ViewID } from '@likec4/core/types'

export type ExtensionToPanelProtocol = {
kind: 'update'
view: DiagramView
}
export type ExtensionToPanelProtocol =
| {
kind: 'update'
view: DiagramView
}
| {
kind: 'onContextMenuOpenSource'
}

export type PanelToExtensionProtocol =
| {
Expand Down
Loading

0 comments on commit 8b19661

Please sign in to comment.