mirror of
https://github.com/enso-org/enso.git
synced 2024-12-24 15:51:54 +03:00
Set of GUI2 widgets fixes (#8749)
Implements first two points of #8745 1. The fix for drop-down was simple, just stop click propagation 2. The fix for connections was much more complicated. It turned out, that it's about keeping track of hovered ports; when picking an option in WidgetSelection makes the drop-down disappear - but that won't emit `pointerleave` event, so the port was still deemed hovered. Changed the mechanism for tracking hovered port to more "centralized" one.
This commit is contained in:
parent
5b91f16498
commit
b28b743ae4
@ -25,8 +25,6 @@ export const graphSelection: GraphSelection = {
|
||||
events: {} as any,
|
||||
anchor: undefined,
|
||||
deselectAll: () => {},
|
||||
addHoveredPort: () => new Set(),
|
||||
removeHoveredPort: () => false,
|
||||
handleSelectionOf: () => {},
|
||||
hoveredNode: undefined,
|
||||
hoveredPort: undefined,
|
||||
|
@ -85,7 +85,7 @@ export default defineConfig({
|
||||
env: {
|
||||
E2E: 'true',
|
||||
},
|
||||
command: 'vite build && vite preview',
|
||||
command: 'npx vite build && npx vite preview',
|
||||
port: 4173,
|
||||
// We use our special, mocked version of server, thus do not want to re-use user's one.
|
||||
reuseExistingServer: false,
|
||||
|
@ -98,6 +98,7 @@ const spanStart = computed(() => {
|
||||
:input="props.input"
|
||||
:nesting="nesting"
|
||||
:data-span-start="spanStart"
|
||||
:data-port="props.input.portId"
|
||||
@update="updateHandler"
|
||||
/>
|
||||
<span
|
||||
|
@ -120,13 +120,15 @@ const visualizationData = project.useVisualizationData(visualizationConfig)
|
||||
const widgetConfiguration = computed(() => {
|
||||
if (props.input.dynamicConfig?.kind === 'FunctionCall') return props.input.dynamicConfig
|
||||
const data = visualizationData.value
|
||||
if (data != null && data.ok) {
|
||||
if (data?.ok) {
|
||||
const parseResult = argsWidgetConfigurationSchema.safeParse(data.value)
|
||||
if (parseResult.success) {
|
||||
return functionCallConfiguration(parseResult.data)
|
||||
} else {
|
||||
console.error('Unable to parse widget configuration.', data, parseResult.error)
|
||||
}
|
||||
} else if (data != null && !data.ok) {
|
||||
data.error.log('Cannot load dynamic configuration')
|
||||
}
|
||||
return undefined
|
||||
})
|
||||
|
@ -20,7 +20,6 @@ import {
|
||||
nextTick,
|
||||
onUpdated,
|
||||
proxyRefs,
|
||||
ref,
|
||||
shallowRef,
|
||||
toRef,
|
||||
watch,
|
||||
@ -35,7 +34,7 @@ const navigator = injectGraphNavigator()
|
||||
const tree = injectWidgetTree()
|
||||
const selection = injectGraphSelection(true)
|
||||
|
||||
const isHovered = ref(false)
|
||||
const isHovered = computed(() => selection?.hoveredPort === props.input.portId)
|
||||
|
||||
const hasConnection = computed(
|
||||
() => graph.db.connections.reverseLookup(portId.value as ExprId).size > 0,
|
||||
@ -48,14 +47,6 @@ const connected = computed(() => hasConnection.value || isCurrentEdgeHoverTarget
|
||||
const rootNode = shallowRef<HTMLElement>()
|
||||
const nodeSize = useResizeObserver(rootNode, false)
|
||||
|
||||
watchEffect((onCleanup) => {
|
||||
if (selection != null && isHovered.value === true) {
|
||||
const id = portId.value
|
||||
selection.addHoveredPort(id)
|
||||
onCleanup(() => selection.removeHoveredPort(id))
|
||||
}
|
||||
})
|
||||
|
||||
// Compute the scene-space bounding rectangle of the expression's widget. Those bounds are later
|
||||
// used for edge positioning. Querying and updating those bounds is relatively expensive, so we only
|
||||
// do it when the node has any potential for being used as an edge source or target. This is true
|
||||
@ -155,8 +146,6 @@ export const widgetDefinition = defineWidget(WidgetInput.isAstOrPlaceholder, {
|
||||
}"
|
||||
:data-id="portId"
|
||||
:data-h="randSlice"
|
||||
@pointerenter="isHovered = true"
|
||||
@pointerleave="isHovered = false"
|
||||
>
|
||||
<NodeWidget :input="innerWidget" />
|
||||
</div>
|
||||
|
@ -85,7 +85,7 @@ export const widgetDefinition = defineWidget(WidgetInput.isAstOrPlaceholder, {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="WidgetSelection" @pointerdown="toggleDropdownWidget">
|
||||
<div class="WidgetSelection" @pointerdown.stop="toggleDropdownWidget">
|
||||
<NodeWidget :input="innerWidgetInput" />
|
||||
<DropdownWidget
|
||||
v-if="showDropdownWidget"
|
||||
|
@ -1,7 +1,7 @@
|
||||
/** @file A Vue composable for keeping track of selected DOM elements. */
|
||||
|
||||
import { selectionMouseBindings } from '@/bindings'
|
||||
import { usePointer } from '@/composables/events'
|
||||
import { useEvent, usePointer } from '@/composables/events'
|
||||
import type { NavigatorComposable } from '@/composables/navigator'
|
||||
import type { PortId } from '@/providers/portInfo.ts'
|
||||
import type { Rect } from '@/util/data/rect'
|
||||
@ -23,8 +23,19 @@ export function useSelection<T>(
|
||||
const initiallySelected = new Set<T>()
|
||||
const selected = reactive(new Set<T>())
|
||||
const hoveredNode = ref<ExprId>()
|
||||
const hoveredPorts = reactive(new Set<PortId>())
|
||||
const hoveredPort = computed(() => [...hoveredPorts].pop())
|
||||
const hoveredPort = ref<PortId>()
|
||||
|
||||
useEvent(document, 'pointerover', (event) => {
|
||||
if (event.target instanceof Element) {
|
||||
const widgetPort = event.target.closest('.WidgetPort')
|
||||
hoveredPort.value =
|
||||
widgetPort instanceof HTMLElement &&
|
||||
'port' in widgetPort.dataset &&
|
||||
typeof widgetPort.dataset.port === 'string'
|
||||
? (widgetPort.dataset.port as PortId)
|
||||
: undefined
|
||||
}
|
||||
})
|
||||
|
||||
function readInitiallySelected() {
|
||||
initiallySelected.clear()
|
||||
@ -137,8 +148,6 @@ export function useSelection<T>(
|
||||
hoveredPort,
|
||||
mouseHandler: selectionEventHandler,
|
||||
events: pointer.events,
|
||||
addHoveredPort: (port: PortId) => hoveredPorts.add(port),
|
||||
removeHoveredPort: (port: PortId) => hoveredPorts.delete(port),
|
||||
})
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user