Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: SVG Recolor Component #1

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
80 changes: 79 additions & 1 deletion src/index.ts
Expand Up @@ -73,11 +73,89 @@ function needsUpdate(infile: string, outfile: string) {
return inStat.mtimeMs > outStat.mtimeMs;
}

function nthIndex(str: string, search: string, occurrence: number) {
const inputLength = str.length;
let index = -1;

while (occurrence-- && index++ < inputLength) {
index = str.indexOf(search, index);
if (index < 0) {
break;
}
}

return index;
}

function transformSvg(filename: string) {
const config = resolveConfig.sync(path.dirname(filename));
var svgrConfig = config ? Object.assign({}, defaultsvgrConfig, config) : defaultsvgrConfig;
const jsCode = svgr.sync(fs.readFileSync(filename, 'utf8'), svgrConfig);
return fixRenderingBugs(jsCode);

// split element lines to collect current svg values
const elementSplit = jsCode.split('<');
let colorCount = 0;
let defaultColors: string[] = [];
// color modified svg element array
const jsSvgColorModifiedCode = elementSplit.map((row) => {
if (row.includes('fill="#') || row.includes('stroke="#')) {
// match rows with hex color
const match = row.match(/"#.*?"/g);
// if more than one was found, iterate and replace current colors with vars
if (match!.length > 1) {
return match!.reduce((acc, value, i) => {
defaultColors.push(value.replace(/"/g, ''));
const index = nthIndex(acc, '"#', i + 1);
const firstSection = acc.substring(0, index);
const secondSection = acc.substring(index);
const final = firstSection.concat(
secondSection.replace(/"#.*?"/, `{svgColor[${colorCount}]}`),
);
colorCount++;
return final;
}, row);
} else {
// otherwise, replace double quotes and value with var
defaultColors.push(match![0].replace(/"/g, ''));
const finalRow = row.replace(/"#.*?"/, `{svgColor[${colorCount}]}`);
colorCount++;
return finalRow;
}
}

return row;
});

const defaultColorsJs = `const defaultColors = [${defaultColors.map((x) => `'${x}'`)}];\n\n`;
const svgColorJs =
"const svgColor = typeof color === 'string' ? new Array(defaultColors.length).fill(color) : color;\n\n";

const jsColorCode = jsSvgColorModifiedCode.join('<').split(' ');

const insertCode = (code: string, val: string, row: string) => {
const index = row.indexOf(val);
return row.substring(0, index) + code + row.substring(index);
};

const propLookupTable: any = {
"'react-native-svg';\n\nfunction": (str: string): string =>
insertCode(defaultColorsJs, 'function', str),
'SvgComponent(props)': (str: string): string =>
str.replace(
'props',
'{ color = defaultColors, ...rest } : { color: Array | String; rest: SvgProps }',
),
return: (str: string): string => insertCode(svgColorJs, 'return', str),
'{...props}>': (str: string): string => str.replace('{...props}', '{...rest}'),
};

const jsModifiedProps = jsColorCode.map(
(val: string) => propLookupTable[val.trim()] || propLookupTable[val.trim()](val) || val,
);

const svgComponentCode = jsModifiedProps.join(' ');

return fixRenderingBugs(svgComponentCode);
}

function safeName(name: string) {
Expand Down