export htmlattributes as props where possible

This commit is contained in:
peterkogo
2025-04-14 18:59:31 +02:00
parent 6be1b7822b
commit 2ca682c6f2
33 changed files with 173 additions and 197 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@xyflow/svelte",
"version": "1.0.0-next.8",
"version": "1.0.0-next.9",
"description": "Svelte Flow - A highly customizable Svelte library for building node-based editors, workflow systems, diagrams and more.",
"keywords": [
"svelte",

View File

@@ -1,41 +1,45 @@
<script lang="ts">
import { getContext, type Snippet } from 'svelte';
import type { ClassValue } from 'svelte/elements';
import { getContext } from 'svelte';
import { portal } from '$lib/actions/portal';
import { EdgeLabelRenderer } from '$lib/components/EdgeLabelRenderer';
import { useStore } from '$lib/store';
import type { EdgeLabelProps } from './types';
let {
x,
y,
selectEdgeOnClick = false,
transparent = false,
style,
class: className,
children
}: {
x?: number;
y?: number;
style?: string;
class?: ClassValue;
children?: Snippet;
} = $props();
children,
...rest
}: EdgeLabelProps = $props();
const store = useStore();
const id = getContext<string>('svelteflow__edge_id');
</script>
<EdgeLabelRenderer>
<div
class={['svelte-flow__edge-label', className]}
style:transform="translate(-50%, -50%) translate({x}px,{y}px)"
style={'pointer-events: all;' + style}
role="button"
tabindex="-1"
onkeyup={() => {}}
onclick={() => {
if (id) store.handleEdgeSelection(id);
}}
>
{@render children?.()}
</div>
</EdgeLabelRenderer>
<div
use:portal={'edgelabel'}
class={['svelte-flow__edge-label', { transparent }, className]}
style:cursor={selectEdgeOnClick ? 'pointer' : undefined}
style:transform="translate(-50%, -50%) translate({x}px,{y}px)"
style:pointer-events="all"
{style}
role="button"
tabindex="-1"
onclick={() => {
if (selectEdgeOnClick && id) store.handleEdgeSelection(id);
}}
{...rest}
>
{@render children?.()}
</div>
<style>
.transparent {
background: transparent;
}
</style>

View File

@@ -1 +1,2 @@
export { default as EdgeLabel } from './EdgeLabel.svelte';
export * from './types';

View File

@@ -0,0 +1,12 @@
import type { Snippet } from 'svelte';
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
export type EdgeLabelProps = {
x?: number;
y?: number;
selectEdgeOnClick?: boolean;
transparent?: boolean;
style?: string;
class?: ClassValue;
children?: Snippet;
} & HTMLAttributes<HTMLDivElement>;

View File

