Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
062894e113 | ||
|
|
eaa99b35f6 | ||
|
|
7c22ccfab4 | ||
|
|
e0e171db81 | ||
|
|
3b11552e5e | ||
|
|
d8b455b614 | ||
|
|
79eecc89f6 | ||
|
|
b943430a08 | ||
|
|
cebb0ee84b | ||
|
|
210c56807e | ||
|
|
c2a8f31176 | ||
|
|
a3f70d5b8b | ||
|
|
c97c6ed9e4 | ||
|
|
e9d69c6948 | ||
|
|
270c935cd4 |
5
.github/workflows/ci.yml
vendored
@@ -63,11 +63,16 @@ jobs:
|
||||
id: change-log
|
||||
run: |
|
||||
CHANGE_LOG=$(pnpm run generate:changelog --old-tag=${{ steps.latest-tag.outputs.LATEST_TAG }})
|
||||
CHANGE_LOG=$(tail -n +5 <<< $CHANGE_LOG)
|
||||
CHANGE_LOG="${CHANGE_LOG//'%'/'%25'}"
|
||||
CHANGE_LOG="${CHANGE_LOG//$'\n'/'%0A'}"
|
||||
CHANGE_LOG="${CHANGE_LOG//$'\r'/'%0D'}"
|
||||
echo $CHANGE_LOG
|
||||
echo "CHANGE_LOG=$CHANGE_LOG" >> $GITHUB_OUTPUT
|
||||
env:
|
||||
GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Check output
|
||||
run: |
|
||||
echo '${{ steps.new-version.outputs.NEW_VERSION }}'
|
||||
|
||||
2
.github/workflows/release.yml
vendored
@@ -196,8 +196,8 @@ jobs:
|
||||
]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/download-artifact@v2
|
||||
|
||||
- name: Zip font and icons
|
||||
run: |
|
||||
zip -r lucide-font-${{ needs.pre-release.outputs.VERSION }}.zip lucide-font
|
||||
|
||||
1
.gitignore
vendored
@@ -17,6 +17,7 @@ packages/**/src/icons/*.js
|
||||
packages/**/src/icons/*.ts
|
||||
packages/**/src/icons/*.tsx
|
||||
packages/**/src/aliases.ts
|
||||
packages/**/src/dynamicIconImports.ts
|
||||
packages/**/LICENSE
|
||||
categories.json
|
||||
tags.json
|
||||
|
||||
@@ -67,6 +67,8 @@ It is possible to create one generic icon component to load icons. It's not reco
|
||||
|
||||
::: danger
|
||||
Example below importing all ES Modules, caution using this example. All icons will be imported. When using bundlers like: `Webpack`, `Rollup` or `Vite` the application build size will grow strongly and harming the performance the application.
|
||||
|
||||
This is not the case for the latest NextJS, because it uses server side rendering. The icons will be streamed to the client when needed. For NextJS with Dynamic Imports, see [dynamic imports](#nextjs-example) section for more information.
|
||||
:::
|
||||
|
||||
### Icon Component Example
|
||||
@@ -94,3 +96,59 @@ const App = () => {
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
#### With Dynamic Imports
|
||||
|
||||
> :warning: This is experimental and only works with bundlers that support dynamic imports.
|
||||
|
||||
Lucide react exports a dynamic import map `dynamicIconImports`. Useful for applications that want to show icons dynamically by icon name. For example when using a content management system with where icon names are stored in a database.
|
||||
|
||||
When using client side rendering, it will fetch the icon component when it's needed. This will reduce the initial bundle size.
|
||||
|
||||
The keys of the dynamic import map are the lucide original icon names (kebab case).
|
||||
|
||||
Example with React suspense:
|
||||
|
||||
```tsx
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
const fallback = <div style={{ background: '#ddd', width: 24, height: 24 }}/>
|
||||
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={fallback}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default Icon
|
||||
```
|
||||
|
||||
##### NextJS Example
|
||||
|
||||
In NextJS [the dynamic function](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#nextdynamic) can be used to load the icon component dynamically.
|
||||
|
||||
```tsx
|
||||
import dynamic from 'next/dynamic'
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
interface IconProps extends LucideProps {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = dynamic(dynamicIconImports[name])
|
||||
|
||||
return <LucideIcon {...props} />;
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
31
icons/antenna.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"signal",
|
||||
"connection",
|
||||
"connectivity",
|
||||
"tv",
|
||||
"television",
|
||||
"broadcast",
|
||||
"live",
|
||||
"frequency",
|
||||
"tune",
|
||||
"scan",
|
||||
"channels",
|
||||
"aerial",
|
||||
"receiver",
|
||||
"transmission",
|
||||
"transducer",
|
||||
"terrestrial",
|
||||
"satellite",
|
||||
"cable"
|
||||
],
|
||||
"categories": [
|
||||
"devices",
|
||||
"multimedia",
|
||||
"communication"
|
||||
]
|
||||
}
|
||||
18
icons/antenna.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<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="M2 12 7 2" />
|
||||
<path d="m7 12 5-10" />
|
||||
<path d="m12 12 5-10" />
|
||||
<path d="m17 12 5-10" />
|
||||
<path d="M4.5 7h15" />
|
||||
<path d="M12 16v6" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 362 B |
@@ -6,9 +6,12 @@
|
||||
],
|
||||
"tags": [
|
||||
"robot",
|
||||
"ai"
|
||||
"ai",
|
||||
"chat",
|
||||
"assistant"
|
||||
],
|
||||
"categories": [
|
||||
"development"
|
||||
"development",
|
||||
"social"
|
||||
]
|
||||
}
|
||||
41
icons/cable.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"cord",
|
||||
"wire",
|
||||
"connector",
|
||||
"connection",
|
||||
"link",
|
||||
"signal",
|
||||
"console",
|
||||
"computer",
|
||||
"equipment",
|
||||
"electricity",
|
||||
"electronics",
|
||||
"recharging",
|
||||
"charger",
|
||||
"power",
|
||||
"supply",
|
||||
"disconnected",
|
||||
"unplugged",
|
||||
"plugs",
|
||||
"interface",
|
||||
"input",
|
||||
"output",
|
||||
"audio video",
|
||||
"av",
|
||||
"rca",
|
||||
"scart",
|
||||
"tv",
|
||||
"television",
|
||||
"optical"
|
||||
],
|
||||
"categories": [
|
||||
"connectivity",
|
||||
"devices",
|
||||
"multimedia"
|
||||
]
|
||||
}
|
||||
19
icons/cable.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<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="M4 9a2 2 0 0 1-2-2V5h6v2a2 2 0 0 1-2 2Z" />
|
||||
<path d="M3 5V3" />
|
||||
<path d="M7 5V3" />
|
||||
<path d="M19 15V6.5a3.5 3.5 0 0 0-7 0v11a3.5 3.5 0 0 1-7 0V9" />
|
||||
<path d="M17 21v-2" />
|
||||
<path d="M21 21v-2" />
|
||||
<path d="M22 19h-6v-2a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 483 B |
14
icons/computer.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"tags": [
|
||||
"pc",
|
||||
"chassis",
|
||||
"codespaces",
|
||||
"github"
|
||||
],
|
||||
"categories": [
|
||||
"devices",
|
||||
"development",
|
||||
"gaming"
|
||||
]
|
||||
}
|
||||
16
icons/computer.svg
Normal 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"
|
||||
>
|
||||
<rect width="14" height="8" x="5" y="2" rx="2" />
|
||||
<rect width="20" height="8" x="2" y="14" rx="2" />
|
||||
<path d="M6 18h2" />
|
||||
<path d="M12 18h6" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 360 B |
@@ -7,7 +7,8 @@
|
||||
],
|
||||
"tags": [
|
||||
"import",
|
||||
"export"
|
||||
"export",
|
||||
"save"
|
||||
],
|
||||
"categories": [
|
||||
"arrows",
|
||||
|
||||
18
icons/gauge-circle.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"tags": [
|
||||
"dashboard",
|
||||
"dial",
|
||||
"meter",
|
||||
"speed",
|
||||
"pressure",
|
||||
"measure",
|
||||
"level"
|
||||
],
|
||||
"categories": [
|
||||
"account",
|
||||
"transportation",
|
||||
"sports",
|
||||
"science"
|
||||
]
|
||||
}
|
||||
15
icons/gauge-circle.svg
Normal 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="M15.6 2.7a10 10 0 1 0 5.7 5.7" />
|
||||
<circle cx="12" cy="12" r="2" />
|
||||
<path d="M13.4 10.6 19 5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 319 B |
@@ -12,7 +12,8 @@
|
||||
"meter",
|
||||
"speed",
|
||||
"pressure",
|
||||
"measure"
|
||||
"measure",
|
||||
"level"
|
||||
],
|
||||
"categories": [
|
||||
"account",
|
||||
|
||||
22
icons/hard-drive-download.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"computer",
|
||||
"server",
|
||||
"memory",
|
||||
"data",
|
||||
"ssd",
|
||||
"disk",
|
||||
"hard disk",
|
||||
"save"
|
||||
],
|
||||
"categories": [
|
||||
"development",
|
||||
"devices",
|
||||
"arrows",
|
||||
"files"
|
||||
]
|
||||
}
|
||||
17
icons/hard-drive-download.svg
Normal 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="M12 2v8" />
|
||||
<path d="m16 6-4 4-4-4" />
|
||||
<rect width="20" height="8" x="2" y="14" rx="2" />
|
||||
<path d="M6 18h.01" />
|
||||
<path d="M10 18h.01" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 364 B |
22
icons/hard-drive-upload.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"computer",
|
||||
"server",
|
||||
"memory",
|
||||
"data",
|
||||
"ssd",
|
||||
"disk",
|
||||
"hard disk",
|
||||
"save"
|
||||
],
|
||||
"categories": [
|
||||
"development",
|
||||
"devices",
|
||||
"arrows",
|
||||
"files"
|
||||
]
|
||||
}
|
||||
17
icons/hard-drive-upload.svg
Normal 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="m16 6-4-4-4 4" />
|
||||
<path d="M12 2v8" />
|
||||
<rect width="20" height="8" x="2" y="14" rx="2" />
|
||||
<path d="M6 18h.01" />
|
||||
<path d="M10 18h.01" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 364 B |
28
icons/hdmi-port.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"socket",
|
||||
"plug",
|
||||
"slot",
|
||||
"controller",
|
||||
"connector",
|
||||
"interface",
|
||||
"console",
|
||||
"signal",
|
||||
"audio",
|
||||
"video",
|
||||
"visual",
|
||||
"av",
|
||||
"data",
|
||||
"input",
|
||||
"output"
|
||||
],
|
||||
"categories": [
|
||||
"devices",
|
||||
"multimedia",
|
||||
"gaming"
|
||||
]
|
||||
}
|
||||
14
icons/hdmi-port.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<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="M22 9a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h1l2 2h12l2-2h1a1 1 0 0 0 1-1Z" />
|
||||
<path d="M7.5 12h9" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 330 B |
@@ -6,8 +6,16 @@
|
||||
],
|
||||
"tags": [
|
||||
"subtract",
|
||||
"remove",
|
||||
"decrease",
|
||||
"reduce",
|
||||
"calculate",
|
||||
"maths",
|
||||
"line",
|
||||
"operator",
|
||||
"code",
|
||||
"coding",
|
||||
"minimum",
|
||||
"downgrade",
|
||||
"-"
|
||||
],
|
||||
"categories": [
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<line x1="8" x2="16" y1="12" y2="12" />
|
||||
<path d="M8 12h8" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 267 B |
@@ -6,12 +6,34 @@
|
||||
],
|
||||
"tags": [
|
||||
"subtract",
|
||||
"calculate",
|
||||
"maths",
|
||||
"-"
|
||||
"remove",
|
||||
"decrease",
|
||||
"reduce",
|
||||
"calculator",
|
||||
"button",
|
||||
"keyboard",
|
||||
"line",
|
||||
"divider",
|
||||
"separator",
|
||||
"horizontal rule",
|
||||
"hr",
|
||||
"html",
|
||||
"markup",
|
||||
"markdown",
|
||||
"---",
|
||||
"toolbar",
|
||||
"operator",
|
||||
"code",
|
||||
"coding",
|
||||
"minimum",
|
||||
"downgrade"
|
||||
],
|
||||
"categories": [
|
||||
"maths",
|
||||
"development",
|
||||
"text",
|
||||
"tools",
|
||||
"devices",
|
||||
"shapes"
|
||||
]
|
||||
}
|
||||
@@ -9,6 +9,6 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
||||
<line x1="8" x2="16" y1="12" y2="12" />
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
<path d="M8 12h8" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 310 B After Width: | Height: | Size: 284 B |
@@ -6,20 +6,33 @@
|
||||
],
|
||||
"tags": [
|
||||
"subtract",
|
||||
"remove",
|
||||
"decrease",
|
||||
"decrement",
|
||||
"reduce",
|
||||
"negative",
|
||||
"calculate",
|
||||
"maths",
|
||||
"line",
|
||||
"divide",
|
||||
"division",
|
||||
"divider",
|
||||
"separator",
|
||||
"horizontal rule",
|
||||
"hr",
|
||||
"html",
|
||||
"markup",
|
||||
"markdown",
|
||||
"---",
|
||||
"toolbar",
|
||||
"operator",
|
||||
"code",
|
||||
"-"
|
||||
"coding",
|
||||
"minimum",
|
||||
"downgrade"
|
||||
],
|
||||
"categories": [
|
||||
"maths",
|
||||
"shapes",
|
||||
"development"
|
||||
"development",
|
||||
"text",
|
||||
"tools",
|
||||
"shapes"
|
||||
]
|
||||
}
|
||||
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="5" x2="19" y1="12" y2="12" />
|
||||
<path d="M5 12h14" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 232 B |
@@ -7,11 +7,31 @@
|
||||
"tags": [
|
||||
"add",
|
||||
"new",
|
||||
"maths",
|
||||
"increase",
|
||||
"increment",
|
||||
"positive",
|
||||
"calculate",
|
||||
"crosshair",
|
||||
"aim",
|
||||
"target",
|
||||
"scope",
|
||||
"sight",
|
||||
"reticule",
|
||||
"maximum",
|
||||
"upgrade",
|
||||
"extra",
|
||||
"operator",
|
||||
"join",
|
||||
"concatenate",
|
||||
"code",
|
||||
"coding",
|
||||
"+"
|
||||
],
|
||||
"categories": [
|
||||
"maths",
|
||||
"shapes"
|
||||
"development",
|
||||
"shapes",
|
||||
"cursors",
|
||||
"gaming"
|
||||
]
|
||||
}
|
||||
@@ -10,6 +10,6 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<line x1="12" x2="12" y1="8" y2="16" />
|
||||
<line x1="8" x2="16" y1="12" y2="12" />
|
||||
<path d="M8 12h8" />
|
||||
<path d="M12 8v8" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 290 B |
@@ -7,11 +7,29 @@
|
||||
"tags": [
|
||||
"add",
|
||||
"new",
|
||||
"maths",
|
||||
"increase",
|
||||
"increment",
|
||||
"positive",
|
||||
"calculate",
|
||||
"calculator",
|
||||
"button",
|
||||
"keyboard",
|
||||
"toolbar",
|
||||
"maximum",
|
||||
"upgrade",
|
||||
"extra",
|
||||
"operator",
|
||||
"join",
|
||||
"concatenate",
|
||||
"code",
|
||||
"coding",
|
||||
"+"
|
||||
],
|
||||
"categories": [
|
||||
"maths",
|
||||
"tools",
|
||||
"development",
|
||||
"text",
|
||||
"shapes"
|
||||
]
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
||||
<line x1="12" x2="12" y1="8" y2="16" />
|
||||
<line x1="8" x2="16" y1="12" y2="12" />
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
<path d="M8 12h8" />
|
||||
<path d="M12 8v8" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 307 B |
@@ -7,15 +7,28 @@
|
||||
"tags": [
|
||||
"add",
|
||||
"new",
|
||||
"maths",
|
||||
"operator",
|
||||
"join",
|
||||
"concatenate",
|
||||
"code",
|
||||
"increase",
|
||||
"increment",
|
||||
"positive",
|
||||
"calculate",
|
||||
"toolbar",
|
||||
"crosshair",
|
||||
"aim",
|
||||
"target",
|
||||
"scope",
|
||||
"sight",
|
||||
"reticule",
|
||||
"maximum",
|
||||
"upgrade",
|
||||
"extra",
|
||||
"+"
|
||||
],
|
||||
"categories": [
|
||||
"maths",
|
||||
"development"
|
||||
"tools",
|
||||
"development",
|
||||
"text",
|
||||
"cursors",
|
||||
"gaming"
|
||||
]
|
||||
}
|
||||
@@ -9,6 +9,6 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<line x1="12" x2="12" y1="5" y2="19" />
|
||||
<line x1="5" x2="19" y1="12" y2="12" />
|
||||
<path d="M5 12h14" />
|
||||
<path d="M12 5v14" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 292 B After Width: | Height: | Size: 256 B |
29
icons/ratio.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"screens",
|
||||
"rotate",
|
||||
"rotation",
|
||||
"aspect ratio",
|
||||
"proportions",
|
||||
"16:9",
|
||||
"widescreen",
|
||||
"4:3",
|
||||
"responsive",
|
||||
"mobile",
|
||||
"desktop",
|
||||
"monitor",
|
||||
"orientation",
|
||||
"portrait",
|
||||
"landscape"
|
||||
],
|
||||
"categories": [
|
||||
"connectivity",
|
||||
"devices",
|
||||
"design",
|
||||
"photography"
|
||||
]
|
||||
}
|
||||
14
icons/ratio.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<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"
|
||||
>
|
||||
<rect width="12" height="20" x="6" y="2" rx="2" />
|
||||
<rect width="20" height="12" x="2" y="6" rx="2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 314 B |
20
icons/scissors-line-dashed.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"cut here",
|
||||
"along",
|
||||
"snip",
|
||||
"chop",
|
||||
"stationery",
|
||||
"crafts",
|
||||
"instructions",
|
||||
"diagram"
|
||||
],
|
||||
"categories": [
|
||||
"design",
|
||||
"tools"
|
||||
]
|
||||
}
|
||||
19
icons/scissors-line-dashed.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<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="M5.42 9.42 8 12" />
|
||||
<circle cx="4" cy="8" r="2" />
|
||||
<path d="m14 6-8.58 8.58" />
|
||||
<circle cx="4" cy="16" r="2" />
|
||||
<path d="M10.8 14.8 14 18" />
|
||||
<path d="M16 12h-2" />
|
||||
<path d="M22 12h-2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 419 B |
20
icons/scissors-square-dashed-bottom.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"cut",
|
||||
"snippet",
|
||||
"chop",
|
||||
"stationery",
|
||||
"crafts"
|
||||
],
|
||||
"categories": [
|
||||
"text",
|
||||
"design",
|
||||
"tools",
|
||||
"files",
|
||||
"development"
|
||||
]
|
||||
}
|
||||
20
icons/scissors-square-dashed-bottom.svg
Normal 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="M4 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2" />
|
||||
<path d="M10 22H8" />
|
||||
<path d="M16 22h-2" />
|
||||
<circle cx="8" cy="8" r="2" />
|
||||
<path d="M9.414 9.414 12 12" />
|
||||
<path d="M14.8 14.8 18 18" />
|
||||
<circle cx="8" cy="16" r="2" />
|
||||
<path d="m18 6-8.586 8.586" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 508 B |
22
icons/scissors-square.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"cut",
|
||||
"snippet",
|
||||
"chop",
|
||||
"stationery",
|
||||
"crafts",
|
||||
"toolbar",
|
||||
"button"
|
||||
],
|
||||
"categories": [
|
||||
"text",
|
||||
"design",
|
||||
"tools",
|
||||
"files",
|
||||
"development"
|
||||
]
|
||||
}
|
||||
18
icons/scissors-square.svg
Normal file
@@ -0,0 +1,18 @@
|
||||
<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"
|
||||
>
|
||||
<rect width="20" height="20" x="2" y="2" rx="2" />
|
||||
<circle cx="8" cy="8" r="2" />
|
||||
<path d="M9.414 9.414 12 12" />
|
||||
<path d="M14.8 14.8 18 18" />
|
||||
<circle cx="8" cy="16" r="2" />
|
||||
<path d="m18 6-8.586 8.586" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 427 B |
@@ -5,10 +5,15 @@
|
||||
"ericfennis"
|
||||
],
|
||||
"tags": [
|
||||
"cut"
|
||||
"cut",
|
||||
"snip",
|
||||
"chop",
|
||||
"stationery",
|
||||
"crafts"
|
||||
],
|
||||
"categories": [
|
||||
"text",
|
||||
"design"
|
||||
"design",
|
||||
"tools"
|
||||
]
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="6" cy="6" r="3" />
|
||||
<path d="M8.12 8.12 12 12" />
|
||||
<path d="M20 4 8.12 15.88" />
|
||||
<circle cx="6" cy="18" r="3" />
|
||||
<line x1="20" x2="8.12" y1="4" y2="15.88" />
|
||||
<line x1="14.47" x2="20" y1="14.48" y2="20" />
|
||||
<line x1="8.12" x2="12" y1="8.12" y2="12" />
|
||||
<path d="M14.8 14.8 20 20" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 371 B |
@@ -9,7 +9,7 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z" />
|
||||
<line x1="3" x2="21" y1="6" y2="6" />
|
||||
<path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z" />
|
||||
<path d="M3 6h18" />
|
||||
<path d="M16 10a4 4 0 0 1-8 0" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 333 B |
18
icons/shopping-basket.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"cart",
|
||||
"e-commerce",
|
||||
"store",
|
||||
"purchase",
|
||||
"products",
|
||||
"items",
|
||||
"ingredients"
|
||||
],
|
||||
"categories": [
|
||||
"shopping"
|
||||
]
|
||||
}
|
||||
19
icons/shopping-basket.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<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="m5 11 4-7" />
|
||||
<path d="m19 11-4-7" />
|
||||
<path d="M2 11h20" />
|
||||
<path d="m3.5 11 1.6 7.4a2 2 0 0 0 2 1.6h9.8c.9 0 1.8-.7 2-1.6l1.7-7.4" />
|
||||
<path d="m9 11 1 9" />
|
||||
<path d="M4.5 15.5h15" />
|
||||
<path d="m15 11-1 9" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 439 B |
@@ -7,10 +7,15 @@
|
||||
"karsa-mistmere"
|
||||
],
|
||||
"tags": [
|
||||
"ecommerce",
|
||||
"trolley",
|
||||
"cart",
|
||||
"basket",
|
||||
"e-commerce",
|
||||
"store",
|
||||
"purchase",
|
||||
"store"
|
||||
"products",
|
||||
"items",
|
||||
"ingredients"
|
||||
],
|
||||
"categories": [
|
||||
"shopping"
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" ry="2" />
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 261 B |
22
icons/triangle-right.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"contributors": [
|
||||
"danielbayley"
|
||||
],
|
||||
"tags": [
|
||||
"volume",
|
||||
"controls",
|
||||
"controller",
|
||||
"tv remote",
|
||||
"geometry",
|
||||
"delta",
|
||||
"ramp",
|
||||
"slope",
|
||||
"incline",
|
||||
"increase"
|
||||
],
|
||||
"categories": [
|
||||
"shapes",
|
||||
"maths"
|
||||
]
|
||||
}
|
||||
13
icons/triangle-right.svg
Normal 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"
|
||||
>
|
||||
<path d="M22 18a2 2 0 0 1-2 2H3c-1.1 0-1.3-.6-.4-1.3L20.4 4.3c.9-.7 1.6-.4 1.6.7Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 296 B |
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"$schema": "../icon.schema.json",
|
||||
"aliases": [
|
||||
"tv-2"
|
||||
],
|
||||
"contributors": [
|
||||
"ericfennis"
|
||||
],
|
||||
@@ -7,7 +10,21 @@
|
||||
"flatscreen",
|
||||
"television",
|
||||
"stream",
|
||||
"display"
|
||||
"display",
|
||||
"widescreen",
|
||||
"high-definition",
|
||||
"hd",
|
||||
"1080p",
|
||||
"4k",
|
||||
"8k",
|
||||
"smart",
|
||||
"digital",
|
||||
"video",
|
||||
"home cinema",
|
||||
"entertainment",
|
||||
"showtime",
|
||||
"channels",
|
||||
"catchup"
|
||||
],
|
||||
"categories": [
|
||||
"devices",
|
||||
|
||||
@@ -6,10 +6,38 @@
|
||||
],
|
||||
"tags": [
|
||||
"television",
|
||||
"stream"
|
||||
"stream",
|
||||
"display",
|
||||
"widescreen",
|
||||
"high-definition",
|
||||
"hd",
|
||||
"1080p",
|
||||
"4k",
|
||||
"8k",
|
||||
"smart",
|
||||
"digital",
|
||||
"video",
|
||||
"entertainment",
|
||||
"showtime",
|
||||
"channels",
|
||||
"terrestrial",
|
||||
"satellite",
|
||||
"cable",
|
||||
"broadcast",
|
||||
"live",
|
||||
"frequency",
|
||||
"tune",
|
||||
"scan",
|
||||
"aerial",
|
||||
"receiver",
|
||||
"transmission",
|
||||
"signal",
|
||||
"connection",
|
||||
"connectivity"
|
||||
],
|
||||
"categories": [
|
||||
"devices",
|
||||
"multimedia"
|
||||
"multimedia",
|
||||
"communication"
|
||||
]
|
||||
}
|
||||
@@ -60,7 +60,7 @@ It is possible to create a generic icon component to load icons.
|
||||
> :warning: The example below is importing all ES modules. This is **not** recommended when you using a bundler since your application build size will grow substantially.
|
||||
|
||||
```js
|
||||
import * as icons from 'lucide-react';
|
||||
import { icons } from 'lucide-react';
|
||||
|
||||
const Icon = ({ name, color, size }) => {
|
||||
const LucideIcon = icons[name];
|
||||
@@ -70,3 +70,59 @@ const Icon = ({ name, color, size }) => {
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
#### With Dynamic Imports
|
||||
|
||||
> :warning: This is experimental and only works with bundlers that support dynamic imports.
|
||||
|
||||
Lucide react exports a dynamic import map `dynamicIconImports`. Useful for applications that want to show icons dynamically by icon name. For example when using a content management system with where icon names are stored in a database.
|
||||
|
||||
When using client side rendering, it will fetch the icon component when it's needed. This will reduce the initial bundle size.
|
||||
|
||||
The keys of the dynamic import map are the lucide original icon names.
|
||||
|
||||
Example with React suspense:
|
||||
|
||||
```tsx
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
const fallback = <div style={{ background: '#ddd', width: 24, height: 24 }}/>
|
||||
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={fallback}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
export default Icon
|
||||
```
|
||||
|
||||
##### NextJS Example
|
||||
|
||||
In NextJS [the dynamic function](https://nextjs.org/docs/pages/building-your-application/optimizing/lazy-loading#nextdynamic) can be used to load the icon component dynamically.
|
||||
|
||||
```tsx
|
||||
import dynamic from 'next/dynamic'
|
||||
import { dynamicIconImports, LucideProps } from 'lucide-react';
|
||||
|
||||
interface IconProps extends LucideProps {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = dynamic(dynamicIconImports[name])
|
||||
|
||||
return <LucideIcon {...props} />;
|
||||
};
|
||||
|
||||
export default Icon;
|
||||
```
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm typecheck && pnpm build:bundles && pnpm build:types",
|
||||
"build": "pnpm clean && pnpm copy:license && pnpm build:icons && pnpm typecheck && pnpm build:bundles",
|
||||
"copy:license": "cp ../../LICENSE ./LICENSE",
|
||||
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts",
|
||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts",
|
||||
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mjs --renderUniqueKey --withAliases --withDynamicImports --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts",
|
||||
"build:types": "node ./scripts/buildTypes.mjs",
|
||||
"build:bundles": "rollup -c ./rollup.config.mjs",
|
||||
"typecheck": "tsc",
|
||||
@@ -44,6 +44,7 @@
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"rollup": "^3.5.1",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
"typescript": "^4.8.4",
|
||||
"vite": "^4.3.9",
|
||||
"vitest": "^0.32.2"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import plugins, { replace } from '@lucide/rollup-plugins';
|
||||
import pkg from './package.json' assert { type: 'json' };
|
||||
import dts from "rollup-plugin-dts";
|
||||
|
||||
const packageName = 'LucideReact';
|
||||
const outputFileName = 'lucide-react';
|
||||
@@ -21,19 +22,21 @@ const bundles = [
|
||||
format: 'cjs',
|
||||
inputs,
|
||||
outputDir,
|
||||
aliasesSupport: true
|
||||
aliasesSupport: true,
|
||||
withDynamicImports: true,
|
||||
},
|
||||
{
|
||||
format: 'esm',
|
||||
inputs,
|
||||
outputDir,
|
||||
preserveModules: true,
|
||||
aliasesSupport: true
|
||||
aliasesSupport: true,
|
||||
withDynamicImports: true,
|
||||
},
|
||||
];
|
||||
|
||||
const configs = bundles
|
||||
.map(({ inputs, outputDir, format, minify, preserveModules, aliasesSupport }) =>
|
||||
.map(({ inputs, outputDir, format, minify, preserveModules, aliasesSupport, withDynamicImports }) =>
|
||||
inputs.map(input => ({
|
||||
input,
|
||||
plugins: [
|
||||
@@ -47,6 +50,15 @@ const configs = bundles
|
||||
}),
|
||||
] : []
|
||||
),
|
||||
...(
|
||||
!withDynamicImports ? [
|
||||
replace({
|
||||
"export { default as dynamicIconImports } from './dynamicIconImports';": '',
|
||||
delimiters: ['', ''],
|
||||
preventAssignment: false,
|
||||
}),
|
||||
] : []
|
||||
),
|
||||
...plugins(pkg, minify)
|
||||
],
|
||||
external: ['react', 'prop-types'],
|
||||
@@ -71,4 +83,13 @@ const configs = bundles
|
||||
)
|
||||
.flat();
|
||||
|
||||
export default configs;
|
||||
export default [
|
||||
{
|
||||
input: inputs[0],
|
||||
output: [{
|
||||
file: `dist/${outputFileName}.d.ts`, format: "es"
|
||||
}],
|
||||
plugins: [dts()],
|
||||
},
|
||||
...configs
|
||||
];
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
import path from 'path';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { getAliases } from '@lucide/build-icons';
|
||||
import {
|
||||
readSvgDirectory,
|
||||
resetFile,
|
||||
toPascalCase,
|
||||
writeFile,
|
||||
getCurrentDirPath,
|
||||
} from '../../../scripts/helpers.mjs';
|
||||
|
||||
const currentDir = getCurrentDirPath(import.meta.url);
|
||||
const srcDirectory = path.join(currentDir, '../dist');
|
||||
|
||||
const writeDeclarationFile = (typesFile, directory, content) => {
|
||||
resetFile(typesFile, directory);
|
||||
writeFile(content, typesFile, directory);
|
||||
};
|
||||
|
||||
const ICONS_DIR = path.resolve(currentDir, '../../../icons');
|
||||
const TYPES_FILE = 'lucide-react.d.ts';
|
||||
|
||||
let declarationFileContent = `\
|
||||
/// <reference types="react" />
|
||||
import { SVGAttributes, FC, SVGProps, ReactSVG } from 'react'
|
||||
|
||||
declare module 'lucide-react'
|
||||
|
||||
// Create interface extending SVGProps
|
||||
export interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = (props: LucideProps) => JSX.Element;
|
||||
|
||||
export type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]
|
||||
|
||||
export declare const createLucideIcon: (iconName: string, iconNode: IconNode) => LucideIcon;
|
||||
|
||||
export type Icon = FC<LucideProps>;
|
||||
|
||||
// Generated icon
|
||||
`;
|
||||
|
||||
const svgFiles = readSvgDirectory(ICONS_DIR);
|
||||
|
||||
svgFiles.forEach((svgFile) => {
|
||||
const iconName = path.basename(svgFile, '.svg');
|
||||
const componentName = toPascalCase(iconName);
|
||||
|
||||
declarationFileContent += `export declare const ${componentName}: LucideIcon;\n`;
|
||||
});
|
||||
|
||||
const aliases = await getAliases(ICONS_DIR);
|
||||
|
||||
declarationFileContent += `\n
|
||||
|
||||
// Generated icon aliases
|
||||
`;
|
||||
|
||||
let aliasesCount = 0;
|
||||
|
||||
svgFiles.forEach((svgFile) => {
|
||||
const iconName = path.basename(svgFile, '.svg');
|
||||
const componentName = toPascalCase(iconName);
|
||||
const iconAliases = aliases[iconName]?.aliases;
|
||||
|
||||
declarationFileContent += `// ${componentName} aliases\n`;
|
||||
declarationFileContent += `export declare const ${componentName}Icon: LucideIcon;\n`;
|
||||
declarationFileContent += `export declare const Lucide${componentName}: LucideIcon;\n`;
|
||||
aliasesCount += 1;
|
||||
if (iconAliases != null && Array.isArray(iconAliases)) {
|
||||
iconAliases.forEach((alias) => {
|
||||
const componentNameAlias = toPascalCase(alias);
|
||||
declarationFileContent += `export declare const ${componentNameAlias}: LucideIcon;\n`;
|
||||
|
||||
aliasesCount += 1;
|
||||
});
|
||||
}
|
||||
|
||||
declarationFileContent += '\n';
|
||||
});
|
||||
|
||||
writeDeclarationFile(TYPES_FILE, srcDirectory, declarationFileContent);
|
||||
console.log(
|
||||
`Generated ${TYPES_FILE} file with`,
|
||||
svgFiles.length,
|
||||
'icons and with',
|
||||
aliasesCount,
|
||||
'aliases',
|
||||
);
|
||||
@@ -1,7 +1,33 @@
|
||||
export default ({ componentName, children }) => `
|
||||
export default ({ componentName, iconName, children, getSvg }) => {
|
||||
const svgContents = getSvg();
|
||||
|
||||
const svgBase64 = Buffer.from(
|
||||
svgContents
|
||||
.replace('\n', '')
|
||||
.replace(
|
||||
'stroke="currentColor"',
|
||||
'stroke="#000" style="background-color: #fff; border-radius: 2px"',
|
||||
),
|
||||
).toString('base64');
|
||||
|
||||
// declarationFileContent += `\
|
||||
|
||||
return `
|
||||
import createLucideIcon from '../createLucideIcon';
|
||||
|
||||
/**
|
||||
* @component @name ${componentName}
|
||||
* @description Lucide SVG icon component, renders SVG Element with children.
|
||||
*
|
||||
* @preview  - https://lucide.dev/icons/${iconName}
|
||||
* @see https://lucide.dev/guide/packages/lucide-react - Documentation
|
||||
*
|
||||
* @param {Object} props - Lucide icons props and any valid SVG attribute
|
||||
* @returns {JSX.Element} JSX Element
|
||||
*
|
||||
*/
|
||||
const ${componentName} = createLucideIcon('${componentName}', ${JSON.stringify(children)});
|
||||
|
||||
export default ${componentName};
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { forwardRef, createElement, ReactSVG, SVGProps } from 'react';
|
||||
import { forwardRef, createElement, ReactSVG, SVGProps, ForwardRefExoticComponent, RefAttributes } from 'react';
|
||||
import defaultAttributes from './defaultAttributes';
|
||||
|
||||
export type IconNode = [elementName: keyof ReactSVG, attrs: Record<string, string>][]
|
||||
@@ -9,6 +9,8 @@ export interface LucideProps extends SVGAttributes {
|
||||
size?: string | number
|
||||
absoluteStrokeWidth?: boolean
|
||||
}
|
||||
|
||||
export type LucideIcon = ForwardRefExoticComponent<LucideProps & RefAttributes<SVGSVGElement>>
|
||||
/**
|
||||
* Converts string to KebabCase
|
||||
* Copied from scripts/helper. If anyone knows how to properly import it here
|
||||
@@ -19,7 +21,7 @@ export interface LucideProps extends SVGAttributes {
|
||||
*/
|
||||
export const toKebabCase = (string: string) => string.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode) => {
|
||||
const createLucideIcon = (iconName: string, iconNode: IconNode): LucideIcon => {
|
||||
const Component = forwardRef<SVGSVGElement, LucideProps>(
|
||||
({ color = 'currentColor', size = 24, strokeWidth = 2, absoluteStrokeWidth, children, ...rest }, ref) =>
|
||||
createElement(
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
export * from './icons';
|
||||
export * as icons from './icons';
|
||||
export * from './aliases';
|
||||
export { default as createLucideIcon } from './createLucideIcon';
|
||||
export { default as dynamicIconImports } from './dynamicIconImports';
|
||||
export {
|
||||
default as createLucideIcon,
|
||||
type IconNode,
|
||||
type LucideProps,
|
||||
type LucideIcon,
|
||||
} from './createLucideIcon';
|
||||
|
||||
@@ -5,3 +5,5 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
|
||||
exports[`Using lucide icon components > should not scale the strokeWidth when absoluteStrokeWidth is set 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-grid\\" data-testid=\\"grid-icon\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render an component 1`] = `"<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\\" class=\\"lucide lucide-grid\\"><rect width=\\"18\\" height=\\"18\\" x=\\"3\\" y=\\"3\\" rx=\\"2\\" ry=\\"2\\"></rect><line x1=\\"3\\" x2=\\"21\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"3\\" x2=\\"21\\" y1=\\"15\\" y2=\\"15\\"></line><line x1=\\"9\\" x2=\\"9\\" y1=\\"3\\" y2=\\"21\\"></line><line x1=\\"15\\" x2=\\"15\\" y1=\\"3\\" y2=\\"21\\"></line></svg>"`;
|
||||
|
||||
exports[`Using lucide icon components > should render icons dynamically by using the dynamicIconImports module 1`] = `"<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"48\\" height=\\"48\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"red\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" class=\\"lucide lucide-smile\\" aria-label=\\"smile\\"><circle cx=\\"12\\" cy=\\"12\\" r=\\"10\\"></circle><path d=\\"M8 14s1.5 2 4 2 4-2 4-2\\"></path><line x1=\\"9\\" x2=\\"9.01\\" y1=\\"9\\" y2=\\"9\\"></line><line x1=\\"15\\" x2=\\"15.01\\" y1=\\"9\\" y2=\\"9\\"></line></svg>"`;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { render, cleanup } from '@testing-library/react'
|
||||
import { Pen, Edit2, Grid } from '../src/lucide-react';
|
||||
import { render, cleanup, waitFor } from '@testing-library/react'
|
||||
import { Pen, Edit2, Grid, dynamicIconImports, LucideProps } from '../src/lucide-react';
|
||||
import { Suspense, lazy } from 'react';
|
||||
|
||||
describe('Using lucide icon components', () => {
|
||||
it('should render an component', () => {
|
||||
@@ -73,4 +74,37 @@ describe('Using lucide icon components', () => {
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render icons dynamically by using the dynamicIconImports module', async () => {
|
||||
interface IconProps extends Omit<LucideProps, 'ref'> {
|
||||
name: keyof typeof dynamicIconImports;
|
||||
}
|
||||
|
||||
const Icon = ({ name, ...props }: IconProps) => {
|
||||
const LucideIcon = lazy(dynamicIconImports[name]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LucideIcon {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
const { container, getByLabelText } = render(
|
||||
<Icon
|
||||
aria-label="smile"
|
||||
name="smile"
|
||||
size={48}
|
||||
stroke="red"
|
||||
absoluteStrokeWidth
|
||||
/>,
|
||||
);
|
||||
|
||||
await waitFor(() => getByLabelText('smile'))
|
||||
|
||||
expect( container.innerHTML ).toMatchSnapshot();
|
||||
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
|
||||
9
pnpm-lock.yaml
generated
@@ -384,6 +384,9 @@ importers:
|
||||
rollup:
|
||||
specifier: ^3.5.1
|
||||
version: 3.23.0
|
||||
rollup-plugin-dts:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0(rollup@3.23.0)(typescript@4.9.5)
|
||||
typescript:
|
||||
specifier: ^4.8.4
|
||||
version: 4.9.5
|
||||
@@ -1828,10 +1831,6 @@ packages:
|
||||
resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
/@babel/helper-validator-identifier@7.19.1:
|
||||
resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
/@babel/helper-validator-identifier@7.22.5:
|
||||
resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@@ -4872,7 +4871,7 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.21.5
|
||||
'@babel/helper-validator-identifier': 7.19.1
|
||||
'@babel/helper-validator-identifier': 7.22.5
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
/@babel/types@7.22.5:
|
||||
|
||||
30
tools/build-icons/building/generateDynamicImports.mjs
Normal file
@@ -0,0 +1,30 @@
|
||||
import path from 'path';
|
||||
import { resetFile, appendFile } from '../../../scripts/helpers.mjs';
|
||||
|
||||
export default function generateDynamicImports({
|
||||
iconNodes,
|
||||
outputDirectory,
|
||||
fileExtension,
|
||||
showLog = true,
|
||||
}) {
|
||||
const fileName = path.basename(`dynamicIconImports${fileExtension}`);
|
||||
const icons = Object.keys(iconNodes);
|
||||
|
||||
// Reset file
|
||||
resetFile(fileName, outputDirectory);
|
||||
|
||||
let importString = `const dynamicIconImports = {\n`;
|
||||
|
||||
// Generate Import for Icon VNodes
|
||||
icons.forEach((iconName) => {
|
||||
importString += ` '${iconName}': () => import('./icons/${iconName}'),\n`;
|
||||
});
|
||||
|
||||
importString += '};\nexport default dynamicIconImports;\n';
|
||||
|
||||
appendFile(importString, fileName, outputDirectory);
|
||||
|
||||
if (showLog) {
|
||||
console.log(`Successfully generated ${fileName} file`);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import prettier from 'prettier';
|
||||
import { toPascalCase } from '../../../scripts/helpers.mjs';
|
||||
import { readSvg, toPascalCase } from '../../../scripts/helpers.mjs';
|
||||
|
||||
export default ({
|
||||
iconNodes,
|
||||
@@ -10,6 +10,7 @@ export default ({
|
||||
showLog = true,
|
||||
iconFileExtension = '.js',
|
||||
pretty = true,
|
||||
iconsDir,
|
||||
}) => {
|
||||
const icons = Object.keys(iconNodes);
|
||||
const iconsDistDirectory = path.join(outputDirectory, `icons`);
|
||||
@@ -25,7 +26,9 @@ export default ({
|
||||
let { children } = iconNodes[iconName];
|
||||
children = children.map(({ name, attributes }) => [name, attributes]);
|
||||
|
||||
const elementTemplate = template({ componentName, iconName, children });
|
||||
const getSvg = () => readSvg(`${iconName}.svg`, iconsDir);
|
||||
|
||||
const elementTemplate = template({ componentName, iconName, children, getSvg });
|
||||
const output = pretty
|
||||
? prettier.format(elementTemplate, {
|
||||
singleQuote: true,
|
||||
|
||||
@@ -10,6 +10,7 @@ import generateExportsFile from './building/generateExportsFile.mjs';
|
||||
import { readSvgDirectory, getCurrentDirPath } from '../../scripts/helpers.mjs';
|
||||
import generateAliasesFile from './building/generateAliasesFile.mjs';
|
||||
import getAliases from './utils/getAliases.mjs';
|
||||
import generateDynamicImports from './building/generateDynamicImports.mjs';
|
||||
|
||||
const cliArguments = getArgumentOptions(process.argv.slice(2));
|
||||
|
||||
@@ -30,6 +31,7 @@ const {
|
||||
importImportFileExtension = '',
|
||||
exportFileName = 'index.js',
|
||||
withAliases = false,
|
||||
withDynamicImports = false,
|
||||
aliasesFileExtension = '.js',
|
||||
aliasImportFileExtension = '',
|
||||
pretty = true,
|
||||
@@ -54,6 +56,7 @@ async function buildIcons() {
|
||||
showLog: !silent,
|
||||
iconFileExtension,
|
||||
pretty: JSON.parse(pretty),
|
||||
iconsDir: ICONS_DIR,
|
||||
});
|
||||
|
||||
if (withAliases) {
|
||||
@@ -69,6 +72,15 @@ async function buildIcons() {
|
||||
});
|
||||
}
|
||||
|
||||
if (withDynamicImports) {
|
||||
generateDynamicImports({
|
||||
iconNodes: icons,
|
||||
outputDirectory: OUTPUT_DIR,
|
||||
fileExtension: aliasesFileExtension,
|
||||
showLog: !silent,
|
||||
});
|
||||
}
|
||||
|
||||
// Generates entry files for the compiler filled with icons exports
|
||||
generateExportsFile(
|
||||
path.join(OUTPUT_DIR, 'icons', exportFileName),
|
||||
|
||||