Compare commits

...

21 Commits

Author SHA1 Message Date
Jakob Guddas
a8f578fa8b fix: fixed async migration issue in generate changed icons comment markup 2025-02-20 21:55:53 +01:00
Eric Fennis
97f214934d refactor(scripts): Formatting in readAllMetadata 2025-02-19 14:32:10 +01:00
Eric Fennis
34dfc63ce2 refactor: Optimize readAllMetadata function to use Promise.all for concurrent metadata reading 2025-02-19 13:55:31 +01:00
Eric Fennis
b46927e510 fix(lucide-react): Revert exports property package.json, fixing edge worker environments. (#2814)
* Revert exports prop

* Adjust export

* Adjust export path

* Add to gitignore

* Adjust build process

* Update .gitignore and add dynamicIconImports module

* Formatting
2025-02-19 11:33:08 +01:00
Eric Fennis
1828a392c8 fix: Add await to checkIconsAndCategories script 2025-02-19 11:19:53 +01:00
dependabot[bot]
3ab6c373a0 build(deps-dev): bump vite from 5.4.12 to 5.4.13 (#2798)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.12 to 5.4.13.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.13/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.13/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-14 08:53:09 +01:00
dependabot[bot]
ba2c4b526f build(deps-dev): bump vite from 5.1.8 to 5.4.12 (#2786)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.1.8 to 5.4.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.12/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-12 09:41:52 +01:00
dependabot[bot]
bde3f01e0b build(deps): bump esbuild from 0.19.12 to 0.25.0 (#2791)
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.19.12 to 0.25.0.
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2024.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.19.12...v0.25.0)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-12 09:41:40 +01:00
Eric Fennis
50630b3aaf ci: Improve build speeds (#2778)
* Revert sync to async functions

* Replace more sync fs functions

* Format files

* Fix build svelte package
2025-02-10 14:13:52 +01:00
Jamie Law
e28426a871 feat(icons): Add gender icons (#2607)
* Add gender icons

* Rename `nonbinary.*` to `non-binary.*`

* Update icon categories

* Remove `neuter` icon

Pending additional use cases or significant demand

* Add more gender-related tags

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-02-07 15:45:34 +01:00
Eric Fennis
eb158561d3 fix(lucide): Support for iconNodes from other libs like Lab (#2752)
* Add support for iconNodes

* formatting
2025-02-07 15:44:54 +01:00
realguse
410ae434fa docs(readme): improve packages table (#2755) 2025-02-07 15:31:21 +01:00
Ikko Eltociear Ashimine
0801b89e4d chore: fix typo (#2777)
* chore: update replaceElement.spec.js

retuns -> returns

* chore: update replaceElement.spec.js.snap

retuns -> returns
2025-02-07 15:29:29 +01:00
Eric Fennis
a1d17eedc9 fix: Redirect aliases site (#2769)
* Fix redirects site

* Remove console.log
2025-02-06 15:39:07 +01:00
Eric Fennis
7481dd0a3f format(license): add missing semicolon in license script 2025-01-24 16:54:10 +01:00
Eric Fennis
f9e93824f1 format package.svg 2025-01-24 14:34:07 +01:00
Abdalrhman Almarakeby
4ba4cf2f35 feat(cog-icon): update tags to add more relevant keywords (#2748) 2025-01-24 14:32:55 +01:00
Eric Fennis
6b29716aa9 Hide add if script is blocked (#2750) 2025-01-24 14:28:54 +01:00
Jakob Guddas
97bbe1d6b2 fix(icons): changed expand icon (#2677)
* Updated icons/expand.svg

* Updated icons/expand.json
2025-01-23 16:54:06 +01:00
Abdalrhman Almarakeby
608da04bdf fix(bolt-icon): correct "contruction" typo in tags to "construction" (#2749) 2025-01-23 16:25:28 +01:00
ケイラ
961404d5cc replace keyof ReactSVG with SVGElementType (#2668)
* replace `keyof ReactSVG` with `SVGElementType`

* define `SVGElementType` locally

* 🧹

* update comments

* Format types.ts

* Update types.ts

* Update types.ts

---------

Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2025-01-18 16:35:52 +01:00
93 changed files with 1559 additions and 595 deletions

6
.gitignore vendored
View File

@@ -20,9 +20,13 @@ packages/**/src/aliases/*.ts
packages/**/src/aliases.ts packages/**/src/aliases.ts
!packages/**/src/aliases/index.ts !packages/**/src/aliases/index.ts
packages/**/src/dynamicIconImports.ts packages/**/src/dynamicIconImports.ts
packages/**/DynamicIcon.d.ts
packages/**/dynamicIconImports.js packages/**/dynamicIconImports.js
packages/**/dynamicIconImports.d.ts packages/**/dynamicIconImports.d.ts
packages/**/dynamicIconImports.js.map packages/**/dynamicIconImports.js.map
packages/**/dynamic.d.ts
packages/**/dynamic.mjs.map
packages/**/dynamic.mjs
packages/**/LICENSE packages/**/LICENSE
categories.json categories.json
tags.json tags.json
@@ -41,3 +45,5 @@ docs/.vitepress/data/iconDetails
docs/.vitepress/data/relatedIcons.json docs/.vitepress/data/relatedIcons.json
docs/.vercel docs/.vercel
docs/.nitro docs/.nitro
.gitignore

View File

@@ -30,17 +30,17 @@ Lucide is an open-source icon library that provides 1000+ vector (svg) files for
## Packages ## Packages
| | Package | Version & Downloads | Links | | Logo | Package | Version | Downloads | Links |
| --- | --- | --- | --- | | ---- | ------- | ------- | --------- | ----- |
| <img src="https://lucide.dev/framework-logos/js.svg" alt="JS logo" width="48"> | `lucide` | [![npm](https://img.shields.io/npm/v/lucide)](https://www.npmjs.com/package/lucide) ![NPM Downloads](https://img.shields.io/npm/dw/lucide) | [Docs](https://lucide.dev/guide/packages/lucide) [Source](./packages/lucide) | | <img src="https://lucide.dev/framework-logos/js.svg" alt="JS logo" width="48"> | **`lucide`** | [![npm](https://img.shields.io/npm/v/lucide)](https://www.npmjs.com/package/lucide) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide) | [Docs](https://lucide.dev/guide/packages/lucide) · [Source](./packages/lucide) |
| <img src="https://lucide.dev/framework-logos/react.svg" alt="React logo" width="48"> | `lucide-react` | [![npm](https://img.shields.io/npm/v/lucide-react)](https://www.npmjs.com/package/lucide-react) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-react) | [Docs](https://lucide.dev/guide/packages/lucide-react) [Source](./packages/lucide-react) | | <img src="https://lucide.dev/framework-logos/react.svg" alt="React logo" width="48"> | **`lucide-react`** | [![npm](https://img.shields.io/npm/v/lucide-react)](https://www.npmjs.com/package/lucide-react) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-react) | [Docs](https://lucide.dev/guide/packages/lucide-react) · [Source](./packages/lucide-react) |
| <img src="https://lucide.dev/framework-logos/vue.svg" alt="Vue logo" width="48"> | `lucide-vue-next` | [![npm](https://img.shields.io/npm/v/lucide-vue-next)](https://www.npmjs.com/package/lucide-vue-next) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-vue-next) | [Docs](https://lucide.dev/guide/packages/lucide-vue-next) [Source](./packages/lucide-vue-next) | | <img src="https://lucide.dev/framework-logos/vue.svg" alt="Vue logo" width="48"> | **`lucide-vue-next`** | [![npm](https://img.shields.io/npm/v/lucide-vue-next)](https://www.npmjs.com/package/lucide-vue-next) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-vue-next) | [Docs](https://lucide.dev/guide/packages/lucide-vue-next) · [Source](./packages/lucide-vue-next) |
| <img src="https://lucide.dev/framework-logos/svelte.svg" alt="Svelte logo" width="48"> | `lucide-svelte` | [![npm](https://img.shields.io/npm/v/lucide-svelte)](https://www.npmjs.com/package/lucide-svelte) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-svelte) | [Docs](https://lucide.dev/guide/packages/lucide-svelte) [Source](./packages/lucide-svelte) | | <img src="https://lucide.dev/framework-logos/svelte.svg" alt="Svelte logo" width="48"> | **`lucide-svelte`** | [![npm](https://img.shields.io/npm/v/lucide-svelte)](https://www.npmjs.com/package/lucide-svelte) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-svelte) | [Docs](https://lucide.dev/guide/packages/lucide-svelte) · [Source](./packages/lucide-svelte) |
| <img src="https://lucide.dev/framework-logos/solid.svg" alt="Solid logo" width="48"> | `lucide-solid` | [![npm](https://img.shields.io/npm/v/lucide-solid)](https://www.npmjs.com/package/lucide-solid) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-solid) | [Docs](https://lucide.dev/guide/packages/lucide-solid) [Source](./packages/lucide-solid) | | <img src="https://lucide.dev/framework-logos/solid.svg" alt="Solid logo" width="48"> | **`lucide-solid`** | [![npm](https://img.shields.io/npm/v/lucide-solid)](https://www.npmjs.com/package/lucide-solid) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-solid) | [Docs](https://lucide.dev/guide/packages/lucide-solid) · [Source](./packages/lucide-solid) |
| <img src="https://lucide.dev/framework-logos/preact.svg" alt="Preact logo" width="48"> | `lucide-preact` | [![npm](https://img.shields.io/npm/v/lucide-preact)](https://www.npmjs.com/package/lucide-preact) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-preact) | [Docs](https://lucide.dev/guide/packages/lucide-preact) [Source](./packages/lucide-preact) | | <img src="https://lucide.dev/framework-logos/preact.svg" alt="Preact logo" width="48"> | **`lucide-preact`** | [![npm](https://img.shields.io/npm/v/lucide-preact)](https://www.npmjs.com/package/lucide-preact) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-preact) | [Docs](https://lucide.dev/guide/packages/lucide-preact) · [Source](./packages/lucide-preact) |
| <img src="https://lucide.dev/framework-logos/react-native.svg" alt="React Native logo" width="48"> | `lucide-react-native` | [![npm](https://img.shields.io/npm/v/lucide-react-native)](https://www.npmjs.com/package/lucide-react-native) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-react-native) | [Docs](https://lucide.dev/guide/packages/lucide-react-native) [Source](./packages/lucide-react-native) | | <img src="https://lucide.dev/framework-logos/react-native.svg" alt="React Native logo" width="48"> | **`lucide-react-native`** | [![npm](https://img.shields.io/npm/v/lucide-react-native)](https://www.npmjs.com/package/lucide-react-native) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-react-native) | [Docs](https://lucide.dev/guide/packages/lucide-react-native) · [Source](./packages/lucide-react-native) |
| <img src="https://lucide.dev/framework-logos/angular.svg" alt="Angular logo" width="48"> | `lucide-angular` | [![npm](https://img.shields.io/npm/v/lucide-angular)](https://www.npmjs.com/package/lucide-angular) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-angular) | [Docs](https://lucide.dev/guide/packages/lucide-angular) [Source](./packages/lucide-angular) | | <img src="https://lucide.dev/framework-logos/angular.svg" alt="Angular logo" width="48"> | **`lucide-angular`** | [![npm](https://img.shields.io/npm/v/lucide-angular)](https://www.npmjs.com/package/lucide-angular) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-angular) | [Docs](https://lucide.dev/guide/packages/lucide-angular) · [Source](./packages/lucide-angular) |
| <img src="https://lucide.dev/framework-logos/svg.svg" alt="SVG logo" width="48"> | `lucide-static` | [![npm](https://img.shields.io/npm/v/lucide-static)](https://www.npmjs.com/package/lucide-static) ![NPM Downloads](https://img.shields.io/npm/dw/lucide-static) | [Docs](https://lucide.dev/guide/packages/lucide-static) [Source](./packages/lucide-static) | | <img src="https://lucide.dev/framework-logos/svg.svg" alt="SVG logo" width="48"> | **`lucide-static`** | [![npm](https://img.shields.io/npm/v/lucide-static)](https://www.npmjs.com/package/lucide-static) | ![NPM Downloads](https://img.shields.io/npm/dw/lucide-static) | [Docs](https://lucide.dev/guide/packages/lucide-static) · [Source](./packages/lucide-static) |
### Figma ### Figma

View File

@@ -61,7 +61,7 @@
}, },
{ {
"name": "finance", "name": "finance",
"title": "Money" "title": "Finance"
}, },
{ {
"name": "food-beverage", "name": "food-beverage",
@@ -85,7 +85,7 @@
}, },
{ {
"name": "math", "name": "math",
"title": "Math" "title": "Mathematics"
}, },
{ {
"name": "medical", "name": "medical",

View File

@@ -5,22 +5,32 @@ import IconButton from '../base/IconButton.vue';
import VPDocAsideCarbonAds from 'vitepress/dist/client/theme-default/components/VPDocAsideCarbonAds.vue' import VPDocAsideCarbonAds from 'vitepress/dist/client/theme-default/components/VPDocAsideCarbonAds.vue'
import { x } from '../../../data/iconNodes' import { x } from '../../../data/iconNodes'
import createLucideIcon from 'lucide-vue-next/src/createLucideIcon'; import createLucideIcon from 'lucide-vue-next/src/createLucideIcon';
import { onMounted, ref } from 'vue';
const { theme } = useData() const { theme } = useData()
const showAd = useSessionStorage('show-carbon-ads',true) const showAd = useSessionStorage('show-carbon-ads', true)
const carbonLoaded = ref(true)
defineProps<{ defineProps<{
drawerOpen: boolean drawerOpen: boolean
}>() }>()
const CloseIcon = createLucideIcon('Close', x) const CloseIcon = createLucideIcon('Close', x)
onMounted(() => {
setTimeout(() => {
if (window?._carbonads == null) {
carbonLoaded.value = false
}
}, 5000)
})
</script> </script>
<template> <template>
<div <div
:class="{ :class="{
'drawer-open': drawerOpen, 'drawer-open': drawerOpen,
'hide-ad': !showAd 'hide-ad': !(showAd && carbonLoaded)
}" }"
class="floating-ad" class="floating-ad"
v-if="theme.carbonAds" v-if="theme.carbonAds"

View File

@@ -1,16 +1,17 @@
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
const currentDir = process.cwd(); const currentDir = process.cwd();
const dataDirectory = path.resolve(currentDir, '.vitepress/data'); const dataDirectory = path.resolve(currentDir, '.vitepress/data');
const directory = path.join(process.cwd(), '../categories'); const directory = path.join(process.cwd(), '../categories');
function getAllCategoryFiles() { async function getAllCategoryFiles() {
const fileNames = fs.readdirSync(directory).filter((file) => path.extname(file) === '.json'); const categoryDirectoryContents = await fs.readdir(directory);
const fileNames = categoryDirectoryContents.filter((file) => path.extname(file) === '.json');
return fileNames.map((fileName) => { const categoryJSONReadPromises = fileNames.map(async (fileName) => {
const name = path.basename(fileName, '.json'); const name = path.basename(fileName, '.json');
const fileContent = fs.readFileSync(path.join(directory, fileName), 'utf8'); const fileContent = await fs.readFile(path.join(directory, fileName), 'utf8');
const parsedFileContent = JSON.parse(fileContent); const parsedFileContent = JSON.parse(fileContent);
@@ -19,14 +20,15 @@ function getAllCategoryFiles() {
title: parsedFileContent.title, title: parsedFileContent.title,
}; };
}); });
return Promise.all(categoryJSONReadPromises);
} }
const categoriesFile = path.resolve(dataDirectory, `categoriesData.json`); const categoriesFile = path.resolve(dataDirectory, `categoriesData.json`);
const categoriesData = getAllCategoryFiles(); const categoriesData = await getAllCategoryFiles();
fs.promises fs.writeFile(categoriesFile, JSON.stringify(categoriesData, null, 2), 'utf-8')
.writeFile(categoriesFile, JSON.stringify(categoriesData, null, 2), 'utf-8')
.then(() => { .then(() => {
console.log('Successfully written categoriesData.json file'); console.log('Successfully written categoriesData.json file');
}) })

View File

@@ -4,7 +4,7 @@ import { readSvgDirectory, toCamelCase } from '@lucide/helpers';
const currentDir = process.cwd(); const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const icons = readSvgDirectory(ICONS_DIR, '.json'); const icons = await readSvgDirectory(ICONS_DIR, '.json');
const iconDetailsDirectory = path.resolve(currentDir, '.vitepress/data', 'iconDetails'); const iconDetailsDirectory = path.resolve(currentDir, '.vitepress/data', 'iconDetails');

View File

@@ -4,7 +4,7 @@ import { readSvgDirectory, toCamelCase } from '@lucide/helpers';
const currentDir = process.cwd(); const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const iconJsonFiles = readSvgDirectory(ICONS_DIR, '.json'); const iconJsonFiles = await readSvgDirectory(ICONS_DIR, '.json');
const location = path.resolve(currentDir, '.vitepress/data', 'iconMetaData.ts'); const location = path.resolve(currentDir, '.vitepress/data', 'iconMetaData.ts');

View File

@@ -5,8 +5,8 @@ import { readSvgDirectory, toCamelCase } from '@lucide/helpers';
const currentDir = process.cwd(); const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const svgFiles = readSvgDirectory(ICONS_DIR); const svgFiles = await readSvgDirectory(ICONS_DIR);
const icons = renderIconsObject(svgFiles, ICONS_DIR, true); const icons = await renderIconsObject(svgFiles, ICONS_DIR, true);
const iconNodesDirectory = path.resolve(currentDir, '.vitepress/data', 'iconNodes'); const iconNodesDirectory = path.resolve(currentDir, '.vitepress/data', 'iconNodes');
@@ -32,7 +32,7 @@ const writeIconFiles = Object.entries(icons).map(async ([iconName, { children }]
await fs.promises.writeFile(location, output, 'utf-8'); await fs.promises.writeFile(location, output, 'utf-8');
iconIndexFileImports.push( iconIndexFileImports.push(
`import ${toCamelCase(iconName)}Node from './${iconName}.node.json' assert { type: "json" };`, `import ${toCamelCase(iconName)}Node from './${iconName}.node.json' with { type: "json" };`,
); );
iconIndexFileExports.push(` ${toCamelCase(iconName)}Node as ${toCamelCase(iconName)},`); iconIndexFileExports.push(` ${toCamelCase(iconName)}Node as ${toCamelCase(iconName)},`);
iconIndexFileDefaultExports.push(` '${iconName}': ${toCamelCase(iconName)}Node,`); iconIndexFileDefaultExports.push(` '${iconName}': ${toCamelCase(iconName)}Node,`);

View File

@@ -4,7 +4,7 @@ import { readSvgDirectory } from '@lucide/helpers';
const currentDir = process.cwd(); const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const svgFiles = readSvgDirectory(ICONS_DIR, '.json'); const svgFiles = await readSvgDirectory(ICONS_DIR, '.json');
const location = path.resolve(currentDir, '.vitepress/data', 'relatedIcons.json'); const location = path.resolve(currentDir, '.vitepress/data', 'relatedIcons.json');
@@ -18,9 +18,7 @@ const categoryWeight = 3;
const MAX_RELATED_ICONS = 4 * 17; // grid of 4x17 icons, = 68 icons const MAX_RELATED_ICONS = 4 * 17; // grid of 4x17 icons, = 68 icons
const arrayMatches = (a, b) => { const arrayMatches = (a, b) => a.filter((item) => b.includes(item)).length;
return a.filter((item) => b.includes(item)).length;
};
const nameParts = (icon) => const nameParts = (icon) =>
[ [
@@ -36,6 +34,7 @@ const getRelatedIcons = (currentIcon, icons) => {
nameWeight * arrayMatches(nameParts(item), nameParts(currentIcon)) + nameWeight * arrayMatches(nameParts(item), nameParts(currentIcon)) +
categoryWeight * arrayMatches(item.categories ?? [], currentIcon.categories ?? []) + categoryWeight * arrayMatches(item.categories ?? [], currentIcon.categories ?? []) +
tagWeight * arrayMatches(item.tags ?? [], currentIcon.tags ?? []); tagWeight * arrayMatches(item.tags ?? [], currentIcon.tags ?? []);
return icons return icons
.filter((i) => i.name !== currentIcon.name) .filter((i) => i.name !== currentIcon.name)
.map((icon) => ({ icon, similarity: iconSimilarity(icon) })) .map((icon) => ({ icon, similarity: iconSimilarity(icon) }))
@@ -46,7 +45,8 @@ const getRelatedIcons = (currentIcon, icons) => {
}; };
const iconsMetaDataPromises = svgFiles.map(async (iconName) => { const iconsMetaDataPromises = svgFiles.map(async (iconName) => {
const metaData = JSON.parse(fs.readFileSync(`../icons/${iconName}`)); const metaDataFileContent = await fs.promises.readFile(`../icons/${iconName}`);
const metaData = JSON.parse(metaDataFileContent);
const name = iconName.replace('.json', ''); const name = iconName.replace('.json', '');

View File

@@ -11,7 +11,7 @@ const git = simpleGit();
const currentDir = process.cwd(); const currentDir = process.cwd();
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const iconJsonFiles = readSvgDirectory(ICONS_DIR, '.json'); const iconJsonFiles = await readSvgDirectory(ICONS_DIR, '.json');
const location = path.resolve(currentDir, '.vitepress/data', 'releaseMetaData.json'); const location = path.resolve(currentDir, '.vitepress/data', 'releaseMetaData.json');
const releaseMetaDataDirectory = path.resolve(currentDir, '.vitepress/data', 'releaseMetadata'); const releaseMetaDataDirectory = path.resolve(currentDir, '.vitepress/data', 'releaseMetadata');

View File

@@ -6,7 +6,7 @@ import { getCurrentDirPath } from '@lucide/helpers';
const currentDir = process.cwd(); const currentDir = process.cwd();
const scriptDir = getCurrentDirPath(import.meta.url); const scriptDir = getCurrentDirPath(import.meta.url);
const iconMetaData = await getIconMetaData(path.resolve(scriptDir, '../icons')); const iconMetaData = await getIconMetaData(path.resolve(scriptDir, '../../icons'));
const iconAliasesRedirectRoutes = Object.entries(iconMetaData) const iconAliasesRedirectRoutes = Object.entries(iconMetaData)
.filter(([, { aliases }]) => aliases?.length) .filter(([, { aliases }]) => aliases?.length)
@@ -16,7 +16,7 @@ const iconAliasesRedirectRoutes = Object.entries(iconMetaData)
const aliasRouteMatches = aliases.join('|'); const aliasRouteMatches = aliases.join('|');
return { return {
src: `/icons/(${aliasRouteMatches})`, src: `/icons/${aliasRouteMatches}`,
status: 302, status: 302,
headers: { headers: {
Location: `/icons/${iconName}`, Location: `/icons/${iconName}`,
@@ -44,4 +44,4 @@ const output = JSON.stringify(vercelRouteConfig, null, 2);
const vercelOutputJSON = path.resolve(currentDir, '.vercel/output/config.json'); const vercelOutputJSON = path.resolve(currentDir, '.vercel/output/config.json');
fs.writeFileSync(vercelOutputJSON, output, 'utf-8'); await fs.promises.writeFile(vercelOutputJSON, output, 'utf-8');

View File

@@ -14,7 +14,7 @@
"diy", "diy",
"fixed", "fixed",
"build", "build",
"contruction", "construction",
"parts" "parts"
], ],
"categories": [ "categories": [

16
icons/circle-small.json Normal file
View File

@@ -0,0 +1,16 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jamiemlaw"
],
"tags": [
"shape",
"bullet",
"gender",
"genderless"
],
"categories": [
"shapes",
"medical"
]
}

13
icons/circle-small.svg Normal file
View File

@@ -0,0 +1,13 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="6" />
</svg>

After

Width:  |  Height:  |  Size: 243 B

View File

@@ -10,7 +10,13 @@
"cog", "cog",
"edit", "edit",
"gear", "gear",
"preferences" "preferences",
"controls",
"configuration",
"fixed",
"build",
"construction",
"parts"
], ],
"categories": [ "categories": [
"account" "account"

View File

@@ -2,13 +2,18 @@
"$schema": "../icon.schema.json", "$schema": "../icon.schema.json",
"contributors": [ "contributors": [
"mittalyashu", "mittalyashu",
"ericfennis" "ericfennis",
"jguddas"
], ],
"tags": [ "tags": [
"scale", "scale",
"fullscreen" "fullscreen",
"maximize",
"minimize",
"contract"
], ],
"categories": [ "categories": [
"text" "text",
"arrows"
] ]
} }

View File

@@ -9,8 +9,12 @@
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
> >
<path d="m21 21-6-6m6 6v-4.8m0 4.8h-4.8" /> <path d="m15 15 6 6" />
<path d="M3 16.2V21m0 0h4.8M3 21l6-6" /> <path d="m15 9 6-6" />
<path d="M21 7.8V3m0 0h-4.8M21 3l-6 6" /> <path d="M21 16.2V21h-4.8" />
<path d="M3 7.8V3m0 0h4.8M3 3l6 6" /> <path d="M21 7.8V3h-4.8" />
<path d="M3 16.2V21h4.8" />
<path d="m3 21 6-6" />
<path d="M3 7.8V3h4.8" />
<path d="M9 9 3 3" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 428 B

14
icons/mars-stroke.json Normal file
View File

@@ -0,0 +1,14 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jamiemlaw"
],
"tags": [
"gender",
"androgyne",
"transgender"
],
"categories": [
"medical"
]
}

16
icons/mars-stroke.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m14 6 4 4" />
<path d="M17 3h4v4" />
<path d="m21 3-7.75 7.75" />
<circle cx="9" cy="15" r="6" />
</svg>

After

Width:  |  Height:  |  Size: 323 B

18
icons/mars.json Normal file
View File

@@ -0,0 +1,18 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jguddas",
"jamiemlaw"
],
"tags": [
"gender",
"sex",
"male",
"masculine",
"man",
"boy"
],
"categories": [
"medical"
]
}

15
icons/mars.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M16 3h5v5" />
<path d="m21 3-6.75 6.75" />
<circle cx="10" cy="14" r="6" />
</svg>

After

Width:  |  Height:  |  Size: 299 B

14
icons/non-binary.json Normal file
View File

@@ -0,0 +1,14 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jamiemlaw"
],
"tags": [
"gender",
"nonbinary",
"enby"
],
"categories": [
"medical"
]
}

16
icons/non-binary.svg Normal file
View File

@@ -0,0 +1,16 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 2v10" />
<path d="m9 4 6 4" />
<path d="m9 8 6-4" />
<circle cx="12" cy="17" r="5" />
</svg>

After

Width:  |  Height:  |  Size: 315 B

View File

@@ -11,6 +11,6 @@
> >
<path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" /> <path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z" />
<path d="M12 22V12" /> <path d="M12 22V12" />
<polyline points="3.29 7 12 12 20.71 7"/> <polyline points="3.29 7 12 12 20.71 7" />
<path d="m7.5 4.27 9 5.15" /> <path d="m7.5 4.27 9 5.15" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 445 B

After

Width:  |  Height:  |  Size: 446 B

14
icons/transgender.json Normal file
View File

@@ -0,0 +1,14 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jamiemlaw"
],
"tags": [
"gender",
"inclusive"
],
"categories": [
"medical",
"accessibility"
]
}

20
icons/transgender.svg Normal file
View File

@@ -0,0 +1,20 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 16v6" />
<path d="M14 20h-4" />
<path d="M18 2h4v4" />
<path d="m2 2 7.17 7.17" />
<path d="M2 5.355V2h3.357" />
<path d="m22 2-7.17 7.17" />
<path d="M8 5 5 8" />
<circle cx="12" cy="12" r="4" />
</svg>

After

Width:  |  Height:  |  Size: 434 B

16
icons/venus-and-mars.json Normal file
View File

@@ -0,0 +1,16 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jamiemlaw"
],
"tags": [
"gender",
"sex",
"intersex",
"androgynous",
"hermaphrodite"
],
"categories": [
"medical"
]
}

17
icons/venus-and-mars.svg Normal file
View File

@@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10 20h4" />
<path d="M12 16v6" />
<path d="M17 2h4v4" />
<path d="m21 2-5.46 5.46" />
<circle cx="12" cy="11" r="5" />
</svg>

After

Width:  |  Height:  |  Size: 347 B

18
icons/venus.json Normal file
View File

@@ -0,0 +1,18 @@
{
"$schema": "../icon.schema.json",
"contributors": [
"jguddas",
"jamiemlaw"
],
"tags": [
"gender",
"sex",
"female",
"feminine",
"woman",
"girl"
],
"categories": [
"medical"
]
}

15
icons/venus.svg Normal file
View File

@@ -0,0 +1,15 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 15v7" />
<path d="M9 19h6" />
<circle cx="12" cy="9" r="6" />
</svg>

After

Width:  |  Height:  |  Size: 289 B

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return `\ return `\

View File

@@ -53,7 +53,7 @@
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^6.1.0",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^1.1.1" "vitest": "^1.1.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

@@ -1,6 +1,6 @@
import plugins from '@lucide/rollup-plugins'; import plugins from '@lucide/rollup-plugins';
import dts from 'rollup-plugin-dts'; import dts from 'rollup-plugin-dts';
import pkg from './package.json' assert { type: 'json' }; import pkg from './package.json' with { type: 'json' };
const packageName = 'LucidePreact'; const packageName = 'LucidePreact';
const outputFileName = 'lucide-preact'; const outputFileName = 'lucide-preact';

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `

View File

@@ -59,7 +59,7 @@
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^6.1.0",
"typescript": "^4.8.4", "typescript": "^4.8.4",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^1.1.1" "vitest": "^1.1.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `

View File

@@ -1,10 +1,4 @@
import { import { forwardRef, createElement, FunctionComponent } from 'react';
forwardRef,
createElement,
ReactSVG,
FunctionComponent,
ForwardRefExoticComponent,
} from 'react';
import * as NativeSvg from 'react-native-svg'; import * as NativeSvg from 'react-native-svg';
import defaultAttributes, { childDefaultAttributes } from './defaultAttributes'; import defaultAttributes, { childDefaultAttributes } from './defaultAttributes';
import { IconNode, LucideIcon, LucideProps } from './types'; import { IconNode, LucideIcon, LucideProps } from './types';

View File

@@ -1,7 +1,22 @@
import type { ForwardRefExoticComponent, ReactSVG } from 'react'; import type { ForwardRefExoticComponent } from 'react';
import type { SvgProps } from 'react-native-svg'; import type { SvgProps } from 'react-native-svg';
export type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]; /**
* A reduced version of `SVGElementType` from @types/react. This type was added
* with the release of React 19, and is included here in order to support usage
* with older versions.
*/
type SVGElementType =
| 'circle'
| 'ellipse'
| 'g'
| 'line'
| 'path'
| 'polygon'
| 'polyline'
| 'rect';
export type IconNode = [elementName: SVGElementType, attrs: Record<string, string>][];
export interface LucideProps extends SvgProps { export interface LucideProps extends SvgProps {
size?: string | number; size?: string | number;

View File

@@ -0,0 +1 @@
export { default } from './dist/esm/dynamicIconImports.js';

View File

@@ -23,57 +23,25 @@
], ],
"author": "Eric Fennis", "author": "Eric Fennis",
"amdName": "lucide-react", "amdName": "lucide-react",
"source": "src/lucide-react.ts", "main": "dist/cjs/lucide-react.js",
"main": "dist/esm/lucide-react.js", "main:umd": "dist/umd/lucide-react.js",
"types": "dist/lucide-react.d.ts", "module": "dist/esm/lucide-react.js",
"type": "module", "unpkg": "dist/umd/lucide-react.min.js",
"files": [ "typings": "dist/lucide-react.d.ts",
"dist"
],
"exports": {
".": {
"types": "./dist/lucide-react.d.ts",
"import": "./dist/esm/lucide-react.js",
"browser": "./dist/esm/lucide-react.js",
"require": "./dist/cjs/lucide-react.js",
"node": "./dist/cjs/lucide-react.js"
},
"./icons": {
"types": "./dist/lucide-react.d.ts",
"import": "./dist/esm/lucide-react.js",
"browser": "./dist/esm/lucide-react.js",
"require": "./dist/cjs/lucide-react.js",
"node": "./dist/cjs/lucide-react.js"
},
"./icons/*": {
"types": "./dist/icons/*.d.ts",
"import": "./dist/esm/icons/*.js",
"browser": "./dist/esm/icons/*.js",
"require": "./dist/cjs/icons/*.js",
"node": "./dist/cjs/icons/*.js"
},
"./dynamic": {
"types": "./dist/dynamic.d.ts",
"import": "./dist/esm/dynamic.js",
"browser": "./dist/esm/dynamic.js",
"require": "./dist/cjs/dynamic.js",
"node": "./dist/cjs/dynamic.js"
},
"./dynamicIconImports": {
"types": "./dist/dynamicIconImports.d.ts",
"import": "./dist/esm/dynamicIconImports.js",
"browser": "./dist/esm/dynamicIconImports.js",
"require": "./dist/cjs/dynamicIconImports.js",
"node": "./dist/cjs/dynamicIconImports.js"
},
"./src/*": "./src/*.ts",
"./package.json": "./package.json"
},
"sideEffects": false, "sideEffects": false,
"files": [
"dist",
"dynamic.mjs",
"dynamic.js.map",
"dynamic.d.ts",
"dynamicIconImports.mjs",
"dynamicIconImports.js.map",
"dynamicIconImports.d.ts"
],
"scripts": { "scripts": {
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm typecheck && pnpm build:bundles", "build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm typecheck && pnpm build:bundles",
"copy:license": "cp ../../LICENSE ./LICENSE", "copy:license": "cp ../../LICENSE ./LICENSE",
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts && rm -f dynamicIconImports.*", "clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts && rm -f dynamic.* && rm -f dynamicIconImports.d.ts",
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --withDynamicImports --separateAliasesFile --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts", "build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --withDynamicImports --separateAliasesFile --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts",
"build:bundles": "rollup -c ./rollup.config.mjs", "build:bundles": "rollup -c ./rollup.config.mjs",
"typecheck": "tsc", "typecheck": "tsc",
@@ -97,7 +65,7 @@
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^6.1.0",
"rollup-plugin-preserve-directives": "^0.4.0", "rollup-plugin-preserve-directives": "^0.4.0",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^1.1.1" "vitest": "^1.1.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

@@ -8,42 +8,40 @@ const aliasesEntries = await getAliasesEntryNames();
const packageName = 'LucideReact'; const packageName = 'LucideReact';
const outputFileName = 'lucide-react'; const outputFileName = 'lucide-react';
const outputDir = `dist`;
const inputs = [`src/lucide-react.ts`]; const inputs = [`src/lucide-react.ts`];
const bundles = [ const bundles = [
{ {
format: 'umd', format: 'umd',
inputs, inputs,
outputDir, outputDir: 'dist/umd',
minify: true, minify: true,
}, },
{ {
format: 'umd', format: 'umd',
inputs, inputs,
outputDir, outputDir: 'dist/umd',
}, },
{ {
format: 'cjs', format: 'cjs',
inputs, inputs,
outputDir, outputDir: 'dist/cjs',
}, },
{ {
format: 'esm', format: 'esm',
inputs: [...inputs, ...aliasesEntries], inputs: [...inputs, , 'src/dynamicIconImports.ts', 'src/DynamicIcon.ts', ...aliasesEntries],
outputDir, outputDir: 'dist/esm',
preserveModules: true, preserveModules: true,
}, },
{ {
format: 'esm', format: 'esm',
inputs: ['src/dynamic.ts', 'src/dynamicIconImports.ts', 'src/DynamicIcon.ts'], inputs: ['src/dynamic.ts'],
outputDir, outputFile: 'dynamic.mjs',
preserveModules: true,
external: [/src/], external: [/src/],
paths: (id) => { paths: (id) => {
if (id.match(/src/)) { if (id.match(/src/)) {
const [, modulePath] = id.match(/src\/(.*)\.ts/); const [, modulePath] = id.match(/src\/(.*)\.ts/);
return `${modulePath}.js`; return `dist/esm/${modulePath}.js`;
} }
}, },
}, },
@@ -77,12 +75,10 @@ const configs = bundles
name: packageName, name: packageName,
...(preserveModules ...(preserveModules
? { ? {
dir: `${outputDir}/${format}`, dir: outputDir,
} }
: { : {
file: file: outputFile ?? `${outputDir}/${outputFileName}${minify ? '.min' : ''}.js`,
outputFile ??
`${outputDir}/${format}/${outputFileName}${minify ? '.min' : ''}.js`,
}), }),
paths, paths,
entryFileNames, entryFileNames,
@@ -104,31 +100,17 @@ export default [
input: 'src/dynamicIconImports.ts', input: 'src/dynamicIconImports.ts',
output: [ output: [
{ {
file: `dist/dynamicIconImports.d.ts`, file: `dynamicIconImports.d.ts`,
format: 'es',
},
],
plugins: [
dts({
exclude: ['./src/icons'],
}),
],
},
{
input: 'src/dynamic.ts',
output: [
{
file: `dist/dynamic.d.ts`,
format: 'es', format: 'es',
}, },
], ],
plugins: [dts()], plugins: [dts()],
}, },
{ {
input: 'src/DynamicIcon.ts', input: 'src/dynamic.ts',
output: [ output: [
{ {
file: `dist/DynamicIcon.d.ts`, file: `dynamic.d.ts`,
format: 'es', format: 'es',
}, },
], ],

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `

View File

@@ -1,6 +1,21 @@
import { ReactSVG, SVGProps, ForwardRefExoticComponent, RefAttributes } from 'react'; import type { SVGProps, ForwardRefExoticComponent, RefAttributes } from 'react';
export type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]; /**
* A reduced version of `SVGElementType` from @types/react. This type was added
* with the release of React 19, and is included here in order to support usage
* with older versions.
*/
type SVGElementType =
| 'circle'
| 'ellipse'
| 'g'
| 'line'
| 'path'
| 'polygon'
| 'polyline'
| 'rect';
export type IconNode = [elementName: SVGElementType, attrs: Record<string, string>][];
export type SVGAttributes = Partial<SVGProps<SVGSVGElement>>; export type SVGAttributes = Partial<SVGProps<SVGSVGElement>>;
type ElementAttributes = RefAttributes<SVGSVGElement> & SVGAttributes; type ElementAttributes = RefAttributes<SVGSVGElement> & SVGAttributes;

View File

@@ -83,10 +83,10 @@
"rollup": "^4.22.4", "rollup": "^4.22.4",
"solid-js": "^1.8.7", "solid-js": "^1.8.7",
"typescript": "^4.9.4", "typescript": "^4.9.4",
"vite": "5.1.8", "vite": "5.4.13",
"vite-plugin-solid": "^2.10.1", "vite-plugin-solid": "^2.10.1",
"vitest": "^1.1.1", "vitest": "^1.1.1",
"esbuild": "^0.19.11" "esbuild": "^0.25.0"
}, },
"peerDependencies": { "peerDependencies": {
"solid-js": "^1.4.7" "solid-js": "^1.4.7"

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `

View File

@@ -30,8 +30,8 @@ const license = `@license ${pkg.name} v${pkg.version} - ${pkg.license}`;
createDirectory(LIB_DIR); createDirectory(LIB_DIR);
createDirectory(ICON_MODULE_DIR); createDirectory(ICON_MODULE_DIR);
const svgFiles = readSvgDirectory(ICONS_DIR); const svgFiles = await readSvgDirectory(ICONS_DIR);
const svgs = readSvgs(svgFiles, ICONS_DIR); const svgs = await readSvgs(svgFiles, ICONS_DIR);
const parsedSvgs = svgs.map(({ name, contents }) => ({ const parsedSvgs = svgs.map(({ name, contents }) => ({
name, name,
@@ -39,6 +39,8 @@ const parsedSvgs = svgs.map(({ name, contents }) => ({
parsedSvg: parseSync(contents), parsedSvg: parseSync(contents),
})); }));
generateSprite(parsedSvgs, PACKAGE_DIR, license); await Promise.all([
generateIconNodes(parsedSvgs, PACKAGE_DIR); generateSprite(parsedSvgs, PACKAGE_DIR, license),
copyIcons(parsedSvgs, PACKAGE_DIR, license); generateIconNodes(parsedSvgs, PACKAGE_DIR),
copyIcons(parsedSvgs, PACKAGE_DIR, license),
]);

View File

@@ -1,8 +1,8 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({ componentName, iconName, getSvg, deprecated, deprecationReason }) => {
let svgContents = getSvg(); let svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
svgContents = svgContents.replace( svgContents = svgContents.replace(

View File

@@ -1,6 +1,6 @@
import { writeFile } from '@lucide/helpers'; import { writeFile } from '@lucide/helpers';
export default function generateIconNodes(parsedSvgs, packageDir) { export default async function generateIconNodes(parsedSvgs, packageDir) {
const iconNodes = parsedSvgs.reduce((acc, { name, parsedSvg }) => { const iconNodes = parsedSvgs.reduce((acc, { name, parsedSvg }) => {
acc[name] = parsedSvg.children.map(({ name, attributes }) => [name, attributes]); acc[name] = parsedSvg.children.map(({ name, attributes }) => [name, attributes]);
@@ -9,5 +9,5 @@ export default function generateIconNodes(parsedSvgs, packageDir) {
const iconNodesStringified = JSON.stringify(iconNodes, null, 2); const iconNodesStringified = JSON.stringify(iconNodes, null, 2);
writeFile(iconNodesStringified, 'icon-nodes.json', packageDir); await writeFile(iconNodesStringified, 'icon-nodes.json', packageDir);
} }

View File

@@ -3,7 +3,7 @@ import { stringify } from 'svgson';
import { format } from 'prettier'; import { format } from 'prettier';
import { appendFile } from '@lucide/helpers'; import { appendFile } from '@lucide/helpers';
export default function generateSprite(svgs, packageDir, license) { export default async function generateSprite(svgs, packageDir, license) {
const symbols = svgs.map(({ name, parsedSvg }) => ({ const symbols = svgs.map(({ name, parsedSvg }) => ({
name: 'symbol', name: 'symbol',
type: 'element', type: 'element',
@@ -34,6 +34,6 @@ export default function generateSprite(svgs, packageDir, license) {
const xmlMeta = `<?xml version="1.0" encoding="utf-8"?>\n<!-- ${license} -->\n`; const xmlMeta = `<?xml version="1.0" encoding="utf-8"?>\n<!-- ${license} -->\n`;
appendFile(xmlMeta, `sprite.svg`, packageDir); await appendFile(xmlMeta, `sprite.svg`, packageDir);
appendFile(prettifiedSprite, `sprite.svg`, packageDir); await appendFile(prettifiedSprite, `sprite.svg`, packageDir);
} }

View File

@@ -9,10 +9,12 @@ import { readSvg } from '@lucide/helpers';
* @returns {Object} * @returns {Object}
*/ */
export default function readSVGs(svgFiles, iconsDirectory) { export default function readSVGs(svgFiles, iconsDirectory) {
return svgFiles.map((svgFile) => { const SVGReadPromises = svgFiles.map(async (svgFile) => {
const name = basename(svgFile, '.svg'); const name = basename(svgFile, '.svg');
const contents = readSvg(svgFile, iconsDirectory); const contents = await readSvg(svgFile, iconsDirectory);
return { name, contents }; return { name, contents };
}); });
return Promise.all(SVGReadPromises);
} }

View File

@@ -52,7 +52,7 @@
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --exportFileName=index.ts --iconFileExtension=.svelte --importImportFileExtension=.svelte --separateIconFileExport --separateIconFileExportExtension=.ts --withAliases --aliasesFileExtension=.ts --separateAliasesFile --separateAliasesFileExtension=.ts --aliasImportFileExtension=.js --pretty=false", "build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --exportFileName=index.ts --iconFileExtension=.svelte --importImportFileExtension=.svelte --separateIconFileExport --separateIconFileExportExtension=.ts --withAliases --aliasesFileExtension=.ts --separateAliasesFile --separateAliasesFileExtension=.ts --aliasImportFileExtension=.js --pretty=false",
"build:package": "svelte-package --input ./src", "build:package": "svelte-package --input ./src",
"build:license": "node ./scripts/appendBlockComments.mjs", "build:license": "node ./scripts/appendBlockComments.mjs",
"test": "pnpm build:icons && vitest run", "test": "pnpm copy:license && pnpm build:icons && vitest run",
"test:watch": "vitest watch", "test:watch": "vitest watch",
"version": "pnpm version --git-tag-version=false" "version": "pnpm version --git-tag-version=false"
}, },
@@ -70,7 +70,7 @@
"svelte-check": "^3.4.4", "svelte-check": "^3.4.4",
"svelte-preprocess": "^5.0.4", "svelte-preprocess": "^5.0.4",
"typescript": "^5.1.6", "typescript": "^5.1.6",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^1.1.1" "vitest": "^1.1.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

@@ -4,7 +4,7 @@ import path from 'path';
import { getCurrentDirPath } from '@lucide/helpers'; import { getCurrentDirPath } from '@lucide/helpers';
import { getJSBanner } from './license.mjs'; import { getJSBanner } from './license.mjs';
const currentDir = getCurrentDirPath(import.meta.url); const currentDir = await getCurrentDirPath(import.meta.url);
const targetDirectory = path.join(currentDir, '../dist'); const targetDirectory = path.join(currentDir, '../dist');
const files = await readdir(targetDirectory, { const files = await readdir(targetDirectory, {

View File

@@ -2,8 +2,15 @@
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
import { getJSBanner } from './license.mjs'; import { getJSBanner } from './license.mjs';
export default ({ iconName, children, componentName, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); iconName,
children,
componentName,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return `\ return `\

View File

@@ -1,7 +1,7 @@
import fs from 'fs'; import fs from 'fs';
import pkg from '../package.json' with { type: 'json' }; import pkg from '../package.json' with { type: 'json' };
const license = fs.readFileSync('LICENSE', 'utf-8') const license = fs.readFileSync('LICENSE', 'utf-8');
export function getJSBanner() { export function getJSBanner() {
return `/** return `/**

View File

@@ -54,7 +54,7 @@
"@vue/test-utils": "2.4.5", "@vue/test-utils": "2.4.5",
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^6.1.0",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^1.4.0", "vitest": "^1.4.0",
"vue": "^3.4.21" "vue": "^3.4.21"
}, },

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `

View File

@@ -52,7 +52,7 @@
"@vue/test-utils": "1.3.0", "@vue/test-utils": "1.3.0",
"rollup": "^3.29.5", "rollup": "^3.29.5",
"typescript": "^4.9.5", "typescript": "^4.9.5",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^0.32.2", "vitest": "^0.32.2",
"vue": "2.7.14", "vue": "2.7.14",
"vue-template-compiler": "2.7.14" "vue-template-compiler": "2.7.14"

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `

View File

@@ -39,6 +39,7 @@
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --iconFileExtension=.ts --withAliases --aliasNamesOnly --aliasesFileExtension=.ts --exportFileName=index.ts", "build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --iconFileExtension=.ts --withAliases --aliasNamesOnly --aliasesFileExtension=.ts --exportFileName=index.ts",
"build:bundle": "rollup -c rollup.config.mjs", "build:bundle": "rollup -c rollup.config.mjs",
"test": "pnpm build:icons && vitest run", "test": "pnpm build:icons && vitest run",
"test:watch": "vitest watch",
"version": "pnpm version --git-tag-version=false" "version": "pnpm version --git-tag-version=false"
}, },
"devDependencies": { "devDependencies": {
@@ -50,7 +51,7 @@
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^6.1.0",
"typescript": "^4.9.3", "typescript": "^4.9.3",
"vite": "5.1.8", "vite": "5.4.13",
"vitest": "^1.1.1" "vitest": "^1.1.1"
} }
} }

View File

@@ -1,8 +1,15 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs'; import base64SVG from '@lucide/build-icons/utils/base64SVG.mjs';
export default ({ componentName, iconName, children, getSvg, deprecated, deprecationReason }) => { export default async ({
const svgContents = getSvg(); componentName,
iconName,
children,
getSvg,
deprecated,
deprecationReason,
}) => {
const svgContents = await getSvg();
const svgBase64 = base64SVG(svgContents); const svgBase64 = base64SVG(svgContents);
return ` return `
@@ -19,11 +26,7 @@ import type { IconNode } from '../types';
* @returns {Array} * @returns {Array}
* ${deprecated ? `@deprecated ${deprecationReason}` : ''} * ${deprecated ? `@deprecated ${deprecationReason}` : ''}
*/ */
const ${componentName}: IconNode = [ const ${componentName}: IconNode = ${JSON.stringify(children)}
'svg',
defaultAttributes,
${JSON.stringify(children)}
];
export default ${componentName}; export default ${componentName};
`; `;

View File

@@ -1,4 +1,6 @@
import { IconNode, IconNodeChild, SVGProps } from './types'; import { IconNode, SVGProps } from './types';
type CreateElementParams = [tag: string, attrs: SVGProps, children?: IconNode];
/** /**
* Creates a new HTMLElement from icon node * Creates a new HTMLElement from icon node
@@ -7,16 +9,16 @@ import { IconNode, IconNodeChild, SVGProps } from './types';
* @param {array} children * @param {array} children
* @returns {HTMLElement} * @returns {HTMLElement}
*/ */
const createElement = (tag: string, attrs: SVGProps, children: IconNodeChild[] = []) => { const createElement = ([tag, attrs, children]: CreateElementParams) => {
const element = document.createElementNS('http://www.w3.org/2000/svg', tag); const element = document.createElementNS('http://www.w3.org/2000/svg', tag);
Object.keys(attrs).forEach((name) => { Object.keys(attrs).forEach((name) => {
element.setAttribute(name, String(attrs[name])); element.setAttribute(name, String(attrs[name]));
}); });
if (children.length) { if (children?.length) {
children.forEach((child) => { children.forEach((child) => {
const childElement = createElement(...child); const childElement = createElement(child);
element.appendChild(childElement); element.appendChild(childElement);
}); });
@@ -25,9 +27,4 @@ const createElement = (tag: string, attrs: SVGProps, children: IconNodeChild[] =
return element; return element;
}; };
/** export default createElement;
* Creates a new HTMLElement from icon node
* @param {[tag: string, attrs: object, children: array]} iconNode
* @returns {HTMLElement}
*/
export default ([tag, attrs, children]: IconNode) => createElement(tag, attrs, children);

View File

@@ -1,4 +1,5 @@
import createElement from './createElement'; import createElement from './createElement';
import defaultAttributes from './defaultAttributes';
import { Icons } from './types'; import { Icons } from './types';
export type CustomAttrs = { [attr: string]: any }; export type CustomAttrs = { [attr: string]: any };
@@ -19,7 +20,9 @@ export const getAttrs = (element: Element): Record<string, string> =>
* @param {Object} attrs * @param {Object} attrs
* @returns {Array} * @returns {Array}
*/ */
export const getClassNames = (attrs: Record<string, string> | string): string | string[] => { export const getClassNames = (
attrs: Record<string, string | string[]> | string,
): string | string[] => {
if (typeof attrs === 'string') return attrs; if (typeof attrs === 'string') return attrs;
if (!attrs || !attrs.class) return ''; if (!attrs || !attrs.class) return '';
if (attrs.class && typeof attrs.class === 'string') { if (attrs.class && typeof attrs.class === 'string') {
@@ -36,7 +39,9 @@ export const getClassNames = (attrs: Record<string, string> | string): string |
* @param {array} arrayOfClassnames * @param {array} arrayOfClassnames
* @returns {string} * @returns {string}
*/ */
export const combineClassNames = (arrayOfClassnames: (string | Record<string, string>)[]) => { export const combineClassNames = (
arrayOfClassnames: (string | Record<string, string | string[]>)[],
) => {
const classNameArray = arrayOfClassnames.flatMap(getClassNames); const classNameArray = arrayOfClassnames.flatMap(getClassNames);
return classNameArray return classNameArray
@@ -77,10 +82,9 @@ const replaceElement = (element: Element, { nameAttr, icons, attrs }: ReplaceEle
} }
const elementAttrs = getAttrs(element); const elementAttrs = getAttrs(element);
const [tag, iconAttributes, children] = iconNode;
const iconAttrs = { const iconAttrs = {
...iconAttributes, ...defaultAttributes,
'data-lucide': iconName, 'data-lucide': iconName,
...attrs, ...attrs,
...elementAttrs, ...elementAttrs,
@@ -94,7 +98,7 @@ const replaceElement = (element: Element, { nameAttr, icons, attrs }: ReplaceEle
}); });
} }
const svgElement = createElement([tag, iconAttrs, children]); const svgElement = createElement(['svg', iconAttrs, iconNode]);
return element.parentNode?.replaceChild(svgElement, element); return element.parentNode?.replaceChild(svgElement, element);
}; };

View File

@@ -1,6 +1,5 @@
// className is not supported in svg elements // className is not supported in svg elements
export type SVGProps = Record<string, string | number>; export type SVGProps = Record<string, string | number>;
export type IconNodeChild = readonly [tag: string, attrs: SVGProps]; export type IconNode = [tag: string, attrs: SVGProps][];
export type IconNode = readonly [tag: string, attrs: SVGProps, children?: IconNodeChild[]];
export type Icons = { [key: string]: IconNode }; export type Icons = { [key: string]: IconNode };

View File

@@ -1,3 +0,0 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`combineClassNames > should retuns a string of classNames 1`] = `"item item1 item2 item3 item4 item5 item6 item7 item8 item9"`;

View File

@@ -0,0 +1,3 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`combineClassNames > should returns a string of classNames 1`] = `"item item1 item2 item3 item4 item5 item6 item7 item8 item9"`;

View File

@@ -6,7 +6,7 @@ import { parseSync, stringify } from 'svgson';
const ICONS_DIR = path.resolve(__dirname, '../../../icons'); const ICONS_DIR = path.resolve(__dirname, '../../../icons');
const getOriginalSvg = (iconName, aliasName) => { const getOriginalSvg = (iconName: string, aliasName?: string) => {
const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8'); const svgContent = fs.readFileSync(path.join(ICONS_DIR, `${iconName}.svg`), 'utf8');
const svgParsed = parseSync(svgContent); const svgParsed = parseSync(svgContent);
@@ -51,14 +51,17 @@ describe('createIcons', () => {
createIcons({ icons, attrs }); createIcons({ icons, attrs });
const element = document.querySelector('svg'); const element = document.querySelector('svg') as SVGSVGElement;
const attributes = element.getAttributeNames(); const attributes = element.getAttributeNames();
const attributesAndValues = attributes.reduce((acc, item) => { const attributesAndValues = attributes.reduce(
acc[item] = element.getAttribute(item); (acc, item) => {
acc[item] = element.getAttribute(item);
return acc; return acc;
}, {}); },
{} as Record<string, string | null>,
);
expect(document.body.innerHTML).toMatchSnapshot(); expect(document.body.innerHTML).toMatchSnapshot();
@@ -74,14 +77,17 @@ describe('createIcons', () => {
createIcons({ icons }); createIcons({ icons });
const element = document.querySelector('svg'); const element = document.querySelector('svg') as SVGSVGElement;
const attributes = element.getAttributeNames(); const attributes = element.getAttributeNames();
const attributesAndValues = attributes.reduce((acc, item) => { const attributesAndValues = attributes.reduce(
acc[item] = element.getAttribute(item); (acc, item) => {
acc[item] = element.getAttribute(item);
return acc; return acc;
}, {}); },
{} as Record<string, string | null>,
);
expect(attributesAndValues).toEqual(expect.objectContaining(attrs)); expect(attributesAndValues).toEqual(expect.objectContaining(attrs));
}); });

View File

@@ -16,7 +16,7 @@ describe('getAtts', () => {
], ],
}; };
const attrs = getAttrs(element); const attrs = getAttrs(element as unknown as Element);
expect(attrs.class).toBe(element.attributes[0].value); expect(attrs.class).toBe(element.attributes[0].value);
}); });
@@ -43,8 +43,8 @@ describe('getClassNames', () => {
}); });
describe('combineClassNames', () => { describe('combineClassNames', () => {
it('should retuns a string of classNames', () => { it('should returns a string of classNames', () => {
const arrayOfClassnames = [ const arrayOfClassnames: (string | Record<string, string[]>)[] = [
'item', 'item',
{ {
class: ['item1', 'item2', 'item3'], class: ['item1', 'item2', 'item3'],

1209
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -7,13 +7,13 @@ import {
const currentDir = getCurrentDirPath(import.meta.url); const currentDir = getCurrentDirPath(import.meta.url);
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const icons = readAllMetadata(ICONS_DIR); const icons = await readAllMetadata(ICONS_DIR);
const CATEGORIES_DIR = path.resolve(currentDir, '../categories'); const CATEGORIES_DIR = path.resolve(currentDir, '../categories');
const categories = readAllMetadata(CATEGORIES_DIR); const categories = await readAllMetadata(CATEGORIES_DIR);
console.log('Reading all icons'); console.log('Reading all icons');
const svgFiles = readSvgDirectory(ICONS_DIR); const svgFiles = await readSvgDirectory(ICONS_DIR);
const iconNames = svgFiles.map((icon) => icon.split('.')[0]); const iconNames = svgFiles.map((icon) => icon.split('.')[0]);
let error = false; let error = false;

View File

@@ -3,7 +3,6 @@ import path from 'path';
import { parseSync } from 'svgson'; import { parseSync } from 'svgson';
import { import {
shuffleArray, shuffleArray,
readSvgDirectory,
getCurrentDirPath, getCurrentDirPath,
minifySvg, minifySvg,
toPascalCase, toPascalCase,
@@ -43,7 +42,7 @@ const getImageTagsByFiles = (files, getBaseUrl, width) =>
return `<img title="${file}" alt="${file}" ${widthAttr} src="${url}/${base64}.svg"/>`; return `<img title="${file}" alt="${file}" ${widthAttr} src="${url}/${base64}.svg"/>`;
}); });
const svgFiles = readSvgDirectory(ICONS_DIR).map((file) => `icons/${file}`); const svgFiles = fs.readdirSync(ICONS_DIR).map((file) => `icons/${file}`);
const iconsFilteredByName = (search) => svgFiles.filter((file) => file.includes(search)); const iconsFilteredByName = (search) => svgFiles.filter((file) => file.includes(search));

View File

@@ -1,5 +1,5 @@
import path from 'path'; import path from 'path';
import categories from '../categories.json' assert { type: 'json' }; import categories from '../categories.json' with { type: 'json' };
import { import {
mergeArrays, mergeArrays,
writeFile, writeFile,

View File

@@ -3,7 +3,7 @@ import { writeFile, getCurrentDirPath, readAllMetadata } from '../tools/build-he
const currentDir = getCurrentDirPath(import.meta.url); const currentDir = getCurrentDirPath(import.meta.url);
const ICONS_DIR = path.resolve(currentDir, '../icons'); const ICONS_DIR = path.resolve(currentDir, '../icons');
const icons = readAllMetadata(ICONS_DIR); const icons = await readAllMetadata(ICONS_DIR);
const tags = Object.keys(icons) const tags = Object.keys(icons)
.sort() .sort()
@@ -14,4 +14,4 @@ const tags = Object.keys(icons)
const tagsContent = JSON.stringify(tags, null, 2); const tagsContent = JSON.stringify(tags, null, 2);
writeFile(tagsContent, 'tags.json', path.resolve(process.cwd())); await writeFile(tagsContent, 'tags.json', path.resolve(process.cwd()));

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -10,4 +10,4 @@ import path from 'path';
* @param {string} outputDirectory * @param {string} outputDirectory
*/ */
export const appendFile = (content, fileName, outputDirectory) => export const appendFile = (content, fileName, outputDirectory) =>
fs.appendFileSync(path.join(outputDirectory, fileName), content, 'utf-8'); fs.appendFile(path.join(outputDirectory, fileName), content, 'utf-8');

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
import { readMetadata } from './readMetadata.mjs'; import { readMetadata } from './readMetadata.mjs';
@@ -9,11 +9,14 @@ import { readMetadata } from './readMetadata.mjs';
* @param {string} directory * @param {string} directory
* @returns {object} A map of icon or category metadata * @returns {object} A map of icon or category metadata
*/ */
export const readAllMetadata = (directory) => export const readAllMetadata = async (directory) => {
fs const directoryContent = await fs.readdir(directory);
.readdirSync(directory)
const metaDataPromises = directoryContent
.filter((file) => path.extname(file) === '.json') .filter((file) => path.extname(file) === '.json')
.reduce((acc, fileName) => { .map(async (file) => [path.basename(file, '.json'), await readMetadata(file, directory)]);
acc[path.basename(fileName, '.json')] = readMetadata(fileName, directory);
return acc; const metadata = await Promise.all(metaDataPromises);
}, {});
return Object.fromEntries(metadata);
};

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -8,4 +8,4 @@ import path from 'path';
* @param {string} path * @param {string} path
* @returns {string} The contents of a file * @returns {string} The contents of a file
*/ */
export const readFile = (path) => fs.readFileSync(path.resolve(__dirname, '../', path), 'utf-8'); export const readFile = (path) => fs.readFile(path.resolve(__dirname, '../', path), 'utf-8');

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -9,5 +9,8 @@ import path from 'path';
* @param {string} directory * @param {string} directory
* @returns {object} The metadata for the icon or category * @returns {object} The metadata for the icon or category
*/ */
export const readMetadata = (fileName, directory) => export const readMetadata = async (fileName, directory) => {
JSON.parse(fs.readFileSync(path.join(directory, fileName), 'utf-8')); const metadataFileContent = await fs.readFile(path.join(directory, fileName), 'utf-8');
return JSON.parse(metadataFileContent);
};

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -9,4 +9,4 @@ import path from 'path';
* @param {string} directory * @param {string} directory
*/ */
export const readSvg = (fileName, directory) => export const readSvg = (fileName, directory) =>
fs.readFileSync(path.join(directory, fileName), 'utf-8'); fs.readFile(path.join(directory, fileName), 'utf-8');

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -9,5 +9,8 @@ import path from 'path';
* @param {string} fileExtension * @param {string} fileExtension
* @returns {array} An array of file paths containing svgs * @returns {array} An array of file paths containing svgs
*/ */
export const readSvgDirectory = (directory, fileExtension = '.svg') => export const readSvgDirectory = async (directory, fileExtension = '.svg') => {
fs.readdirSync(directory).filter((file) => path.extname(file) === fileExtension); const directoryContents = await fs.readdir(directory);
return directoryContents.filter((file) => path.extname(file) === fileExtension);
};

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -9,4 +9,4 @@ import path from 'path';
* @param {string} outputDirectory * @param {string} outputDirectory
*/ */
export const resetFile = (fileName, outputDirectory) => export const resetFile = (fileName, outputDirectory) =>
fs.writeFileSync(path.join(outputDirectory, fileName), '', 'utf-8'); fs.writeFile(path.join(outputDirectory, fileName), '', 'utf-8');

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -10,4 +10,4 @@ import path from 'path';
* @param {string} outputDirectory * @param {string} outputDirectory
*/ */
export const writeFile = (content, fileName, outputDirectory) => export const writeFile = (content, fileName, outputDirectory) =>
fs.writeFileSync(path.join(outputDirectory, fileName), content, 'utf-8'); fs.writeFile(path.join(outputDirectory, fileName), content, 'utf-8');

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
import { writeFile } from './writeFile.mjs'; import { writeFile } from './writeFile.mjs';

View File

@@ -1,5 +1,5 @@
/* eslint-disable import/prefer-default-export */ /* eslint-disable import/prefer-default-export */
import fs from 'fs'; import fs from 'fs/promises';
import path from 'path'; import path from 'path';
/** /**
@@ -10,4 +10,4 @@ import path from 'path';
* @param {string} content * @param {string} content
*/ */
export const writeSvgFile = (fileName, outputDirectory, content) => export const writeSvgFile = (fileName, outputDirectory, content) =>
fs.writeFileSync(path.join(outputDirectory, fileName), content, 'utf-8'); fs.writeFile(path.join(outputDirectory, fileName), content, 'utf-8');

View File

@@ -31,11 +31,11 @@ export default async function generateAliasesFiles({
} }
// Reset files // Reset files
resetFile(aliasFileName, destinationDirectory); await resetFile(aliasFileName, destinationDirectory);
if (!aliasNamesOnly) { if (!aliasNamesOnly) {
resetFile(aliasPrefixesFileName, destinationDirectory); await resetFile(aliasPrefixesFileName, destinationDirectory);
resetFile(aliasSuffixFileName, destinationDirectory); await resetFile(aliasSuffixFileName, destinationDirectory);
} }
// Generate Import for Icon VNodes // Generate Import for Icon VNodes
@@ -149,20 +149,20 @@ export default async function generateAliasesFiles({
); );
} }
appendFile(aliasFileContent, aliasFileName, destinationDirectory); await appendFile(aliasFileContent, aliasFileName, destinationDirectory);
if (!aliasNamesOnly) { if (!aliasNamesOnly) {
appendFile(aliasPrefixesFileContent, aliasPrefixesFileName, destinationDirectory); await appendFile(aliasPrefixesFileContent, aliasPrefixesFileName, destinationDirectory);
appendFile(aliasSuffixFileContent, aliasSuffixFileName, destinationDirectory); await appendFile(aliasSuffixFileContent, aliasSuffixFileName, destinationDirectory);
} }
}), }),
); );
appendFile('\n', aliasFileName, destinationDirectory); await appendFile('\n', aliasFileName, destinationDirectory);
if (!aliasNamesOnly) { if (!aliasNamesOnly) {
appendFile('\n', aliasPrefixesFileName, destinationDirectory); await appendFile('\n', aliasPrefixesFileName, destinationDirectory);
appendFile('\n', aliasSuffixFileName, destinationDirectory); await appendFile('\n', aliasSuffixFileName, destinationDirectory);
} }
if (showLog) { if (showLog) {

View File

@@ -1,7 +1,7 @@
import path from 'path'; import path from 'path';
import { resetFile, appendFile } from '@lucide/helpers'; import { resetFile, appendFile } from '@lucide/helpers';
export default function generateDynamicImports({ export default async function generateDynamicImports({
iconNodes, iconNodes,
outputDirectory, outputDirectory,
fileExtension, fileExtension,
@@ -12,7 +12,7 @@ export default function generateDynamicImports({
const icons = Object.keys(iconNodes); const icons = Object.keys(iconNodes);
// Reset file // Reset file
resetFile(fileName, outputDirectory); await resetFile(fileName, outputDirectory);
let importString = `const dynamicIconImports = {\n`; let importString = `const dynamicIconImports = {\n`;
@@ -40,7 +40,7 @@ export default function generateDynamicImports({
importString += '};\nexport default dynamicIconImports;\n'; importString += '};\nexport default dynamicIconImports;\n';
appendFile(importString, fileName, outputDirectory); await appendFile(importString, fileName, outputDirectory);
if (showLog) { if (showLog) {
console.log(`Successfully generated ${fileName} file`); console.log(`Successfully generated ${fileName} file`);

View File

@@ -3,22 +3,22 @@ import path from 'path';
// eslint-disable-next-line import/no-extraneous-dependencies // eslint-disable-next-line import/no-extraneous-dependencies
import { toPascalCase, toCamelCase, resetFile, appendFile } from '@lucide/helpers'; import { toPascalCase, toCamelCase, resetFile, appendFile } from '@lucide/helpers';
export default ( export default async function generateExportFile(
inputEntry, inputEntry,
outputDirectory, outputDirectory,
iconNodes, iconNodes,
exportModuleNameCasing, exportModuleNameCasing,
iconFileExtension = '', iconFileExtension = '',
) => { ) {
const fileName = path.basename(inputEntry); const fileName = path.basename(inputEntry);
// Reset file // Reset file
resetFile(fileName, outputDirectory); await resetFile(fileName, outputDirectory);
const icons = Object.keys(iconNodes); const icons = Object.keys(iconNodes);
// Generate Import for Icon VNodes // Generate Import for Icon VNodes
icons.forEach((iconName) => { const iconImportNodesPromises = icons.map(async (iconName) => {
let componentName; let componentName;
if (exportModuleNameCasing === 'camel') { if (exportModuleNameCasing === 'camel') {
@@ -27,10 +27,12 @@ export default (
componentName = toPascalCase(iconName); componentName = toPascalCase(iconName);
} }
const importString = `export { default as ${componentName} } from './${iconName}${iconFileExtension}';\n`; const importString = `export { default as ${componentName} } from './${iconName}${iconFileExtension}';\n`;
appendFile(importString, fileName, outputDirectory); return appendFile(importString, fileName, outputDirectory);
}); });
appendFile('\n', fileName, outputDirectory); await Promise.all(iconImportNodesPromises);
await appendFile('\n', fileName, outputDirectory);
console.log(`Successfully generated ${fileName} file`); console.log(`Successfully generated ${fileName} file`);
}; }

View File

@@ -4,7 +4,7 @@ import prettier from 'prettier';
import { readSvg, toPascalCase } from '@lucide/helpers'; import { readSvg, toPascalCase } from '@lucide/helpers';
import deprecationReasonTemplate from '../utils/deprecationReasonTemplate.mjs'; import deprecationReasonTemplate from '../utils/deprecationReasonTemplate.mjs';
export default ({ function generateIconFiles({
iconNodes, iconNodes,
outputDirectory, outputDirectory,
template, template,
@@ -15,7 +15,7 @@ export default ({
pretty = true, pretty = true,
iconsDir, iconsDir,
iconMetaData, iconMetaData,
}) => { }) {
const icons = Object.keys(iconNodes); const icons = Object.keys(iconNodes);
const iconsDistDirectory = path.join(outputDirectory, `icons`); const iconsDistDirectory = path.join(outputDirectory, `icons`);
@@ -40,7 +40,7 @@ export default ({
}) })
: ''; : '';
const elementTemplate = template({ const elementTemplate = await template({
componentName, componentName,
iconName, iconName,
children, children,
@@ -71,7 +71,7 @@ export default ({
} }
}); });
Promise.all(writeIconFiles) return Promise.all(writeIconFiles)
.then(() => { .then(() => {
if (showLog) { if (showLog) {
console.log('Successfully built', icons.length, 'icons.'); console.log('Successfully built', icons.length, 'icons.');
@@ -80,4 +80,6 @@ export default ({
.catch((error) => { .catch((error) => {
throw new Error(`Something went wrong generating icon files,\n ${error}`); throw new Error(`Something went wrong generating icon files,\n ${error}`);
}); });
}; }
export default generateIconFiles;

View File

@@ -47,16 +47,16 @@ async function buildIcons() {
throw new Error('No `templateSrc` argument given.'); throw new Error('No `templateSrc` argument given.');
} }
const svgFiles = readSvgDirectory(ICONS_DIR); const svgFiles = await readSvgDirectory(ICONS_DIR);
const icons = renderIconsObject(svgFiles, ICONS_DIR, renderUniqueKey); const icons = await renderIconsObject(svgFiles, ICONS_DIR, renderUniqueKey);
const { default: iconFileTemplate } = await import(path.resolve(process.cwd(), templateSrc)); const { default: iconFileTemplate } = await import(path.resolve(process.cwd(), templateSrc));
const iconMetaData = await getIconMetaData(ICONS_DIR); const iconMetaData = await getIconMetaData(ICONS_DIR);
// Generates iconsNodes files for each icon // Generates iconsNodes files for each icon
generateIconFiles({ await generateIconFiles({
iconNodes: icons, iconNodes: icons,
outputDirectory: OUTPUT_DIR, outputDirectory: OUTPUT_DIR,
template: iconFileTemplate, template: iconFileTemplate,
@@ -86,7 +86,7 @@ async function buildIcons() {
} }
if (withDynamicImports) { if (withDynamicImports) {
generateDynamicImports({ await generateDynamicImports({
iconNodes: icons, iconNodes: icons,
outputDirectory: OUTPUT_DIR, outputDirectory: OUTPUT_DIR,
fileExtension: aliasesFileExtension, fileExtension: aliasesFileExtension,
@@ -96,7 +96,7 @@ async function buildIcons() {
} }
// Generates entry files for the compiler filled with icons exports // Generates entry files for the compiler filled with icons exports
generateExportsFile( await generateExportsFile(
path.join(OUTPUT_DIR, 'icons', exportFileName), path.join(OUTPUT_DIR, 'icons', exportFileName),
path.join(OUTPUT_DIR, 'icons'), path.join(OUTPUT_DIR, 'icons'),
icons, icons,

View File

@@ -20,11 +20,13 @@
"@lucide/helpers": "workspace:*" "@lucide/helpers": "workspace:*"
}, },
"dependencies": { "dependencies": {
"@lucide/helpers": "^1.0.0",
"minimist": "^1.2.7", "minimist": "^1.2.7",
"node-fetch": "^3.2.10", "node-fetch": "^3.2.10",
"prettier": "2.7.1", "prettier": "2.7.1",
"svgo": "^3.0.0", "svgo": "^3.0.0",
"svgson": "^5.2.1" "svgson": "^5.2.1"
},
"peerDependencies": {
"@lucide/helpers": "*"
} }
} }

View File

@@ -8,32 +8,39 @@ import { generateHashedKey, readSvg, hasDuplicatedChildren } from '@lucide/helpe
* @param {Function} getSvg - A function that returns the contents of an SVG file given a filename. * @param {Function} getSvg - A function that returns the contents of an SVG file given a filename.
* @returns {Object} * @returns {Object}
*/ */
export default (svgFiles, iconsDirectory, renderUniqueKey = false) => export default async function generateIconObject(
svgFiles svgFiles,
.map((svgFile) => { iconsDirectory,
const name = basename(svgFile, '.svg'); renderUniqueKey = false,
const svg = readSvg(svgFile, iconsDirectory); ) {
const contents = parseSync(svg); const svgsContentPromises = svgFiles.map(async (svgFile) => {
const name = basename(svgFile, '.svg');
const svg = await readSvg(svgFile, iconsDirectory);
const contents = parseSync(svg);
if (!(contents.children && contents.children.length)) { if (!(contents.children && contents.children.length)) {
throw new Error(`${name}.svg has no children!`); throw new Error(`${name}.svg has no children!`);
} }
if (hasDuplicatedChildren(contents.children)) { if (hasDuplicatedChildren(contents.children)) {
throw new Error(`Duplicated children in ${name}.svg`); throw new Error(`Duplicated children in ${name}.svg`);
} }
if (renderUniqueKey) { if (renderUniqueKey) {
contents.children = contents.children.map((child) => { contents.children = contents.children.map((child) => {
child.attributes.key = generateHashedKey(child); child.attributes.key = generateHashedKey(child);
return child; return child;
}); });
} }
return { name, contents }; return { name, contents };
}) });
.reduce((icons, icon) => {
icons[icon.name] = icon.contents; const svgsContents = await Promise.all(svgsContentPromises);
return icons;
}, {}); return svgsContents.reduce((icons, icon) => {
icons[icon.name] = icon.contents;
return icons;
}, {});
}

View File

@@ -2,7 +2,7 @@ import path from 'path';
import { readSvgDirectory } from '@lucide/helpers'; import { readSvgDirectory } from '@lucide/helpers';
async function getAliases(iconDirectory) { async function getAliases(iconDirectory) {
const iconJsons = readSvgDirectory(iconDirectory, '.json'); const iconJsons = await readSvgDirectory(iconDirectory, '.json');
const aliasesEntries = await Promise.all( const aliasesEntries = await Promise.all(
iconJsons.map(async (jsonFile) => { iconJsons.map(async (jsonFile) => {
const file = await import(path.join(iconDirectory, jsonFile), { with: { type: 'json' } }); const file = await import(path.join(iconDirectory, jsonFile), { with: { type: 'json' } });

View File

@@ -2,7 +2,7 @@ import path from 'path';
import { readSvgDirectory } from '@lucide/helpers'; import { readSvgDirectory } from '@lucide/helpers';
async function getIconMetaData(iconDirectory) { async function getIconMetaData(iconDirectory) {
const iconJsons = readSvgDirectory(iconDirectory, '.json'); const iconJsons = await readSvgDirectory(iconDirectory, '.json');
const aliasesEntries = await Promise.all( const aliasesEntries = await Promise.all(
iconJsons.map(async (jsonFile) => { iconJsons.map(async (jsonFile) => {
/** eslint-disable */ /** eslint-disable */

View File

@@ -11,7 +11,7 @@
"@atomico/rollup-plugin-sizes": "^1.1.4", "@atomico/rollup-plugin-sizes": "^1.1.4",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^6.0.1", "@rollup/plugin-replace": "^6.0.1",
"esbuild": "^0.19.11", "esbuild": "^0.25.0",
"rollup": "^4.22.4", "rollup": "^4.22.4",
"rollup-plugin-esbuild": "^6.1.0", "rollup-plugin-esbuild": "^6.1.0",
"rollup-plugin-license": "^3.2.0", "rollup-plugin-license": "^3.2.0",