import { DOMParser } from "xmldom";
const select = require("xpath.js");
import { curry, isEmpty } from "lodash/fp";
import { relLuminance } from "../spinoffs/wcag-contrast";
const NS = {
svg: "http://www.w3.org/2000/svg"
};
const copyAttributeTo = curry(function(sourceEl, targetEl, attributeName) {
const attributeValue = sourceEl.getAttribute(attributeName);
if (!isEmpty(attributeValue)) {
targetEl.setAttribute(attributeName, attributeValue);
}
});
function surroundWithSymbolEl(contentEl) {
var dom = new DOMParser().parseFromString(``);
const symbolEl = dom.createElementNS(NS.svg, "symbol");
symbolEl.setAttribute("overflow", "visible");
const copyAttribute = copyAttributeTo(contentEl, symbolEl);
["width", "height", "x", "y", "viewBox", "preserveAspectRatio"].forEach(
copyAttribute
);
const id = contentEl.getAttribute("id");
symbolEl.setAttribute("id", id);
contentEl.setAttribute("id", id + "-content");
/*
//*/
//
symbolEl.appendChild(contentEl);
return symbolEl;
}
/*
export function processSymbolDefs1(s) {
s.observe().map(({ node }) => node.getAttribute("id")).toArray(function(ids) {
if (ids.length > 0) {
const suggestedFillOnlyCSS = ids
.map((id, i) => `#${id} {fill: currentColor; stroke: none;}`)
.join("\n\t");
console.log(`
Note that most SVG glyph sets expect a fill color but not a stroke.
To disable stroke for your def(s) and enable fill, add this to the CSS string for Kaavio prop style.diagram:
`);
}
});
}
//*/
export function processSymbolDef({
node,
preserveAspectRatio,
contentTagName,
destTagName
}): { node; jic: any } {
if (contentTagName !== destTagName) {
node = surroundWithSymbolEl(node);
}
const id = node.getAttribute("id");
if (preserveAspectRatio) {
node.setAttribute("preserveAspectRatio", "xMidYMid");
} else {
node.setAttribute("preserveAspectRatio", "none");
}
const ACCEPTABLE_NON_COLOR_STROKE_VALUES = [
"currentColor",
"none",
"transparent"
];
const ACCEPTABLE_STROKE_VALUES_REL_LUMINANCES = [0, 1];
const strokeAttrs = select(node, "//*/@stroke");
for (let i = 0; i < strokeAttrs.length; i++) {
const strokeAttr = strokeAttrs[i];
const stroke = strokeAttr.value;
if (ACCEPTABLE_NON_COLOR_STROKE_VALUES.indexOf(stroke) === -1) {
const strokeRelLuminance = relLuminance(stroke);
if (
ACCEPTABLE_STROKE_VALUES_REL_LUMINANCES.indexOf(strokeRelLuminance) ===
-1
) {
const updatedStroke = strokeRelLuminance > 0.5 ? "white" : "black";
console.warn(`\tWarning: if stroke attribute specified for symbols, these are the accepted values:
"currentColor", "none", "transparent", "black" or "white"
Converting:
${stroke}
to:
${updatedStroke}`);
strokeAttr.value = updatedStroke;
}
}
}
const ACCEPTABLE_NON_COLOR_FILL_VALUES = [
"currentColor",
"none",
"transparent"
];
const ACCEPTABLE_FILL_VALUES_REL_LUMINANCES = [0, 1];
const fillAttrs = select(node, "//*/@fill");
for (let i = 0; i < fillAttrs.length; i++) {
const fillAttr = fillAttrs[i];
const fill = fillAttr.value;
if (ACCEPTABLE_NON_COLOR_FILL_VALUES.indexOf(fill) === -1) {
const fillRelLuminance = relLuminance(fill);
if (
ACCEPTABLE_FILL_VALUES_REL_LUMINANCES.indexOf(fillRelLuminance) === -1
) {
const updatedFill = fillRelLuminance > 0.5 ? "white" : "black";
console.warn(`\tWarning: if fill attribute specified for symbols, these are the accepted values:
"currentColor", "none", "transparent", "black" or "white"
Converting:
${fill}
to:
${updatedFill}`);
fillAttr.value = updatedFill;
}
}
}
const viewBox = node.getAttribute("viewBox");
if (!viewBox) {
const width = node.getAttribute("width") || 200;
const height = node.getAttribute("height") || 100;
if (!width || !height) {
throw new Error(`Cannot set viewBox for ${id}.`);
}
node.setAttribute("viewBox", `0 0 ${width} ${height}`);
}
const [viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight] = node
.getAttribute("viewBox")
.split(/[\ ,]/);
const x = node.getAttribute("x");
const y = node.getAttribute("y");
if (!isFinite(x) || !isFinite(y) || x > viewBoxWidth || y > viewBoxHeight) {
node.setAttribute("x", viewBoxX);
node.setAttribute("y", viewBoxY);
}
return { node, jic: {} };
}