diff --git a/lib/svg-symbol.tsx b/lib/svg-symbol.tsx
index aa101c7..f9a7e62 100644
--- a/lib/svg-symbol.tsx
+++ b/lib/svg-symbol.tsx
@@ -27,14 +27,24 @@ export type SvgSymbolGradientStop = {
* This represents a definition that will be referenced
* from elsewhere in an SVG, such as a radial gradient.
*/
-export type SvgSymbolDef = {
- type: "radialGradient";
- id: string;
- cx: string;
- cy: string;
- r: string;
- stops: SvgSymbolGradientStop[];
-};
+export type SvgSymbolDef =
+ | {
+ type: "radialGradient";
+ id: string;
+ cx: string;
+ cy: string;
+ r: string;
+ stops: SvgSymbolGradientStop[];
+ }
+ | {
+ type: "linearGradient";
+ id: string;
+ x1: string;
+ y1: string;
+ x2: string;
+ y2: string;
+ stops: SvgSymbolGradientStop[];
+ };
export const EMPTY_SVG_SYMBOL_DATA: SvgSymbolData = {
name: "",
@@ -167,24 +177,23 @@ function reactifySvgSymbolElement(
const SvgSymbolDef: React.FC<
{ def: SvgSymbolDef; uidMap: UniqueIdMap } & SvgSymbolContext
> = ({ def, uidMap, ...ctx }) => {
+ const id = uidMap.getStrict(def.id);
+ const stops = def.stops.map((stop, i) => (
+
+ ));
switch (def.type) {
case "radialGradient":
return (
-
- {def.stops.map((stop, i) => (
-
- ))}
+
+ {stops}
);
+ case "linearGradient":
+ return (
+
+ {stops}
+
+ );
}
};
diff --git a/lib/vocabulary-builder.ts b/lib/vocabulary-builder.ts
index 5a3ac6a..830d839 100644
--- a/lib/vocabulary-builder.ts
+++ b/lib/vocabulary-builder.ts
@@ -89,16 +89,18 @@ function getNonEmptyAttrib(el: cheerio.TagElement, attr: string): string {
return result;
}
-function parseRadialGradient(el: cheerio.TagElement): SvgSymbolDef {
+function parseGradientStops(
+ els: cheerio.TagElement["children"]
+): SvgSymbolGradientStop[] {
const stops: SvgSymbolGradientStop[] = [];
- for (let child of el.children) {
- if (child.type === "tag") {
- if (child.tagName !== "stop") {
+ for (let el of els) {
+ if (el.type === "tag") {
+ if (el.tagName !== "stop") {
throw new Error(
`Expected an SVG gradient to only contain elements!`
);
}
- const style = getNonEmptyAttrib(child, "style");
+ const style = getNonEmptyAttrib(el, "style");
const color = style.match(/stop-color\:rgb\((\d+),(\d+),(\d+)\)/);
if (!color) {
throw new Error(`Expected "${style}" to contain a stop-color!`);
@@ -107,18 +109,34 @@ function parseRadialGradient(el: cheerio.TagElement): SvgSymbolDef {
.slice(1)
.map((value) => parseInt(value));
stops.push({
- offset: getNonEmptyAttrib(child, "offset"),
+ offset: getNonEmptyAttrib(el, "offset"),
color: clampedBytesToRGBColor(rgb),
});
}
}
+ return stops;
+}
+
+function parseLinearGradient(el: cheerio.TagElement): SvgSymbolDef {
+ return {
+ type: "linearGradient",
+ id: getNonEmptyAttrib(el, "id"),
+ x1: getNonEmptyAttrib(el, "x1"),
+ y1: getNonEmptyAttrib(el, "y1"),
+ x2: getNonEmptyAttrib(el, "x2"),
+ y2: getNonEmptyAttrib(el, "y2"),
+ stops: parseGradientStops(el.children),
+ };
+}
+
+function parseRadialGradient(el: cheerio.TagElement): SvgSymbolDef {
return {
type: "radialGradient",
id: getNonEmptyAttrib(el, "id"),
cx: getNonEmptyAttrib(el, "cx"),
cy: getNonEmptyAttrib(el, "cy"),
r: getNonEmptyAttrib(el, "r"),
- stops,
+ stops: parseGradientStops(el.children),
};
}
@@ -138,20 +156,22 @@ function serializeSvgSymbolElement(
if (tagName === "radialGradient") {
defsOutput.push(parseRadialGradient(el));
return null;
+ } else if (tagName === "linearGradient") {
+ defsOutput.push(parseLinearGradient(el));
+ return null;
+ } else if (!isSupportedSvgTag(tagName)) {
+ throw new Error(`Unsupported SVG element: <${tagName}>`);
}
let children = withoutNulls(
onlyTags(el.children).map((child) =>
serializeSvgSymbolElement($, child, defsOutput)
)
);
- if (isSupportedSvgTag(tagName)) {
- return {
- tagName,
- props: attribsToProps(el) as any,
- children,
- };
- }
- throw new Error(`Unsupported SVG element: <${tagName}>`);
+ return {
+ tagName,
+ props: attribsToProps(el) as any,
+ children,
+ };
}
function removeEmptyGroups(s: SvgSymbolElement[]): SvgSymbolElement[] {