Skip to content

feat(CC-icons): added support scripts #11794

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions packages/code-connect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# PatternFly React Icon Generation System

## Overview

The PatternFly React icon generation system automates the process of creating and managing icon components, including generation, Figma connections, and consistent integration.

## Components

### 1. Icon Data Source (`iconsData.json`)
Defines the metadata for each icon in the library.

```npm run figma:icons:fetch --token=FIGMA_ACCESS_TOKEN```

#### JSON Structure
```json
[
{
"iconName": "angle-down",
"fileName": "angle-down-icon",
"reactName": "AngleDownIcon",
"url": "Optional Figma design URL",
"svgPath": "SVG path data for the icon"
}
]
```

### 2. Scripts

#### `iconConnector.mjs`
Generates Figma connection files for icons.

## Workflow

### 1. Prepare Icon Data
Create or update `iconsData.json` with icon specifications.

### 2. Generation Commands

#### Generate Icons
```bash
# Generate iconData.json
yarn run figma:fetch

# Generate icon components and Figma connections
yarn run figma:sync
```

## Best Practices

- Keep `iconsData.json` updated with the latest icon information
- Ensure SVG paths are clean and optimized
- Maintain consistent naming conventions
- Validate icon designs in Figma before generation

## Troubleshooting

### Common Issues
- **SVG Path Errors**: Check SVG path syntax and completeness
- **Naming Conflicts**: Ensure unique `reactName` for each icon

### Logging
The system uses a comprehensive logging utility that provides:
- Timestamped logs
- Contextual information
- Color-coded output for different log levels

## Extensibility

The modular design allows easy extension:
- Add new icons by updating `iconsData.json`
- Modify configuration as project needs evolve

## Contributing

1. Update `iconsData.json` with new icon specifications
2. Validate SVG paths and icon designs
3. Run generation scripts
4. Review generated components
5. Commit changes

## Dependencies

- Node.js
- Figma Code Connect
- PatternFly React ecosystem

## License

PatternFly React is licensed under the [MIT License](https://github.com/patternfly/patternfly-react/tree/main/LICENSE).

## Support

For issues or questions, please file a GitHub issue in the PatternFly React repository.
1 change: 1 addition & 0 deletions packages/code-connect/data/iconsData.json

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions packages/code-connect/icons/Icon.figma.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import figma from '@figma/code-connect';
import { Icon } from '@patternfly/react-core';

figma.connect(
Icon,
'https://www.figma.com/design/VMEX8Xg2nzhBX8rfBx53jp/branch/9QzcMKMR7FX7HXlc0sRUSp/PatternFly-6--Components?node-id=198-1573&t=dP3Et2mI3FtI6IEP-11',
{
props: {
// Comprehensive icon size mapping
size: figma.enum('Icon Size', {
'Body - Small': 'bodySm',
'Body - Default': 'bodyDefault',
'Body - Large': 'bodyLg',

// Heading Sizes
'Heading - H1': 'heading_3xl',
'Heading - H2': 'heading_2xl',
'Heading - H3': 'headingXl',
'Heading - H4': 'headingLg',
'Heading - H5': 'headingMd',
'Heading - H6': 'headingSm'
}),
children: figma.instance('*')
},

example: (props) => <Icon size={props.size}>{props.children}</Icon>
}
);
2,156 changes: 2,156 additions & 0 deletions packages/code-connect/icons/icons.figma.tsx

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions packages/code-connect/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "codeConnect",
"packageManager": "yarn@4.7.0",
"devDependencies": {
"fs-extra": "^11.3.0",
"fse": "^4.0.1"
},
"peerDependencies": {
"react": "^17 || ^18 || ^19",
"react-dom": "^17 || ^18 || ^19"
},
"scripts": {
"figma:icons:fetch": "node scripts/fetchIcons.mjs --token",
"figma:icons:sync": "node scripts/iconConnector.mjs"
}
}
71 changes: 71 additions & 0 deletions packages/code-connect/scripts/fetchIcons.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Found similar implementation from Primer @ Github here:
// https://github.com/primer/react/blob/main/packages/react/script/figma-connect-icons.ts
/* eslint-disable no-console */
/* eslint-disable camelcase */
// import fse from 'fs-extra';
import fse from 'fs-extra';
import { fileURLToPath } from 'url';
import { dirname } from 'path';

if (!(process.argv.includes('--token') && process.argv.indexOf('--token') + 1 < process.argv.length)) {
console.log('--token is required followed by the FIGMA_ACCESS_TOKEN name');
process.exit(1);
}

const apiUri = 'https://api.figma.com/v1/files/VMEX8Xg2nzhBX8rfBx53jp/components';
const designBranch = 'PatternFly-6%3A-Components';
const figmaAccessToken = process.argv[process.argv.indexOf('--token') + 1];
// Get the current directory of this file
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Helper functions for manipulating icon name strings
const removeSnake = (s) => s.toUpperCase().replace('-', '').replace('_', '');
const toCamel = (s) => `${s[0].toUpperCase()}${s.substr(1).replace(/([-_][\w])/gi, removeSnake)}`;

// Helper functions to get icons from Figma REST API
// Fetches icons from Figma & writes to ./iconsData.json
// TODO: Use a variable for URI
async function fetchIcons() {
return await fetch(`${apiUri}`, {
headers: {
'Content-Type': 'application/json',
'X-FIGMA-TOKEN': figmaAccessToken
}
})
.then((res) => res.json())
.then((res) => {
const components = res.meta.components;
const iconsArr = filterIcons(components);
const iconsData = buildIconsDataArr(iconsArr);
// Comment out below to write icon data to json file for debugging
fse.writeJSON(__dirname + '/../data/iconsData.json', iconsData);
return { iconsData, __dirname };
});
}

// Takes array of all components from Figma file
// Returns array filtered down only to those on "Icons " page
const filterIcons = (componentsArr) => componentsArr.filter((comp) => comp.containing_frame.pageName === 'Icons ');

// Creates new array with name/nodeId/url for each icon name
const buildIconsDataArr = (iconsArr) =>
iconsArr.reduce((acc, i) => {
const { name, node_id, file_key } = i;
// Remove fa-, pf-icon-, pf- icon name prefixes
const iconName = name.replace('fa-', '').replace('pf-icon-', '').replace('pf-', '');
const fileName = `${iconName}-icon`;
const reactName = `${toCamel(iconName)}Icon`;
const nodeId = node_id.replace(':', '-');
const url = `https://www.figma.com/design/${file_key}/${designBranch}=${nodeId}&m=dev`;

acc.push({
iconName,
fileName,
reactName,
url
});

return acc;
}, []);

fetchIcons();
Loading
Loading