@patternfly/react-icons
Version:
PatternFly 4 Icons as React Components
156 lines (133 loc) • 4.96 kB
JavaScript
import { join } from 'path';
import { outputFileSync, ensureDirSync } from 'fs-extra/esm';
import { generateIcons } from './generateIcons.mjs';
import { createElement } from 'react';
import { renderToString } from 'react-dom/server';
import { pfToRhIcons } from './icons/pfToRhIcons.mjs';
import * as url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
// Import createIconBase from compiled dist (build:esm must run first)
const createIconModule = await import('../dist/esm/createIcon.js');
const createIconBase = createIconModule.createIconBase;
const outDir = join(__dirname, '../dist');
const staticDir = join(outDir, 'static');
const removeSnake = (s) => s.toUpperCase().replace('-', '').replace('_', '');
const toCamel = (s) => `${s[0].toUpperCase()}${s.substr(1).replace(/([-_][\w])/gi, removeSnake)}`;
const writeCJSExport = (fname, jsName, icon, rhUiIcon = null) => {
outputFileSync(
join(outDir, 'js/icons', `${fname}.js`),
`"use strict"
exports.__esModule = true;
exports.${jsName}Config = {
name: '${jsName}',
icon: ${JSON.stringify(icon)},
rhUiIcon: ${rhUiIcon ? JSON.stringify(rhUiIcon) : 'null'},
};
exports.${jsName} = require('../createIcon').createIconBase(exports.${jsName}Config);
exports["default"] = exports.${jsName};
`.trim()
);
};
const writeESMExport = (fname, jsName, icon, rhUiIcon = null) => {
outputFileSync(
join(outDir, 'esm/icons', `${fname}.js`),
`import { createIconBase } from '../createIcon.js';
export const ${jsName}Config = {
name: '${jsName}',
icon: ${JSON.stringify(icon)},
rhUiIcon: ${rhUiIcon ? JSON.stringify(rhUiIcon) : 'null'},
};
export const ${jsName} = createIconBase(${jsName}Config);
export default ${jsName};
`.trim()
);
};
const writeDTSExport = (fname, jsName, icon, rhUiIcon = null) => {
const text = `import { ComponentClass } from 'react';
import { SVGIconProps } from '../createIcon.js';
export declare const ${jsName}Config: {
name: '${jsName}',
icon: ${JSON.stringify(icon)},
rhUiIcon: ${rhUiIcon ? JSON.stringify(rhUiIcon) : 'null'},
};
export declare const ${jsName}: ComponentClass<SVGIconProps>;
export default ${jsName};
`.trim();
const filename = `${fname}.d.ts`;
outputFileSync(join(outDir, 'js/icons', filename), text);
outputFileSync(join(outDir, 'esm/icons', filename), text);
};
/**
* Generates a static SVG string from icon data using createIconBase
* @param {string} iconName The name of the icon
* @param {object} icon The icon data object
* @returns {string} Static SVG markup
*/
function generateStaticSVG(iconName, icon) {
const jsName = `${toCamel(iconName)}Icon`;
// Create icon component using createIconBase
const IconComponent = createIconBase({
name: jsName,
icon
});
// Render the component to string
const svgString = renderToString(createElement(IconComponent));
// Convert React's className to class for static SVG
return svgString.replace(/className=/g, 'class=');
}
/**
* Writes static SVG files to dist/static directory
* @param {object} icons icons from generateIcons
*/
function writeStaticSVGs(icons) {
ensureDirSync(staticDir);
Object.entries(icons).forEach(([iconName, icon]) => {
const svgContent = generateStaticSVG(iconName, icon);
const svgFileName = `${iconName}.svg`;
outputFileSync(join(staticDir, svgFileName), svgContent, 'utf-8');
});
// eslint-disable-next-line no-console
console.log(`Wrote ${Object.keys(icons).length} static SVG files to ${staticDir}`);
}
/**
* Writes CJS and ESM icons to `dist` directory
*
* @param {any} icons icons from generateIcons
*/
function writeIcons(icons) {
const index = [];
Object.entries(icons).forEach(([iconName, icon]) => {
const fname = `${iconName}-icon`;
const jsName = `${toCamel(iconName)}Icon`;
const altIcon = pfToRhIcons[jsName] ? pfToRhIcons[jsName].icon : null;
writeESMExport(fname, jsName, icon, altIcon);
writeCJSExport(fname, jsName, icon, altIcon);
writeDTSExport(fname, jsName, icon, altIcon);
index.push({ fname, jsName });
});
const esmIndexString = index
.map(({ fname, jsName }) => `export { ${jsName}, ${jsName}Config } from './${fname}.js';`)
.sort()
.join('\n');
outputFileSync(join(outDir, 'esm', 'icons/index.js'), esmIndexString);
outputFileSync(join(outDir, 'esm', 'icons/index.d.ts'), esmIndexString);
outputFileSync(join(outDir, 'js', 'icons/index.d.ts'), esmIndexString);
outputFileSync(
join(outDir, 'js', 'icons/index.js'),
`"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
exports.__esModule = true;
${index
.map(({ fname }) => `__export(require('./${fname}'));`)
.sort()
.join('\n')}
`.trim()
);
// eslint-disable-next-line no-console
console.log('Wrote', index.length * 3 + 3, 'icon files.');
}
const icons = generateIcons();
writeIcons(icons);
writeStaticSVGs(icons);