2
0
mirror of https://github.com/iconify/iconify.git synced 2024-11-08 14:20:57 +00:00

React wrapper for iconify-icon, incomplete

This commit is contained in:
Vjacheslav Trushkin 2022-05-13 23:39:36 +03:00
parent 37c5f93948
commit c448199ec6
31 changed files with 20044 additions and 4 deletions

View File

@ -66,7 +66,9 @@ Directory `components` contains Iconify icon components and SVG framework.
#### Deprecation notice #### Deprecation notice
Components in directory `components` are slowly phased out in favor of `iconify-icon` web component. Functionality is identical, but web component has some advantages: Components in directory `components` are slowly phased out in favor of `iconify-icon` web component. Components are still maintained and supported, but it is better to switch to web component.
Functionality is identical, but web component has some advantages:
- No framework specific shenanigans. Events and attributes are supported for all frameworks. - No framework specific shenanigans. Events and attributes are supported for all frameworks.
- Works better with SSR (icon is rendered only in browser, but because icon is contained in shadow DOM, it does not cause hydration problems). - Works better with SSR (icon is rendered only in browser, but because icon is contained in shadow DOM, it does not cause hydration problems).
@ -75,6 +77,7 @@ Components in directory `components` are slowly phased out in favor of `iconify-
Deprecation status: Deprecation status:
- SVG Framework: can be replaced with `iconify-icon`. - SVG Framework: can be replaced with `iconify-icon`.
- React component: can be replaced with `iconify-icon` using `@iconify-icon/react` wrapper.
- Ember component: can be replaced with `iconify-icon`, does not require Ember specific wrapper. - Ember component: can be replaced with `iconify-icon`, does not require Ember specific wrapper.
To import web component, just import it once in your script, as per [`iconify-icon` README file](./iconify-icon/icon/README.md). To import web component, just import it once in your script, as per [`iconify-icon` README file](./iconify-icon/icon/README.md).
@ -99,14 +102,16 @@ Directory `components-demo` contains demo packages that show usage of icon compo
Directory `iconify-icon` contains `iconify-icon` web component and wrappers for various frameworks. Directory `iconify-icon` contains `iconify-icon` web component and wrappers for various frameworks.
| Package | Usage | | Package | Usage |
| ------------------------------------- | ---------- | | -------------------------------------- | ---------- |
| [Web component](./iconify-icon/icon/) | Everywhere | | [Web component](./iconify-icon/icon/) | Everywhere |
| [React wrapper](./iconify-icon/react/) | React |
#### Demo #### Demo
Directory `iconify-icon-demo` contains demo packages that show usage of `iconify-icon` web component. Directory `iconify-icon-demo` contains demo packages that show usage of `iconify-icon` web component.
- [Ember demo](./iconify-icon-demo/ember-icon-demo/) - demo using web component with Ember. Run `npm run build` to build demo and `npm run start` to start it. - [Ember demo](./iconify-icon-demo/ember-icon-demo/) - demo using web component with Ember. Run `npm run build` to build demo and `npm run start` to start it.
- [React demo](./iconify-icon-demo/react-demo/) - demo using web component with React. Run `npm run dev` to start demo.
## Installation ## Installation

View File

@ -0,0 +1,5 @@
node_modules
.DS_Store
dist
dist-ssr
*.local

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
{
"name": "@iconify-icon/react-demo",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@iconify-icon/react": "^0.0.1",
"@iconify-icons/mdi-light": "^1.1.1",
"@iconify-icons/uil": "^1.1.2",
"@types/react": "^17.0.33",
"@types/react-dom": "^17.0.10",
"@vitejs/plugin-react": "^1.0.7",
"typescript": "^4.6.3",
"vite": "^2.7.10"
}
}

View File

@ -0,0 +1,165 @@
.App {
font-family: Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: left;
color: #2c3e50;
font-size: 16px;
line-height: 1.5;
}
/* Sections */
section {
border-bottom: 1px dotted #ccc;
padding: 16px;
}
section:last-child {
border-bottom-width: 0;
}
section:after {
content: ' ';
display: table;
clear: both;
}
h1,
h2 {
margin: 0 0 16px;
padding: 0;
font-size: 24px;
font-weight: normal;
}
h2 {
margin: 16px 0;
font-size: 20px;
}
h1 + h2 {
margin-top: -8px;
}
p {
margin: 12px 0 4px;
padding: 0;
}
/* Tests */
.test-row {
font-size: 16px;
line-height: 1.5;
}
.test-row-icons {
padding-right: 4px;
}
.test-row-icons > iconify-icon {
color: #afafaf;
display: none;
}
.test-row-icons > .hidden {
display: none !important;
}
.test-row-icons > .visible {
display: inline-block;
}
.test-row-icons > .success {
color: #327335;
}
.test-row-icons > .failed {
color: #ba3329;
}
/* 24px icon */
.icon-24 iconify-icon {
font-size: 24px;
line-height: 1;
vertical-align: -0.25em;
}
/* Alert demo */
.alert {
position: relative;
margin: 8px;
padding: 16px;
padding-left: 48px;
background: #ba3329;
color: #fff;
border-radius: 5px;
float: left;
}
.alert + div {
clear: both;
}
.alert iconify-icon {
position: absolute;
left: 12px;
top: 50%;
font-size: 24px;
line-height: 1em;
margin: -0.5em 0 0;
}
/* Checkbox component */
.checkbox-container {
margin: 8px 0;
}
.checkbox {
cursor: pointer;
/* color: #1769aa; */
color: #626262;
text-decoration: none;
}
.checkbox:hover {
color: #ba3329;
text-decoration: underline;
}
.checkbox iconify-icon {
margin-right: 4px;
color: #afafaf;
font-size: 24px;
line-height: 1em;
vertical-align: -0.25em;
}
.checkbox--checked iconify-icon {
color: #327335;
}
.checkbox:hover iconify-icon {
color: inherit;
}
.checkbox-container small {
margin-left: 4px;
opacity: 0.7;
}
/* Inline demo */
.inline-demo iconify-icon {
color: #06a;
margin: 0 8px;
position: relative;
z-index: 2;
background: #fff;
}
.inline-demo div {
position: relative;
font-size: 16px;
line-height: 1.5;
}
.inline-demo div:before,
.inline-demo div:after {
content: '';
position: absolute;
left: 0;
right: 0;
height: 0;
border-top: 1px dashed #506874;
opacity: 0.5;
z-index: -1;
}
.inline-demo div:before {
bottom: 5px;
}
.inline-demo div:after {
bottom: 7px;
border-top-color: #ba3329;
}

View File

@ -0,0 +1,64 @@
import { addIcon, addCollection, disableCache } from '@iconify-icon/react';
import playIcon from '@iconify-icons/mdi-light/play';
import { Checkbox } from './demo-components/Checkbox';
import { InlineDemo } from './demo-components/Inline';
import { OfflineUsageDemo } from './demo-components/UsageOffline';
import { FullUsageDemo } from './demo-components/UsageAPI';
import './App.css';
// Disable cache
disableCache('all');
// Add few custom icons
addIcon('test:demo', playIcon);
addIcon('test:experiment2', {
width: 16,
height: 16,
body: '<mask id="coffee-mask" x="0" y="0" width="16" height="16"><g fill="white"><path d="M5-2c0 2-2 2-2 4s2 2 2 4-2 2-2 4 2 2 2 4M8.5-2c0 2-2 2-2 4s2 2 2 4-2 2-2 4 2 2 2 4M12-2c0 2-2 2-2 4s2 2 2 4-2 2-2 4 2 2 2 4" stroke="white" stroke-width="1" fill="none"><animateMotion path="M0 0v-8" calcMode="linear" dur="3s" repeatCount="indefinite" /></path></g><rect y="4" width="16" height="12" fill="black" /><path d="M2 5H13C14.1046 5 15 5.89543 15 7V8C15 9.10457 14.1046 10 13 10H12V14C12 15.1046 11.1046 16 10 16H4C2.89543 16 2 15.1046 2 14V5Z" fill="white" /><path d="M12 6H13C13.5523 6 14 6.44772 14 7V8C14 8.55228 13.5523 9 13 9H12V6Z" fill="black" /></mask><rect mask="url(#coffee-mask)" width="16" height="16" fill="currentColor" />',
});
// Add mdi-light icons with custom prefix
addCollection({
prefix: 'test',
icons: {
alert1: {
body: '<path d="M10.5 14c4.142 0 7.5 1.567 7.5 3.5V20H3v-2.5c0-1.933 3.358-3.5 7.5-3.5zm6.5 3.5c0-1.38-2.91-2.5-6.5-2.5S4 16.12 4 17.5V19h13v-1.5zM10.5 5a3.5 3.5 0 1 1 0 7a3.5 3.5 0 0 1 0-7zm0 1a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5zM20 16v-1h1v1h-1zm0-3V7h1v6h-1z" fill="currentColor"/>',
},
link1: {
body: '<path d="M8 13v-1h7v1H8zm7.5-6a5.5 5.5 0 1 1 0 11H13v-1h2.5a4.5 4.5 0 1 0 0-9H13V7h2.5zm-8 11a5.5 5.5 0 1 1 0-11H10v1H7.5a4.5 4.5 0 1 0 0 9H10v1H7.5z" fill="currentColor"/>',
},
},
width: 24,
height: 24,
});
function App() {
return (
<div className="App">
<OfflineUsageDemo />
<FullUsageDemo />
<section>
<h1>Checkbox</h1>
<div>
<Checkbox
checked={true}
text="Checkbox example"
hint="(click to toggle)"
/>
<Checkbox
checked={false}
text="Another checkbox example"
hint="(click to toggle)"
/>
</div>
</section>
<InlineDemo />
</div>
);
}
export default App;

View File

@ -0,0 +1,39 @@
import { useState } from 'react';
import { Icon } from '@iconify-icon/react';
import checkedIcon from '@iconify-icons/uil/check-square';
import uncheckedIcon from '@iconify-icons/uil/square';
interface CheckboxProps {
checked: boolean;
text: string;
hint: string;
}
export function Checkbox(props: CheckboxProps) {
const [checked, setChecked] = useState(props.checked);
function onClick(event: React.MouseEvent<HTMLElement>) {
event.preventDefault();
setChecked((value) => !value);
}
return (
<div className="checkbox-container">
<a
href="# "
className={
'checkbox ' +
(checked ? 'checkbox--checked' : 'checkbox--unchecked')
}
onClick={onClick}
>
<Icon
icon={checked ? checkedIcon : uncheckedIcon}
mode={checked ? 'mask' : 'svg'}
/>
{props.text}
</a>
<small>{props.hint}</small>
</div>
);
}

View File

@ -0,0 +1,27 @@
import React from 'react';
import { Icon } from '@iconify-icon/react';
export function InlineDemo() {
return (
<section className="inline-demo">
<h1>Inline demo</h1>
<div>
Block icon (behaving like image):
<Icon icon="test:experiment2" />
<Icon
icon="test:experiment2"
inline={true}
style={{ verticalAlign: '0' }}
/>
</div>
<div>
Inline icon (behaving line text / icon font):
<Icon icon="test:experiment2" inline={true} />
<Icon
icon="test:experiment2"
style={{ verticalAlign: '-0.125em' }}
/>
</div>
</section>
);
}

View File

@ -0,0 +1,18 @@
import React from 'react';
import { Icon } from '@iconify-icon/react';
export function FullUsageDemo() {
return (
<section className="icon-24">
<h1>Usage (full module)</h1>
<div>
Icons referenced by name (as SVG, as SPAN):{' '}
<Icon icon="mdi:home" /> <Icon icon="mdi:home" mode="style" />
</div>
<div className="alert">
<Icon icon="mdi-light:alert" />
Important notice with alert icon!
</div>
</section>
);
}

View File

@ -0,0 +1,30 @@
import React from 'react';
import { Icon } from '@iconify-icon/react';
import accountIcon from '@iconify-icons/mdi-light/account';
import alertIcon from '@iconify-icons/mdi-light/alert';
export function OfflineUsageDemo() {
return (
<section className="icon-24">
<h1>Usage (offline mode: using preloaded icons)</h1>
<div>
Icons referenced by name (as SVG, as SPAN):{' '}
<Icon icon="test:demo" />
<Icon icon="test:demo" mode="style" />
</div>
<div>
Icons referenced by object (as SVG, as SPAN):{' '}
<Icon icon={accountIcon} />
<Icon icon={accountIcon} mode="style" />
</div>
<div>
2 icons imported from icon set: <Icon icon="test:alert1" />
<Icon icon="test:link1" mode="style" />
</div>
<div className="alert">
<Icon icon={alertIcon} mode="mask" />
Important notice with alert icon!
</div>
</section>
);
}

View File

@ -0,0 +1,15 @@
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF"/>
<stop offset="1" stop-color="#BD34FE"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83"/>
<stop offset="0.0833333" stop-color="#FFDD35"/>
<stop offset="1" stop-color="#FFA800"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,11 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)

View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["./src"]
}

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()]
})

View File

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}

4
iconify-icon/react/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.DS_Store
node_modules
dist
lib

View File

@ -0,0 +1,11 @@
.DS_Store
.babelrc
api-extractor.*.json
rollup.config.js
tsconfig.json
build.js
cleanup.js
node_modules
src
lib
tests

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Vjacheslav Trushkin / Iconify OÜ
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

16623
iconify-icon/react/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,55 @@
{
"name": "@iconify-icon/react",
"description": "React wrapper for Iconify Icon web component",
"author": "Vjacheslav Trushkin",
"version": "0.0.1",
"license": "MIT",
"bugs": "https://github.com/iconify/iconify/issues",
"homepage": "https://iconify.design/",
"funding": "http://github.com/sponsors/cyberalien",
"repository": {
"type": "git",
"url": "https://github.com/iconify/iconify.git",
"directory": "iconify-icon/react"
},
"scripts": {
"clean": "rimraf lib dist tsconfig.tsbuildinfo",
"prebuild": "npm run clean",
"build": "tsup",
"test": "jest --runInBand"
},
"main": "dist/iconify.js",
"module": "dist/iconify.mjs",
"types": "dist/iconify.d.ts",
"exports": {
"./*": "./*",
".": {
"import": "./dist/iconify.mjs",
"types": "./dist/iconify.d.ts",
"default": "./dist/iconify.js"
},
"./lib/iconify": {
"require": "./dist/iconify.js",
"import": "./dist/iconify.mjs",
"types": "./dist/iconify.d.ts"
}
},
"dependencies": {
"iconify-icon": "^0.0.4"
},
"devDependencies": {
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@types/react": "^17.0.41",
"babel-jest": "^27.4.6",
"jest": "^28.0.0-alpha.7",
"react": "^17.0.2",
"react-test-renderer": "^17.0.2",
"rimraf": "^3.0.2",
"tsup": "^5.12.7",
"typescript": "^4.6.2"
},
"peerDependencies": {
"react": "*"
}
}

View File

@ -0,0 +1,377 @@
# Iconify for React
Iconify for React is not yet another icon component! There are many of them already.
What you get with other components:
- Limited set of icons.
- Large bundle size because all icons are bundled.
Iconify icon component is nothing like that. Component does not include any icon data, it is not tied to any specific icon set. Instead, all data is retrieved from public API on demand.
That means:
- One syntax for over 100,000 icons from 100+ icon sets.
- Renders SVG. Many components simply render icon fonts, which look ugly. Iconify renders pixel perfect SVG.
- Loads icons on demand. No need to bundle icons, component will automatically load icon data for icons that you use from Iconify API.
For more information about Iconify project visit [https://iconify.design/](https://iconify.design/).
For extended documentation visit [Iconify for React documentation](https://docs.iconify.design/icon-components/react/).
## Installation
If you are using NPM:
```bash
npm install --save-dev @iconify/react
```
If you are using Yarn:
```bash
yarn add --dev @iconify/react
```
## Usage with API
Install `@iconify/react` and import `Icon` from it:
```typescript
import { Icon } from '@iconify/react';
```
Then use `Icon` component with icon name or data as "icon" parameter:
```jsx
<Icon icon="mdi-light:home" />
```
Component will automatically retrieve data for "mdi-light:home" from Iconify API and render it. There are over 100,000 icons available on Iconify API from various free and open source icon sets, including all the most popular icon sets.
## Offline Usage
Retrieving icon data from Iconify API requires visitor to be online. What if you want to use component offline or on local network?
If you want to use icon component without relying on public Iconify API, there are several options:
1. You can import icon data from Iconify Icons packages.
2. You can create custom icon bundles (more efficient, but requires more coding).
3. You can host your own Iconify API instead of relying on third party service.
See [Iconify for React offline use documentation](https://docs.iconify.design/icon-components/react/offline.html) or [Iconify API documentation](https://docs.iconify.design/sources/api/).
## Icon Names
Icon name is a string. Few examples:
- `@api-provider:icon-set-prefix:icon-name`
- `mdi-light:home` (in this example API provider is empty, so it is skipped)
It has 3 parts, separated by ":":
- provider points to API source. Starts with "@", can be empty (empty value is used for public Iconify API).
- prefix is name of icon set.
- name is name of icon.
See [Iconify for React icon names documentation](https://docs.iconify.design/icon-components/react/icon-name.html) for more detailed explanation.
## Using icon data
Instead of icon name, you can pass icon data to component:
```jsx
import { Icon } from '@iconify/react';
import home from '@iconify-icons/mdi-light/home';
function renderHomeIcon() {
return <Icon icon={home} />;
}
```
See [icon packages documentation](https://docs.iconify.design/sources/npm/) for more details.
### Next.js notice
Example above will currently fail with Next.js. This is because Next.js uses outdated packaging software that does not support ES modules. But do not worry, there is a simple solution: switch to CommonJS icon packages.
To switch to CommonJS package, replace this line in example above:
```js
import home from '@iconify-icons/mdi-light/home';
```
with
```js
import home from '@iconify/icons-mdi-light/home';
```
All icons are available as ES modules for modern bundler and as CommonJS modules for outdated bundlers. ES modules use format `@iconify-icons/{prefix}`, CommonJS modules use `@iconify/icons-{prefix}`.
For more details, see [icon packages documentation](https://docs.iconify.design/sources/npm/).
## Inline icon
Icons have 2 modes: inline and block. Difference between modes is `vertical-align` that is added to inline icons.
Inline icons are aligned slightly below baseline, so they look centred compared to text, like glyph fonts.
Block icons do not have alignment, like images, which aligns them to baseline by default.
Alignment option was added to make icons look like continuation of text, behaving like glyph fonts. This should make migration from glyph fonts easier.
```jsx
import React from 'react';
import { Icon, InlineIcon } from '@iconify/react';
export function inlineDemo() {
return (
<div>
<p>
Block:
<Icon icon="line-md:image-twotone" />
<Icon icon="mdi:account-box-outline" />
</p>
<p>
Inline:
<InlineIcon icon="line-md:image-twotone" />
<InlineIcon icon="mdi:account-box-outline" />
</p>
</div>
);
}
```
To toggle between block and inline modes, you can either use `InlineIcon` or use boolean `inline` property:
```jsx
import React from 'react';
import { Icon } from '@iconify/react';
export function inlineDemo() {
return (
<div>
<p>
Block:
<Icon icon="line-md:image-twotone" />
<Icon icon="mdi:account-box-outline" />
</p>
<p>
Inline:
<Icon icon="line-md:image-twotone" inline={true} />
<Icon icon="mdi:account-box-outline" inline={true} />
</p>
</div>
);
}
```
Visual example to show the difference between inline and block modes:
![Inline icon](https://iconify.design/assets/images/inline.png)
## Icon component properties
`icon` property is mandatory. It tells component what icon to render. The value can be a string containing the icon name or an object containing the icon data.
The icon component has the following optional properties:
- `inline`. Changes icon behaviour to match icon fonts. See "Inline icon" section above.
- `width` and `height`. Icon dimensions. The default values are "1em" for both. See "Dimensions" section below.
- `color`. Icon colour. This is the same as setting colour in style. See "Icon colour" section below.
- `flip`, `hFlip`, `vFlip`. Flip icon horizontally and/or vertically. See "Transformations" section below.
- `rotate`. Rotate icon by 90, 180 or 270 degrees. See "Transformations" section below.
- `align`, `vAlign`, `hAlign`, `slice`. Icon alignment. See "Alignment" section below.
- `onLoad`. Callback function that is called when icon data has been loaded. See "onLoad" section below.
### Other properties and events
In addition to the properties mentioned above, the icon component accepts any other properties and events. All other properties and events will be passed to generated `SVG` element, so you can do stuff like assigning `onClick` event, setting the inline style, add title and so on.
### Dimensions
By default, icon height is "1em". With is dynamic, calculated using the icon's width to height ratio. This makes it easy to change icon size by changing `font-size` in the stylesheet, just like icon fonts.
There are several ways to change icon dimensions:
- Setting `font-size` in style (or `fontSize` if you are using inline style).
- Setting `width` and/or `height` property.
Values for `width` and `height` can be numbers or strings.
If you set only one dimension, another dimension will be calculated using the icon's width to height ratio. For example, if the icon size is 16 x 24, you set the height to 48, the width will be set to 32. Calculations work not only with numbers, but also with string values.
#### Dimensions as numbers
You can use numbers for `width` and `height`.
```jsx
<Icon icon={homeIcon} height={24} />
```
```jsx
<Icon icon="mdi-light:home" width={16} height={16} />
```
Number values are treated as pixels. That means in examples above, values are identical to "24px" and "16px".
#### Dimensions as strings without units
If you use strings without units, they are treated the same as numbers in an example above.
```jsx
<Icon icon={homeIcon} height="24" />
```
```jsx
<Icon icon="mdi-light:home" width="16" height={'16'} />
```
#### Dimensions as strings with units
You can use units in width and height values:
```jsx
<Icon icon="mdi-light:home" height="2em" />
```
Be careful when using `calc`, view port based units or percentages. In SVG element they might not behave the way you expect them to behave and when using such units, you should consider settings both width and height.
#### Dimensions as 'auto'
Keyword "auto" sets dimensions to the icon's `viewBox` dimensions. For example, for 24 x 24 icon using `height="auto"` sets height to 24 pixels.
```jsx
<Icon icon="mdi-light:home" height="auto" />
```
### Icon colour
There are two types of icons: icons that do not have a palette and icons that do have a palette.
Icons that do have a palette, such as emojis, cannot be customised. Setting colour to such icons will not change anything.
Icons that do not have a palette can be customised. By default, colour is set to "currentColor", which means the icon's colour matches text colour. To change the colour you can:
- Set `color` style or use stylesheet to target icon. If you are using the stylesheet, target `svg` element.
- Add `color` property.
Examples:
Using `color` property:
```jsx
<Icon icon="eva:alert-triangle-fill" color="red" />
<Icon icon="eva:alert-triangle-fill" color="#f00" />
```
Using inline style:
```jsx
<Icon icon="eva:alert-triangle-fill" style={{color: 'red'}} />
<Icon icon="eva:alert-triangle-fill" style={{color: '#f00'}} />
```
Using stylesheet:
```jsx
<Icon icon="eva:alert-triangle-fill" className="red-icon" />
```
```css
.red-icon {
color: red;
}
```
### Transformations
You can rotate and flip the icon.
This might seem redundant because icon can also be rotated and flipped using CSS transformations. So why do transformation properties exist? Because it is a different type of transformation.
- CSS transformations transform the entire icon.
- Icon transformations transform the contents of the icon.
If you have a square icon, this makes no difference. However, if you have an icon that has different width and height values, it makes a huge difference.
Rotating 16x24 icon by 90 degrees results in:
- CSS transformation keeps 16x24 bounding box, which might cause the icon to overlap text around it.
- Icon transformation changes bounding box to 24x16, rotating content inside an icon.
See [icon transformations documentation](https://docs.iconify.design/icon-components/react/transform.html) for more details.
#### Flipping an icon
There are several properties available to flip an icon:
- `hFlip`: boolean property, flips icon horizontally.
- `vFlip`: boolean property, flips icon vertically.
- `flip`: shorthand string property, can flip icon horizontally and/or vertically.
Examples:
Flip an icon horizontally:
```jsx
<Icon icon="eva:alert-triangle-fill" hFlip={true} />
<Icon icon="eva:alert-triangle-fill" flip="horizontal" />
```
Flip an icon vertically:
```jsx
<Icon icon="eva:alert-triangle-fill" vFlip={true} />
<Icon icon="eva:alert-triangle-fill" flip="vertical" />
```
Flip an icon horizontally and vertically (the same as 180 degrees rotation):
```jsx
<Icon icon="eva:alert-triangle-fill" hFlip={true} vFlip={true} />
<Icon icon="eva:alert-triangle-fill" flip="horizontal,vertical" />
```
#### Rotating an icon
An icon can be rotated by 90, 180 and 270 degrees. Only contents of the icon are rotated.
To rotate an icon, use `rotate` property. Value can be a string (degrees or percentages) or a number.
Number values are 1 for 90 degrees, 2 for 180 degrees, 3 for 270 degrees.
Examples of 90 degrees rotation:
```jsx
<Icon icon="eva:alert-triangle-fill" rotate={1} />
<Icon icon="eva:alert-triangle-fill" rotate="90deg" />
<Icon icon="eva:alert-triangle-fill" rotate="25%" />
```
### onLoad
`onLoad` property is an optional callback function. It is called when icon data has been loaded.
It is not an event, such as `onClick` event for links, it is a simple callback function.
When `onLoad` is called:
- If value of icon property is an object, `onLoad` is not called.
- If value of icon property is a string and icon data is available, `onLoad` is called on first render.
- If value of icon property is a string and icon data is not available, `onLoad` is called on first re-render after icon data is retrieved from API.
What is the purpose of `onLoad`? To let you know when Icon component renders an icon and when it does not render anything. This allows you to do things like adding class name for parent element, such as "container--with-icon" that modify layout if icon is being displayed.
## Full documentation
For extended documentation visit [Iconify for React documentation](https://docs.iconify.design/icon-components/react/).
## License
React component is released with MIT license.
© 2019 - 2022 Vjacheslav Trushkin / Iconify OÜ
See [Iconify icon sets page](https://icon-sets.iconify.design/) for list of collections and their licenses.

View File

@ -0,0 +1,94 @@
import React from 'react';
import type { IconifyIcon, IconifyIconAttributes } from 'iconify-icon';
/**
* Export types
*/
export type {
IconifyStorageFunctions,
IconifyBuilderFunctions,
IconifyBrowserCacheFunctions,
IconifyAPIFunctions,
IconifyAPIInternalFunctions,
} from 'iconify-icon';
// JSON stuff
export type { IconifyIcon, IconifyJSON, IconifyIconName } from 'iconify-icon';
// Customisations
export type { IconifyIconCustomisations, IconifyIconSize } from 'iconify-icon';
// API
export type {
IconifyAPIConfig,
IconifyIconLoaderCallback,
IconifyIconLoaderAbort,
IconifyAPIModule,
GetAPIConfig,
IconifyAPIPrepareIconsQuery,
IconifyAPISendQuery,
PartialIconifyAPIConfig,
IconifyAPIQueryParams,
IconifyAPICustomQueryParams,
} from 'iconify-icon';
// Builder functions
export type { IconifyIconBuildResult } from 'iconify-icon';
// Browser cache
export type { IconifyBrowserCacheType } from 'iconify-icon';
// Component types
export type { IconifyIconAttributes, IconifyRenderMode } from 'iconify-icon';
/**
* Export functions
*/
export {
enableCache,
disableCache,
iconExists,
getIcon,
listIcons,
shareStorage,
addIcon,
addCollection,
calculateSize,
replaceIDs,
buildIcon,
loadIcons,
loadIcon,
addAPIProvider,
_api,
} from 'iconify-icon';
/**
* Properties for React component
*/
export interface IconifyIconProps
extends React.HTMLProps<HTMLElement>,
IconifyIconAttributes {
icon: string | IconifyIcon;
inline?: boolean;
}
/**
* React component
*/
export function Icon(props: IconifyIconProps) {
const newProps = {
...props,
};
// Stringify icon
if (typeof props.icon === 'object') {
newProps.icon = JSON.stringify(props.icon);
}
// Boolean
if (!props.inline) {
delete newProps.inline;
}
return React.createElement('iconify-icon', newProps);
}

View File

@ -0,0 +1,8 @@
{
"extends": "../tsconfig.common.json",
"compilerOptions": {
"types": ["node", "jest"],
"rootDir": ".",
"outDir": "../tests-compiled"
}
}

View File

@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"strict": true,
"skipLibCheck": true,
"moduleResolution": "node",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"importsNotUsedAsValues": "error",
"resolveJsonModule": true
}
}

View File

@ -0,0 +1,10 @@
{
"extends": "./tsconfig.common.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"module": "CommonJS",
"lib": ["ESNext", "DOM"]
},
"include": ["src/*.ts"]
}

View File

@ -0,0 +1,11 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/iconify.ts'],
format: ['cjs', 'esm'],
splitting: false,
sourcemap: false,
clean: true,
dts: true,
target: 'esnext',
});

View File

@ -10,6 +10,7 @@
"iconify-icon/*", "iconify-icon/*",
"components/*", "components/*",
"components-demo/*", "components-demo/*",
"iconify-icon-demo/*",
"debug/*" "debug/*"
] ]
} }