@@ -4,7 +4,8 @@
import { XYHandle, type HandleType, type XYPosition } from '@xyflow/system';
import { getContext, type Snippet } from 'svelte';
import type { ClassValue } from 'svelte/elements';
import { portal } from '$lib/actions/portal';
import EdgeLabel from '../EdgeLabel/EdgeLabel.svelte';
import type { EdgeReconnectAnchorProps } from './types';
let {
type,
@@ -13,16 +14,9 @@
class: className,
size = 25,
style,
children
}: {
type: HandleType;
reconnecting?: boolean;
style?: string;
class?: ClassValue;
position?: XYPosition;
size?: number;
children?: Snippet;
} = $props();
children,
...rest
}: EdgeReconnectAnchorProps = $props();
const store = useStore();
@@ -110,17 +104,16 @@
};
</script>
<div
use:portal={'edgelabel'}
<EdgeLabel
x={position?.x}
y={position?.y}
class={['svelte-flow__edgeupdater nopan', `svelte-flow__edgeupdater-${type}`, className]}
style:position="absolute"
style:width={`${size}px`}
style:height={`${size}px`}
style:transform={`translate(-50%, -50%) ${position ? `translate(${position.x}px, ${position.y}px` : ''}`}
{style}
style={`width:${size}px; height:${size}px;` + style}
onpointerdown={onPointerDown}
transparent
{...rest}
>
{#if !reconnecting && children}
{@render children()}
{/if}
</div>
</EdgeLabel>

View File

@@ -1 +1,2 @@
export { default as EdgeReconnectAnchor } from './EdgeReconnectAnchor.svelte';
export * from './types';

View File

@@ -0,0 +1,13 @@
import type { HandleType, XYPosition } from '@xyflow/system';
import type { Snippet } from 'svelte';
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
export type EdgeReconnectAnchorProps = {
type: HandleType;
reconnecting?: boolean;
style?: string;
class?: ClassValue;
position?: XYPosition;
size?: number;
children?: Snippet;
} & HTMLAttributes<HTMLDivElement>;

View File

@@ -4,19 +4,20 @@
Position,
XYHandle,
isMouseEvent,
type HandleConnection,
areConnectionMapsEqual,
handleConnectionChange,
ConnectionMode,
getHostForElement,
type HandleConnection,
type Optional,
type ConnectionState,
type Connection
} from '@xyflow/system';
import { useStore } from '$lib/store';
import type { HandleProps } from '$lib/types';
import type { ConnectableContext } from '../NodeWrapper/types';
import type { HandleProps } from './types';
let {
id: handleId = null,
@@ -30,7 +31,8 @@
isValidConnection,
onconnect,
ondisconnect,
children
children,
...rest
}: HandleProps = $props();
const nodeId = getContext<string>('svelteflow__node_id');
@@ -226,6 +228,7 @@ The Handle component is the part of a node that can be used to connect nodes.
{style}
role="button"
tabindex="-1"
{...rest}
>
{@render children?.()}
</div>

View File

@@ -1 +1,2 @@
export { default as Handle } from './Handle.svelte';
export * from './types';

View File

@@ -0,0 +1,10 @@
import type { Connection, HandleProps as HandlePropsSystem } from '@xyflow/system';
import type { Snippet } from 'svelte';
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
export type HandleProps = HandlePropsSystem & {
class?: ClassValue;
onconnect?: (connections: Connection[]) => void;
ondisconnect?: (connections: Connection[]) => void;
children?: Snippet;
} & HTMLAttributes<HTMLDivElement>;

View File

@@ -1,11 +1,10 @@
<script lang="ts">
import type { Snippet } from 'svelte';
import { portal } from '$lib/actions/portal';
import type { ViewportPortalProps } from './types';
let { children }: { children?: Snippet } = $props();
let { children, ...rest }: ViewportPortalProps = $props();
</script>
<div use:portal={'viewport'}>
<div use:portal={'viewport'} {...rest}>
{@render children?.()}
</div>

View File

@@ -1 +1,2 @@
export { default as ViewportPortal } from './ViewportPortal.svelte';
export * from './types';

View File

@@ -0,0 +1,6 @@
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
export type ViewportPortalProps = {
children?: Snippet;
} & HTMLAttributes<HTMLDivElement>;

View File

@@ -1,5 +1,4 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { BaseEdgeProps } from '../../types';
import EdgeLabel from '../EdgeLabel/EdgeLabel.svelte';
@@ -16,7 +15,7 @@
interactionWidth = 20,
class: className,
...rest
}: BaseEdgeProps & HTMLAttributes<SVGPathElement> = $props();
}: BaseEdgeProps = $props();
</script>
<path
@@ -41,7 +40,7 @@
{/if}
{#if label}
<EdgeLabel x={labelX} y={labelY} style={labelStyle}>
<EdgeLabel x={labelX} y={labelY} style={labelStyle} selectEdgeOnClick>
{label}
</EdgeLabel>
{/if}

View File

@@ -218,7 +218,7 @@
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
bind:this={container}
class="svelte-flow__pane"
class="svelte-flow__pane svelte-flow__container"
class:draggable={panOnDrag === true || (Array.isArray(panOnDrag) && panOnDrag.includes(0))}
class:dragging={store.dragging}
class:selection={isSelecting}
@@ -230,13 +230,3 @@
>
{@render children()}
</div>
<style>
.svelte-flow__pane {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>

View File

@@ -1 +1,2 @@
export { default as Pane } from './Pane.svelte';
export * from './types';

View File

@@ -2,13 +2,7 @@
import type { PanelProps } from './types';
import { useStore } from '$lib/store';
let {
position = 'top-right',
style,
class: className,
children,
...restProps
}: PanelProps = $props();
let { position = 'top-right', style, class: className, children, ...rest }: PanelProps = $props();
const store = useStore();
@@ -19,7 +13,7 @@
class={['svelte-flow__panel', className, ...positionClasses]}
{style}
style:pointer-events={store.selectionRectMode ? 'none' : ''}
{...restProps}
{...rest}
>
{@render children?.()}
</div>

View File

@@ -1,2 +1,2 @@
export { default as Panel } from './Panel.svelte';
export type { PanelProps } from './types';
export * from './types';

View File

@@ -6,19 +6,9 @@
</script>
<div
class="svelte-flow__viewport xyflow__viewport"
class="svelte-flow__viewport xyflow__viewport svelte-flow__container"
style="transform: translate({store.viewport.x}px, {store.viewport.y}px) scale({store.viewport
.zoom})"
>
{@render children()}
</div>
<style>
.svelte-flow__viewport {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>

View File

@@ -37,7 +37,7 @@
</script>
<div
class="svelte-flow__zoom"
class="svelte-flow__zoom svelte-flow__container"
use:zoom={{
viewport: store.viewport,
minZoom: store.minZoom,
@@ -74,14 +74,3 @@
>
{@render children()}
</div>
<style>
.svelte-flow__zoom {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 4;
}
</style>

View File

@@ -55,7 +55,7 @@ export type {
EdgeTypes,
DefaultEdgeOptions
} from '$lib/types/edges';
export type { HandleProps, FitViewOptions, OnBeforeDelete } from '$lib/types/general';
export type { FitViewOptions, OnBeforeDelete } from '$lib/types/general';
export type { Node, NodeTypes, BuiltInNode, NodeProps, InternalNode } from '$lib/types/nodes';
export type { SvelteFlowStore } from '$lib/store/types';
export * from '$lib/types/events';

View File

@@ -47,7 +47,7 @@
</script>
<svg
class={['svelte-flow__background', className]}
class={['svelte-flow__background', 'svelte-flow__container', className]}
data-testid="svelte-flow__background"
style:--xy-background-color-props={bgColor}
style:--xy-background-pattern-color-props={patternColor}
@@ -69,13 +69,3 @@
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId})`} />
</svg>
<style>
.svelte-flow__background {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
</style>

View File

@@ -27,7 +27,8 @@
fitViewOptions,
children,
before,
after
after,
...rest
}: ControlsProps = $props();
const store = useStore();
@@ -74,6 +75,7 @@
data-testid="svelte-flow__controls"
aria-label={ariaLabel ?? 'Svelte Flow controls'}
{style}
{...rest}
>
{#if before}
{@render before()}

View File

@@ -1,5 +1,5 @@
import type { Snippet } from 'svelte';
import type { ClassValue, HTMLButtonAttributes } from 'svelte/elements';
import type { ClassValue, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
import type { PanelPosition } from '@xyflow/system';
import type { FitViewOptions } from '$lib/types';
@@ -29,7 +29,7 @@ export type ControlsProps = {
before?: Snippet;
after?: Snippet;
fitViewOptions?: FitViewOptions;
};
} & HTMLAttributes<HTMLDivElement>;
export type ControlButtonProps = HTMLButtonAttributes & {
class?: ClassValue;

View File

@@ -43,8 +43,6 @@
let store = useStore();
// let nodes = $derived(store.nodes);
const nodeColorFunc = nodeColor === undefined ? undefined : getAttrFunction(nodeColor);
const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor);
const nodeClassFunc = getAttrFunction(nodeClass);

View File

@@ -15,7 +15,8 @@
align = 'center',
offset = 10,
isVisible,
children
children,
...rest
}: NodeToolbarProps = $props();
const store = useStore();
@@ -66,12 +67,13 @@
{#if store.domNode && isActive && toolbarNodes}
<div
data-id={toolbarNodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()}
class="svelte-flow__node-toolbar"
use:portal={'root'}
class="svelte-flow__node-toolbar"
data-id={toolbarNodes.reduce((acc, node) => `${acc}${node.id} `, '').trim()}
style:position="absolute"
style:transform
style:z-index={zIndex}
{...rest}
>
{@render children?.()}
</div>

View File

@@ -1,5 +1,6 @@
import type { Position, Align } from '@xyflow/system';
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
export type NodeToolbarProps = {
/** The id of the node, or array of ids the toolbar should be displayed at */
@@ -18,4 +19,4 @@ export type NodeToolbarProps = {
/** If true, node toolbar is visible even if node is not selected */
isVisible?: boolean;
children?: Snippet;
};
} & HTMLAttributes<HTMLDivElement>;

View File

@@ -9,7 +9,7 @@ import type {
} from '@xyflow/system';
import type { Node } from '$lib/types';
import type { ClassValue } from 'svelte/elements';
import type { ClassValue, HTMLAttributes } from 'svelte/elements';
/**
* An `Edge` is the complete description with everything Svelte Flow needs to know in order to
@@ -46,7 +46,7 @@ export type BaseEdgeProps = Pick<
*/
markerEnd?: string;
class?: ClassValue;
};
} & HTMLAttributes<SVGPathElement>;
type SmoothStepEdge<EdgeData extends Record<string, unknown> = Record<string, unknown>> = Edge<
EdgeData,

View File

@@ -1,13 +1,10 @@
import type { Snippet } from 'svelte';
import type { ClassValue } from 'svelte/elements';
import type { ShortcutModifierDefinition } from '@svelte-put/shortcut';
import type {
FitViewOptionsBase,
XYPosition,
Handle,
Connection,
OnBeforeDeleteBase,
HandleProps as HandlePropsSystem
OnBeforeDeleteBase
} from '@xyflow/system';
import type { Node } from './nodes';
@@ -24,14 +21,6 @@ export type ConnectionData = {
connectionStatus: string | null;
};
export type HandleProps = HandlePropsSystem & {
class?: ClassValue;
style?: string;
onconnect?: (connections: Connection[]) => void;
ondisconnect?: (connections: Connection[]) => void;
children?: Snippet;
};
export type FitViewOptions<NodeType extends Node = Node> = FitViewOptionsBase<NodeType>;
export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void;

View File

@@ -7,3 +7,15 @@
text-align: center;
position: absolute;
}
.svelte-flow__nodes {
z-index: 0;
}
.svelte-flow__edgelabel-renderer {
z-index: 0;
}
.svelte-flow__zoom {
z-index: 4;
}

View File

@@ -8,7 +8,6 @@
position: absolute;
padding: 2px;
font-size: 10px;
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));
}
@@ -20,3 +19,7 @@
.svelte-flow__edgelabel-renderer {
z-index: 0;
}
.svelte-flow__zoom {
z-index: 4;
}