Merge pull request #3814 from xyflow/svelte-edge-label-improvements
Svelte edge label improvements
This commit is contained in:
@@ -186,6 +186,7 @@ export function EdgeWrapper({
|
|||||||
animated: edge.animated,
|
animated: edge.animated,
|
||||||
inactive: !isSelectable && !onClick,
|
inactive: !isSelectable && !onClick,
|
||||||
updating: updateHover,
|
updating: updateHover,
|
||||||
|
selectable: isSelectable,
|
||||||
},
|
},
|
||||||
])}
|
])}
|
||||||
onClick={onEdgeClick}
|
onClick={onEdgeClick}
|
||||||
|
|||||||
@@ -1,21 +1,3 @@
|
|||||||
/* this will be exported as base.css and can be used for a basic styling */
|
/* this will be exported as base.css and can be used for a basic styling */
|
||||||
@import '../../../system/src/styles/init.css';
|
@import '../../../system/src/styles/init.css';
|
||||||
@import '../../../system/src/styles/base.css';
|
@import '../../../system/src/styles/base.css';
|
||||||
|
|
||||||
.react-flow {
|
|
||||||
--edge-label-background-color-default: #ffffff;
|
|
||||||
--edge-label-color-default: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow.dark {
|
|
||||||
--edge-label-background-color-default: #141414;
|
|
||||||
--edge-label-color-default: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__edge-textbg {
|
|
||||||
fill: var(--edge-label-background-color, var(--edge-label-background-color-default));
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__edge-text {
|
|
||||||
fill: var(--edge-label-color, var(--edge-label-color-default));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,20 +3,10 @@
|
|||||||
@import '../../../system/src/styles/style.css';
|
@import '../../../system/src/styles/style.css';
|
||||||
@import '../../../system/src/styles/node-resizer.css';
|
@import '../../../system/src/styles/node-resizer.css';
|
||||||
|
|
||||||
.react-flow {
|
|
||||||
--edge-label-background-color-default: #ffffff;
|
|
||||||
--edge-label-color-default: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow.dark {
|
|
||||||
--edge-label-background-color-default: #141414;
|
|
||||||
--edge-label-color-default: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-flow__edge-textbg {
|
.react-flow__edge-textbg {
|
||||||
fill: var(--edge-label-background-color, var(--edge-label-background-color-default));
|
fill: var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default));
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-flow__edge-text {
|
.react-flow__edge-text {
|
||||||
fill: var(--edge-label-color, var(--edge-label-color-default));
|
fill: var(--xy-edge-label-color, var(--xy-edge-label-color-default));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# @xyflow/svelte
|
# @xyflow/svelte
|
||||||
|
|
||||||
|
## 0.0.35
|
||||||
|
|
||||||
|
## Minor changes
|
||||||
|
|
||||||
|
- Edge label has a default background and is clickable
|
||||||
|
|
||||||
## 0.0.34
|
## 0.0.34
|
||||||
|
|
||||||
## Minor changes
|
## Minor changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import { EdgeLabelRenderer } from '$lib/components/EdgeLabelRenderer';
|
|
||||||
import type { BaseEdgeProps } from './types';
|
import type { BaseEdgeProps } from './types';
|
||||||
|
import EdgeLabel from '../EdgeLabel/EdgeLabel.svelte';
|
||||||
|
|
||||||
type $$Props = BaseEdgeProps;
|
type $$Props = BaseEdgeProps;
|
||||||
|
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
let className: $$Props['class'] = undefined;
|
let className: $$Props['class'] = undefined;
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
// @todo, why is interactionWidth undefined after first re-render?
|
|
||||||
let interactionWidthValue = interactionWidth === undefined ? 20 : interactionWidth;
|
let interactionWidthValue = interactionWidth === undefined ? 20 : interactionWidth;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -43,13 +42,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if label}
|
{#if label}
|
||||||
<EdgeLabelRenderer>
|
<EdgeLabel x={labelX} y={labelY} style={labelStyle}>
|
||||||
<div
|
{label}
|
||||||
class="svelte-flow__edge-label"
|
</EdgeLabel>
|
||||||
style:transform="translate(-50%, -50%) translate({labelX}px,{labelY}px)"
|
|
||||||
style={labelStyle}
|
|
||||||
>
|
|
||||||
{label}
|
|
||||||
</div>
|
|
||||||
</EdgeLabelRenderer>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
|
||||||
|
import { EdgeLabelRenderer } from '$lib/components/EdgeLabelRenderer';
|
||||||
|
import { useHandleEdgeSelect } from '$lib/hooks/useHandleEdgeSelect';
|
||||||
|
import type { BaseEdgeProps } from '$lib/components/BaseEdge/types';
|
||||||
|
|
||||||
|
export let style: BaseEdgeProps['labelStyle'] = undefined;
|
||||||
|
export let x: BaseEdgeProps['labelX'] = undefined;
|
||||||
|
export let y: BaseEdgeProps['labelY'] = undefined;
|
||||||
|
|
||||||
|
const handleEdgeSelect = useHandleEdgeSelect();
|
||||||
|
|
||||||
|
const id = getContext<string>('svelteflow__edge_id');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<EdgeLabelRenderer>
|
||||||
|
<div
|
||||||
|
class="svelte-flow__edge-label"
|
||||||
|
style:transform="translate(-50%, -50%) translate({x}px,{y}px)"
|
||||||
|
style={'pointer-events: all;' + style}
|
||||||
|
on:click={() => {
|
||||||
|
if (id) handleEdgeSelect(id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</EdgeLabelRenderer>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default as EdgeLabel } from './EdgeLabel.svelte';
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
<svelte:options immutable />
|
<svelte:options immutable />
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, setContext } from 'svelte';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { getMarkerId } from '@xyflow/system';
|
||||||
import { errorMessages, getMarkerId } from '@xyflow/system';
|
|
||||||
|
|
||||||
import { useStore } from '$lib/store';
|
import { useStore } from '$lib/store';
|
||||||
import { BezierEdgeInternal } from '$lib/components/edges';
|
import { BezierEdgeInternal } from '$lib/components/edges';
|
||||||
import type { EdgeLayouted, Edge } from '$lib/types';
|
import type { EdgeLayouted, Edge } from '$lib/types';
|
||||||
import { get } from 'svelte/store';
|
import { useHandleEdgeSelect } from '$lib/hooks/useHandleEdgeSelect';
|
||||||
|
|
||||||
type $$Props = EdgeLayouted;
|
type $$Props = EdgeLayouted;
|
||||||
|
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
export let animated: $$Props['animated'] = false;
|
export let animated: $$Props['animated'] = false;
|
||||||
export let selected: $$Props['selected'] = false;
|
export let selected: $$Props['selected'] = false;
|
||||||
export let selectable: $$Props['selectable'] = true;
|
|
||||||
export let hidden: $$Props['hidden'] = false;
|
export let hidden: $$Props['hidden'] = false;
|
||||||
export let label: $$Props['label'] = undefined;
|
export let label: $$Props['label'] = undefined;
|
||||||
export let labelStyle: $$Props['labelStyle'] = undefined;
|
export let labelStyle: $$Props['labelStyle'] = undefined;
|
||||||
@@ -43,16 +42,9 @@
|
|||||||
let className: string = '';
|
let className: string = '';
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
const {
|
setContext('svelteflow__edge_id', id);
|
||||||
edges,
|
|
||||||
edgeTypes,
|
const { edgeLookup, edgeTypes, flowId } = useStore();
|
||||||
flowId,
|
|
||||||
selectionRect,
|
|
||||||
selectionRectMode,
|
|
||||||
multiselectionKeyPressed,
|
|
||||||
addSelectedEdges,
|
|
||||||
unselectNodesAndEdges
|
|
||||||
} = useStore();
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
edgeclick: { edge: Edge; event: MouseEvent | TouchEvent };
|
edgeclick: { edge: Edge; event: MouseEvent | TouchEvent };
|
||||||
edgecontextmenu: { edge: Edge; event: MouseEvent };
|
edgecontextmenu: { edge: Edge; event: MouseEvent };
|
||||||
@@ -62,30 +54,19 @@
|
|||||||
$: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined;
|
$: markerStartUrl = markerStart ? `url(#${getMarkerId(markerStart, $flowId)})` : undefined;
|
||||||
$: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined;
|
$: markerEndUrl = markerEnd ? `url(#${getMarkerId(markerEnd, $flowId)})` : undefined;
|
||||||
|
|
||||||
|
const handleEdgeSelect = useHandleEdgeSelect();
|
||||||
|
|
||||||
function onClick(event: MouseEvent | TouchEvent) {
|
function onClick(event: MouseEvent | TouchEvent) {
|
||||||
const edge = $edges.find((e) => e.id === id);
|
const edge = $edgeLookup.get(id);
|
||||||
|
|
||||||
if (!edge) {
|
if (edge) {
|
||||||
console.warn('012', errorMessages['error012'](id));
|
handleEdgeSelect(id);
|
||||||
return;
|
dispatch('edgeclick', { event, edge });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectable) {
|
|
||||||
selectionRect.set(null);
|
|
||||||
selectionRectMode.set(null);
|
|
||||||
|
|
||||||
if (!edge.selected) {
|
|
||||||
addSelectedEdges([id]);
|
|
||||||
} else if (edge.selected && get(multiselectionKeyPressed)) {
|
|
||||||
unselectNodesAndEdges({ nodes: [], edges: [edge] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch('edgeclick', { event, edge });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onContextMenu(event: MouseEvent) {
|
function onContextMenu(event: MouseEvent) {
|
||||||
const edge = $edges.find((e) => e.id === id);
|
const edge = $edgeLookup.get(id);
|
||||||
|
|
||||||
if (edge) {
|
if (edge) {
|
||||||
dispatch('edgecontextmenu', { event, edge });
|
dispatch('edgecontextmenu', { event, edge });
|
||||||
|
|||||||
@@ -24,12 +24,6 @@
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
{#each $visibleEdges as edge (edge.id)}
|
{#each $visibleEdges as edge (edge.id)}
|
||||||
{@const edgeType = edge.type || 'default'}
|
|
||||||
{@const selectable = !!(
|
|
||||||
edge.selectable ||
|
|
||||||
($elementsSelectable && typeof edge.selectable === 'undefined')
|
|
||||||
)}
|
|
||||||
|
|
||||||
<EdgeWrapper
|
<EdgeWrapper
|
||||||
id={edge.id}
|
id={edge.id}
|
||||||
source={edge.source}
|
source={edge.source}
|
||||||
@@ -54,9 +48,8 @@
|
|||||||
ariaLabel={edge.ariaLabel}
|
ariaLabel={edge.ariaLabel}
|
||||||
interactionWidth={edge.interactionWidth}
|
interactionWidth={edge.interactionWidth}
|
||||||
class={edge.class}
|
class={edge.class}
|
||||||
type={edgeType}
|
type={edge.type || 'default'}
|
||||||
zIndex={edge.zIndex}
|
zIndex={edge.zIndex}
|
||||||
{selectable}
|
|
||||||
on:edgeclick
|
on:edgeclick
|
||||||
on:edgecontextmenu
|
on:edgecontextmenu
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { get } from 'svelte/store';
|
||||||
|
import { errorMessages } from '@xyflow/system';
|
||||||
|
|
||||||
|
import { useStore } from '$lib/store';
|
||||||
|
|
||||||
|
export function useHandleEdgeSelect() {
|
||||||
|
const {
|
||||||
|
edgeLookup,
|
||||||
|
selectionRect,
|
||||||
|
selectionRectMode,
|
||||||
|
multiselectionKeyPressed,
|
||||||
|
addSelectedEdges,
|
||||||
|
unselectNodesAndEdges,
|
||||||
|
elementsSelectable
|
||||||
|
} = useStore();
|
||||||
|
|
||||||
|
return (id: string) => {
|
||||||
|
const edge = get(edgeLookup).get(id);
|
||||||
|
|
||||||
|
if (!edge) {
|
||||||
|
console.warn('012', errorMessages['error012'](id));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectable =
|
||||||
|
edge.selectable || (get(elementsSelectable) && typeof edge.selectable === 'undefined');
|
||||||
|
|
||||||
|
if (selectable) {
|
||||||
|
selectionRect.set(null);
|
||||||
|
selectionRectMode.set(null);
|
||||||
|
|
||||||
|
if (!edge.selected) {
|
||||||
|
addSelectedEdges([id]);
|
||||||
|
} else if (edge.selected && get(multiselectionKeyPressed)) {
|
||||||
|
unselectNodesAndEdges({ nodes: [], edges: [edge] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -2,16 +2,7 @@
|
|||||||
@import '../../../system/src/styles/init.css';
|
@import '../../../system/src/styles/init.css';
|
||||||
@import '../../../system/src/styles/base.css';
|
@import '../../../system/src/styles/base.css';
|
||||||
|
|
||||||
.svelte-flow {
|
|
||||||
--edge-label-color-default: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svelte-flow.dark {
|
|
||||||
--edge-label-color-default: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svelte-flow__edge-label {
|
.svelte-flow__edge-label {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
color: var(--edge-label-color, var(--edge-label-color-default));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,14 @@
|
|||||||
@import '../../../system/src/styles/style.css';
|
@import '../../../system/src/styles/style.css';
|
||||||
@import '../../../system/src/styles/node-resizer.css';
|
@import '../../../system/src/styles/node-resizer.css';
|
||||||
|
|
||||||
.svelte-flow {
|
|
||||||
--edge-label-color-default: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svelte-flow.dark {
|
|
||||||
--edge-label-color-default: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svelte-flow__edge-label {
|
.svelte-flow__edge-label {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
padding: 2px;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
color: var(--edge-label-color, var(--edge-label-color-default));
|
cursor: pointer;
|
||||||
|
color: var(--xy-edge-label-color, var(--xy-edge-label-color-default));
|
||||||
|
background: var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default));
|
||||||
}
|
}
|
||||||
|
|
||||||
.svelte-flow__nodes {
|
.svelte-flow__nodes {
|
||||||
|
|||||||
@@ -139,8 +139,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.selected .xy-flow__edge-path,
|
&.selected .xy-flow__edge-path,
|
||||||
&:focus .xy-flow__edge-path,
|
&.selectable:focus .xy-flow__edge-path,
|
||||||
&:focus-visible .xy-flow__edge-path {
|
&.selectable:focus-visible .xy-flow__edge-path {
|
||||||
stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
|
stroke: var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
--xy-controls-button-color-hover-default: inherit;
|
--xy-controls-button-color-hover-default: inherit;
|
||||||
--xy-controls-button-border-color-default: #eee;
|
--xy-controls-button-border-color-default: #eee;
|
||||||
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
--xy-edge-label-background-color-default: #ffffff;
|
||||||
|
--xy-edge-label-color-default: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xy-flow.dark {
|
.xy-flow.dark {
|
||||||
@@ -41,6 +44,9 @@
|
|||||||
--xy-controls-button-color-hover-default: #fff;
|
--xy-controls-button-color-hover-default: #fff;
|
||||||
--xy-controls-button-border-color-default: #5b5b5b;
|
--xy-controls-button-border-color-default: #5b5b5b;
|
||||||
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
--xy-edge-label-background-color-default: #141414;
|
||||||
|
--xy-edge-label-color-default: #f8f8f8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xy-flow__edge {
|
.xy-flow__edge {
|
||||||
|
|||||||
Reference in New Issue
Block a user