mysticsymbolic.github.io/lib/svg-symbol.tsx

95 wiersze
1.9 KiB
TypeScript

import React from "react";
import { SVGProps } from "react";
import { BBox } from "../vendor/bezier-js";
import { FILL_REPLACEMENT_COLOR, STROKE_REPLACEMENT_COLOR } from "./colors";
import { Specs } from "./specs";
import { VisibleSpecs } from "./visible-specs";
export type SvgSymbolData = {
name: string;
bbox: BBox;
layers: SvgSymbolElement[];
specs?: Specs;
};
export type SvgSymbolElement = (
| {
tagName: "g";
props: SVGProps<SVGGElement>;
}
| {
tagName: "path";
props: SVGProps<SVGPathElement>;
}
) & {
children: SvgSymbolElement[];
};
export type SvgSymbolContext = {
stroke: string;
fill: string;
showSpecs: boolean;
};
const DEFAULT_CONTEXT: SvgSymbolContext = {
stroke: "#000000",
fill: "#ffffff",
showSpecs: false,
};
export function createSvgSymbolContext(
ctx: Partial<SvgSymbolContext> = {}
): SvgSymbolContext {
return {
...DEFAULT_CONTEXT,
...ctx,
};
}
function getColor(
ctx: SvgSymbolContext,
color: string | undefined
): string | undefined {
switch (color) {
case STROKE_REPLACEMENT_COLOR:
return ctx.stroke;
case FILL_REPLACEMENT_COLOR:
return ctx.fill;
}
return color;
}
function reactifySvgSymbolElement(
ctx: SvgSymbolContext,
el: SvgSymbolElement,
key: number
): JSX.Element {
let { fill, stroke } = el.props;
fill = getColor(ctx, fill);
stroke = getColor(ctx, stroke);
return React.createElement(
el.tagName,
{
...el.props,
id: undefined,
fill,
stroke,
key,
},
el.children.map(reactifySvgSymbolElement.bind(null, ctx))
);
}
export const SvgSymbolContent: React.FC<
{ data: SvgSymbolData } & SvgSymbolContext
> = (props) => {
const d = props.data;
return (
<>
{props.data.layers.map(reactifySvgSymbolElement.bind(null, props))}
{props.showSpecs && d.specs && <VisibleSpecs specs={d.specs} />}
</>
);
};