Files
xyflow/packages/core/src/additional-components/Background/index.tsx
2022-07-11 18:04:27 +02:00

74 lines
2.1 KiB
TypeScript

import React, { memo, FC, useEffect, useState, useRef } from 'react';
import cc from 'classcat';
import { useStore } from '../../store';
import { createGridLinesPath, createGridDotsPath } from './utils';
import { BackgroundVariant, ReactFlowState, BackgroundProps } from '../../types';
const defaultColors = {
[BackgroundVariant.Dots]: '#81818a',
[BackgroundVariant.Lines]: '#eee',
};
const transformSelector = (s: ReactFlowState) => s.transform;
const Background: FC<BackgroundProps> = ({
variant = BackgroundVariant.Dots,
gap = 15,
size = 0.4,
color,
style,
className,
}) => {
const ref = useRef<SVGSVGElement>(null);
const [patternId, setPatternId] = useState<string | null>(null);
const [tX, tY, tScale] = useStore(transformSelector);
useEffect(() => {
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
const bgs = document.querySelectorAll('.react-flow__background');
const index = Array.from(bgs).findIndex((bg) => bg === ref.current);
setPatternId(`pattern-${index}`);
}, []);
const scaledGap = gap * tScale || 1;
const xOffset = tX % scaledGap;
const yOffset = tY % scaledGap;
const isLines = variant === BackgroundVariant.Lines;
const bgColor = color ? color : defaultColors[variant];
const path = isLines ? createGridLinesPath(scaledGap, size, bgColor) : createGridDotsPath(size * tScale, bgColor);
return (
<svg
className={cc(['react-flow__background', 'react-flow__container', className])}
style={{
...style,
width: '100%',
height: '100%',
}}
ref={ref}
>
{patternId && (
<>
<pattern
id={patternId}
x={xOffset}
y={yOffset}
width={scaledGap}
height={scaledGap}
patternUnits="userSpaceOnUse"
>
{path}
</pattern>
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId})`} />
</>
)}
</svg>
);
};
Background.displayName = 'Background';
export default memo(Background);