-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create a packages to distribute the icons for React 16 projects (#124)
Co-authored-by: vicky-comeau <[email protected]>
- Loading branch information
1 parent
dff7da1
commit f685e70
Showing
168 changed files
with
2,455 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/eslintrc", | ||
"root": true, | ||
"extends": "plugin:@workleap/react-library" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# @hopper-ui/icons-react16 | ||
|
||
A set of icons handcrafted by Workleap. This package is meant to be temporary, to allow teams that are still using React 16 to be able to have access to the shared icons. | ||
|
||
> This package assumes that you are importing the CSS tokens from Hopper in your application. If you are not, icon colors will not be applied. | ||
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](../../LICENSE) | ||
[![npm version](https://img.shields.io/npm/v/@hopper-ui/icons-react16)](https://www.npmjs.com/package/@hopper-ui/icons-react16) | ||
|
||
## Installation | ||
|
||
### Install packages | ||
|
||
**With pnpm** | ||
|
||
```shell | ||
pnpm add @hopper-ui/icons-react16 | ||
``` | ||
|
||
**With yarn** | ||
|
||
```shell | ||
yarn add -D @hopper-ui/icons-react16 | ||
``` | ||
|
||
**With npm** | ||
|
||
```shell | ||
npm install -D @hopper-ui/icons-react16 | ||
``` | ||
|
||
### Import Styles | ||
```css | ||
/* in your root css */ | ||
@import "@hopper-ui/icons-react16/index.css"; | ||
``` | ||
|
||
|
||
https://wl-hopper.netlify.app/icons/react-icons/standalone-installation#import-styles | ||
|
||
### Start using icons | ||
|
||
```tsx | ||
import { AddIcon } from "@hopper-ui/icons-react16"; | ||
|
||
export const App = () => ( | ||
<div> | ||
<span>Hello World!</span> | ||
<AddIcon size="sm" /> | ||
</div> | ||
); | ||
``` | ||
|
||
## Available Icons | ||
|
||
View the [library](https://wl-hopper.netlify.app/icons/react-icons/library). | ||
|
||
## 🤝 Contributing | ||
|
||
View the [contributor's documentation](https://github.com/gsoft-inc/wl-hopper/blob/main/CONTRIBUTING.md). | ||
|
||
## License | ||
|
||
Copyright © 2023, Workleap. This code is licensed under the Apache License, Version 2.0. You may obtain a copy of this license at https://github.com/gsoft-inc/workleap-license/blob/master/LICENSE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
{ | ||
"name": "@hopper-ui/icons-react16", | ||
"author": "Workleap", | ||
"version": "1.0.2", | ||
"description": "The icons package that targets React 16.", | ||
"license": "Apache-2.0", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/gsoft-inc/wl-hopper.git", | ||
"directory": "packages/icons-react16" | ||
}, | ||
"publishConfig": { | ||
"access": "public", | ||
"provenance": true | ||
}, | ||
"type": "module", | ||
"sideEffects": false, | ||
"files": [ | ||
"/dist", | ||
"CHANGELOG.md", | ||
"README.md" | ||
], | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"style": "dist/index.css", | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.js", | ||
"types": "./dist/index.d.ts", | ||
"default": "./dist/index.js" | ||
}, | ||
"./index.css": "./dist/index.css" | ||
}, | ||
"scripts": { | ||
"build": "tsup --config ./tsup.build.ts", | ||
"generate-icons": "tsx scripts/build.ts" | ||
}, | ||
"peerDependencies": { | ||
"react": "^16", | ||
"react-dom": "^16" | ||
}, | ||
"devDependencies": { | ||
"react": "^16", | ||
"react-dom": "^16", | ||
"@svgr/core": "^8.1.0", | ||
"@svgr/plugin-jsx": "^8.1.0", | ||
"@svgr/plugin-svgo": "^8.1.0", | ||
"@swc/core": "1.3.96", | ||
"@swc/helpers": "0.5.3", | ||
"@types/node": "^20.9.3", | ||
"@types/react": "^16", | ||
"@types/react-dom": "^16", | ||
"@workleap/eslint-plugin": "3.0.0", | ||
"@workleap/swc-configs": "2.1.2", | ||
"@workleap/typescript-configs": "3.0.2", | ||
"identity-obj-proxy": "3.0.0", | ||
"ts-jest": "29.1.1", | ||
"ts-node": "10.9.1", | ||
"tsup": "8.0.0", | ||
"tsx": "4.1.4", | ||
"typescript": "5.3.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Purpose: Build script for the icons package. | ||
|
||
import { ComponentDirectory, SVGsDirectory } from "./constants.ts"; | ||
import { fetchSvgs } from "./fetch-svgs.ts"; | ||
import { generateComponents } from "./generate-components.ts"; | ||
import { generateIndex } from "./generate-index.ts"; | ||
|
||
console.log("⚙️ Fetching SVGs...\n"); | ||
const multiSourceIcons = fetchSvgs(SVGsDirectory); | ||
|
||
console.log("⚙️ Generating react components...\n"); | ||
generateComponents(ComponentDirectory, multiSourceIcons); | ||
|
||
console.log("📋 List of icons generation...\n"); | ||
generateIndex(ComponentDirectory, multiSourceIcons); | ||
|
||
console.log("✨ Build completed!\n"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export const ComponentDirectory = "src/generated-icon-components"; | ||
export const SVGsDirectory = "../svg-icons/src/optimized-icons/"; | ||
export const IconSizes = [16, 24, 32] as const; | ||
|
||
export const NeutralIconColor = "#3C3C3C"; // --hop-neutral-icon | ||
export const PrimaryIconColor = "#3B57FF"; // --hop-primary-icon |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import fs from "fs"; | ||
import path from "path"; | ||
import type { IconSizes } from "./constants.ts"; | ||
|
||
export interface MultiSourceIconSource { | ||
name: string; | ||
sizes: Record<typeof IconSizes[number], string>; | ||
} | ||
|
||
const fromKebabToPascalCase = (str: string) => { | ||
return str.split("-").map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(""); | ||
}; | ||
|
||
export const fetchSvgs = (SVGsDir: string) => { | ||
const exists = fs.existsSync(SVGsDir); | ||
if (!exists) { | ||
throw new Error(`Directory, ${SVGsDir}, does not exist.`); | ||
} | ||
|
||
const files = fs.readdirSync(SVGsDir, { recursive: true, withFileTypes: true }); | ||
|
||
const svgFilePaths = files.filter(file => file.isFile() && path.extname(file.name) === ".svg").map(file => { | ||
return path.resolve(file.path, file.name); | ||
}); | ||
|
||
const dict: Record<string, MultiSourceIconSource> = {}; | ||
|
||
svgFilePaths.forEach(svgFilePath => { | ||
const svg = fs.readFileSync(svgFilePath, "utf8"); | ||
const name = path.basename(svgFilePath, ".svg"); | ||
const baseName = name.replace(/-\d+$/, ""); | ||
const size = Number(name.split("-").pop()); | ||
|
||
dict[baseName] = { | ||
name: fromKebabToPascalCase(baseName), | ||
sizes: { ...dict[baseName]?.sizes, [size]: svg } | ||
}; | ||
}); | ||
|
||
return Object.values(dict); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { transform } from "@svgr/core"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { PrimaryIconColor } from "./constants.ts"; | ||
import type { MultiSourceIconSource } from "./fetch-svgs.ts"; | ||
import svgoConfig from "./svgo-config.ts"; | ||
|
||
export async function generateComponents(componentDirectory: string, icons: MultiSourceIconSource[]) { | ||
// Clear directory (It also removes the directory itself) | ||
fs.rmSync(componentDirectory, { recursive: true, force: true }); | ||
fs.mkdirSync(componentDirectory, { recursive: true }); | ||
|
||
for (const icon of icons) { | ||
let componentCode = [ | ||
"/**", | ||
" * This file is generated by the generate-components script. Do not edit directly.", | ||
" */", | ||
"/* eslint-disable */", | ||
"import { createIcon } from \"../create-icon.tsx\";", | ||
"import React, { forwardRef, type Ref, type SVGProps } from \"react\";" | ||
].join("\n"); | ||
componentCode += "\n\n"; | ||
|
||
const baseIconName = `${icon.name}Icon`; | ||
|
||
for (const [size, data] of Object.entries(icon.sizes)) { | ||
componentCode += transform.sync(data, { | ||
typescript: true, | ||
ref: true, | ||
replaceAttrValues: { | ||
[PrimaryIconColor]: "var(--hop-primary-icon)" | ||
}, | ||
jsxRuntime: "automatic", | ||
svgoConfig: svgoConfig, | ||
plugins: ["@svgr/plugin-svgo", "@svgr/plugin-jsx"], | ||
template: ({ componentName, jsx, props }, { tpl }) => { | ||
return tpl` | ||
const ${componentName} = forwardRef((${props}) => ( | ||
${jsx} | ||
)); | ||
`; | ||
} | ||
}, { | ||
componentName: `${baseIconName}${size}` | ||
}); | ||
componentCode += "\n"; | ||
} | ||
componentCode += `\nexport const ${baseIconName} = createIcon(${baseIconName}16, ${baseIconName}24, ${baseIconName}32, "${baseIconName}");`; | ||
|
||
const destinationPath = path.resolve(componentDirectory, baseIconName + ".tsx"); | ||
fs.writeFileSync(destinationPath, Buffer.from(componentCode)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import fs from "fs"; | ||
import type { MultiSourceIconSource } from "./fetch-svgs.ts"; | ||
|
||
const GENERATED_HEADER = `/* | ||
* This file is generated by the generate-components script. Do not edit directly. | ||
*/\n | ||
/* eslint-disable */`; | ||
|
||
export const generateIndex = (componentDirectory: string, iconsByNames: MultiSourceIconSource[]) => { | ||
const iconList = iconsByNames.map(icon => icon.name + "Icon"); | ||
const indexFile = `${componentDirectory}/index.ts`; | ||
const indexContent = `${GENERATED_HEADER}\n | ||
${Object.values(iconsByNames).map(icon => `export * from "./${icon.name}Icon.tsx";`).join("\n")} | ||
\nexport const iconNames = ${JSON.stringify(iconList)} as const;`; | ||
|
||
fs.writeFileSync(indexFile, indexContent); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import type { Config } from "svgo"; | ||
|
||
const config : Config = { | ||
plugins: [ | ||
{ | ||
name: "preset-default", | ||
params: { | ||
overrides: { | ||
removeViewBox: false | ||
} | ||
} | ||
}, | ||
"removeXMLNS" | ||
] | ||
}; | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.hop-icon { | ||
display: inline-block; | ||
pointer-events: none; | ||
flex-shrink: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import React, { forwardRef, type ElementType, type RefAttributes, type SVGProps, type ComponentProps } from "react"; | ||
import styles from "./Icon.module.css"; | ||
|
||
export interface IconProps extends Omit<ComponentProps<"svg">, "ref"> { | ||
/** | ||
* The size of the icon. | ||
*/ | ||
size?: "sm" | "md" | "lg"; | ||
/** | ||
* The source of the icon with a size of 16px. | ||
*/ | ||
src16: ElementType<Omit<SVGProps<SVGSVGElement>, "ref"> & RefAttributes<SVGSVGElement>>; | ||
/** | ||
* The source of the icon with a size of 24px. | ||
*/ | ||
src24: ElementType<Omit<SVGProps<SVGSVGElement>, "ref"> & RefAttributes<SVGSVGElement>>; | ||
/** | ||
* The source of the icon with a size of 32px. | ||
*/ | ||
src32: ElementType<Omit<SVGProps<SVGSVGElement>, "ref"> & RefAttributes<SVGSVGElement>>; | ||
} | ||
|
||
export const Icon = forwardRef<SVGSVGElement, IconProps>((props, ref) => { | ||
const { | ||
size = "md", | ||
src16, | ||
src24, | ||
src32, | ||
style, | ||
className, | ||
"aria-label": ariaLabel, | ||
"aria-hidden": ariaHidden, | ||
...rest | ||
} = props; | ||
|
||
const sizeMappings = { | ||
sm: src16, | ||
md: src24, | ||
lg: src32 | ||
}; | ||
|
||
const As = sizeMappings[size]; | ||
const classNames = [ | ||
styles["hop-icon"], | ||
className | ||
].filter(x => x !== undefined).join(" "); | ||
|
||
return ( | ||
<As | ||
style={style} | ||
{...rest} | ||
ref={ref} | ||
focusable="false" | ||
role="img" | ||
aria-label={ariaLabel} | ||
aria-hidden={(ariaLabel ? (ariaHidden || undefined) : true)} | ||
className={classNames} | ||
/> | ||
); | ||
}); | ||
|
||
Icon.displayName = "Icon"; |
Oops, something went wrong.