├── .prettierignore ├── .gitignore ├── .tool-versions ├── examples ├── sveltekit-app │ ├── .npmrc │ ├── src │ │ ├── lib │ │ │ └── index.ts │ │ ├── app.d.ts │ │ ├── app.html │ │ └── routes │ │ │ └── +page.svelte │ ├── static │ │ └── favicon.png │ ├── vite.config.ts │ ├── .gitignore │ ├── .eslintignore │ ├── tsconfig.json │ ├── .eslintrc.cjs │ ├── svelte.config.js │ ├── README.md │ └── package.json ├── svelte-app │ ├── .vscode │ │ └── extensions.json │ ├── src │ │ ├── app.css │ │ ├── vite-env.d.ts │ │ ├── main.js │ │ └── App.svelte │ ├── vite.config.js │ ├── .gitignore │ ├── index.html │ ├── package.json │ ├── jsconfig.json │ ├── public │ │ └── vite.svg │ ├── README.md │ └── package-lock.json └── svelte-app-typescript │ ├── .vscode │ └── extensions.json │ ├── src │ ├── vite-env.d.ts │ ├── app.css │ ├── main.ts │ └── App.svelte │ ├── tsconfig.node.json │ ├── vite.config.ts │ ├── svelte.config.js │ ├── .gitignore │ ├── index.html │ ├── tsconfig.json │ ├── package.json │ ├── public │ └── vite.svg │ └── README.md ├── babel.config.cjs ├── .prettierrc.js ├── src ├── __mocks__ │ └── logger.js ├── index.js ├── test-setup.js ├── logger.js ├── utils │ ├── object-with-key.js │ ├── __tests__ │ │ ├── camelize.test.js │ │ ├── object-with-key.test.js │ │ ├── normalize-icon-args.test.js │ │ └── get-class-list-from-props.test.js │ ├── camelize.js │ ├── normalize-icon-args.js │ └── get-class-list-from-props.js ├── components │ ├── SvgElement.svelte │ ├── __fixtures__ │ │ ├── icons.js │ │ └── helpers.js │ ├── FontAwesomeIcon.svelte │ └── __tests__ │ │ └── FontAwesomeIcon.test.js └── converter.js ├── .claude └── settings.local.json ├── vitest.config.js ├── UPGRADING.md ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── ci.yml ├── rollup.config.js ├── LICENSE.txt ├── .eslintrc.json ├── CHANGELOG.md ├── index.d.ts ├── DEVELOPMENT.md ├── CONTRIBUTING.md ├── README.md ├── CODE_OF_CONDUCT.md ├── package.json ├── index.es.js └── index.js /.prettierignore: -------------------------------------------------------------------------------- 1 | /index.* 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 22.14.0 2 | python 3.10.1 3 | -------------------------------------------------------------------------------- /examples/sveltekit-app/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /babel.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-env'] 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | singleQuote: true 4 | } 5 | -------------------------------------------------------------------------------- /src/__mocks__/logger.js: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest' 2 | 3 | export default vi.fn() 4 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export { default as FontAwesomeIcon } from './components/FontAwesomeIcon.svelte' 2 | -------------------------------------------------------------------------------- /src/test-setup.js: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom' 2 | 3 | // Global test setup for vitest 4 | -------------------------------------------------------------------------------- /examples/svelte-app/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /examples/svelte-app/src/app.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /examples/svelte-app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /examples/sveltekit-app/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /examples/sveltekit-app/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FortAwesome/svelte-fontawesome/HEAD/examples/sveltekit-app/static/favicon.png -------------------------------------------------------------------------------- /examples/sveltekit-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | -------------------------------------------------------------------------------- /examples/sveltekit-app/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /examples/svelte-app/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { svelte } from '@sveltejs/vite-plugin-svelte' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [svelte()] 7 | }) 8 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { svelte } from '@sveltejs/vite-plugin-svelte' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [svelte()] 7 | }) 8 | -------------------------------------------------------------------------------- /examples/sveltekit-app/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/svelte.config.js: -------------------------------------------------------------------------------- 1 | import sveltePreprocess from 'svelte-preprocess' 2 | 3 | export default { 4 | // Consult https://github.com/sveltejs/svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: sveltePreprocess() 7 | } 8 | -------------------------------------------------------------------------------- /src/logger.js: -------------------------------------------------------------------------------- 1 | let PRODUCTION = false 2 | 3 | try { 4 | PRODUCTION = process.env.NODE_ENV === 'production' 5 | } catch (e) {} 6 | 7 | export default function(...args) { 8 | if (!PRODUCTION && console && typeof console.error === 'function') { 9 | console.error(...args) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.claude/settings.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "permissions": { 3 | "allow": [ 4 | "Bash(npm uninstall:*)", 5 | "Bash(npm test)", 6 | "Bash(npm install:*)", 7 | "Bash(node:*)", 8 | "Bash(npm info:*)", 9 | "Bash(npm run lint)", 10 | "Bash(npm run lint:*)" 11 | ], 12 | "deny": [], 13 | "ask": [] 14 | } 15 | } -------------------------------------------------------------------------------- /examples/sveltekit-app/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /vitest.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config' 2 | import { svelte } from '@sveltejs/vite-plugin-svelte' 3 | 4 | export default defineConfig({ 5 | plugins: [svelte({ hot: false })], 6 | test: { 7 | environment: 'jsdom', 8 | setupFiles: ['./src/test-setup.js'], 9 | include: ['src/**/*.test.js'], 10 | globals: true 11 | } 12 | }) -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | # Upgrading Guide 2 | 3 | See the [CHANGELOG.md](./CHANGELOG.md) for detailed information about what has changed between versions. 4 | 5 | This guide is useful to figure out what you need to do between breaking changes. 6 | 7 | As always, [submit issues](https://github.com/FortAwesome/svelte-fontawesome/issues/new) that you run into with this guide or with these upgrades to us. 8 | 9 | -------------------------------------------------------------------------------- /examples/svelte-app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/sveltekit-app/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/utils/object-with-key.js: -------------------------------------------------------------------------------- 1 | // creates an object with a key of key 2 | // and a value of value 3 | // if certain conditions are met 4 | export default function objectWithKey(key, value) { 5 | // if the value is a non-empty array 6 | // or it's not an array but it is truthy 7 | // then create the object with the key and the value 8 | // if not, return an empty array 9 | return (Array.isArray(value) && value.length > 0) || 10 | (!Array.isArray(value) && value) 11 | ? { [key]: value } 12 | : {} 13 | } 14 | -------------------------------------------------------------------------------- /examples/svelte-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | svelte-app example 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | svelte-app-typescript example 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/sveltekit-app/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 |

12 | Hello SvelteKit 13 |

14 |
15 | -------------------------------------------------------------------------------- /examples/svelte-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "@fortawesome/fontawesome-svg-core": "^7.0.0", 13 | "@fortawesome/free-brands-svg-icons": "^7.0.0", 14 | "@fortawesome/free-solid-svg-icons": "^7.0.0", 15 | "@fortawesome/svelte-fontawesome": "^0.2.0", 16 | "@sveltejs/vite-plugin-svelte": "^1.0.1", 17 | "svelte": "^3.49.0", 18 | "vite": "^3.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/svelte-app/src/main.js: -------------------------------------------------------------------------------- 1 | import './app.css' 2 | import App from './App.svelte' 3 | 4 | import { library } from '@fortawesome/fontawesome-svg-core' 5 | import { fab } from '@fortawesome/free-brands-svg-icons' 6 | import { 7 | faCoffee, 8 | faCog, 9 | faSpinner, 10 | faQuoteLeft, 11 | faSquare, 12 | faCheckSquare 13 | } from '@fortawesome/free-solid-svg-icons' 14 | 15 | library.add( 16 | fab, 17 | faCoffee, 18 | faCog, 19 | faSpinner, 20 | faQuoteLeft, 21 | faSquare, 22 | faCheckSquare 23 | ) 24 | 25 | const app = new App({ 26 | target: document.getElementById('app') 27 | }) 28 | 29 | export default app 30 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/src/app.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/utils/__tests__/camelize.test.js: -------------------------------------------------------------------------------- 1 | import camelize from '../camelize' 2 | 3 | describe('camelize', () => { 4 | test('numerical values return same value', () => { 5 | const numerical = 999 6 | expect(camelize(numerical)).toBe(numerical) 7 | }) 8 | 9 | test('first char is always lowercase', () => { 10 | expect(camelize('f-a')).toBe('fA') 11 | expect(camelize('F-a')).toBe('fA') 12 | }) 13 | 14 | test('multiple humps', () => { 15 | expect(camelize('fa-coffee')).toBe('faCoffee') 16 | expect(camelize('fa-fake-icon')).toBe('faFakeIcon') 17 | expect(camelize('fa-fake-icon-longer')).toBe('faFakeIconLonger') 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /examples/sveltekit-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "moduleResolution": "bundler" 13 | } 14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 15 | // 16 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 17 | // from the referenced tsconfig.json - TypeScript does not merge them in 18 | } 19 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/src/main.ts: -------------------------------------------------------------------------------- 1 | import './app.css' 2 | import App from './App.svelte' 3 | 4 | // Importing types from the API library along with other exports 5 | import { 6 | library 7 | } from '@fortawesome/fontawesome-svg-core' 8 | import { fab } from '@fortawesome/free-brands-svg-icons' 9 | import { 10 | faCog, 11 | faSpinner, 12 | faQuoteLeft, 13 | faSquare, 14 | faCheckSquare 15 | } from '@fortawesome/free-solid-svg-icons' 16 | 17 | library.add( 18 | fab, 19 | faCog, 20 | faSpinner, 21 | faQuoteLeft, 22 | faSquare, 23 | faCheckSquare 24 | ) 25 | 26 | const app = new App({ 27 | target: document.getElementById('app') 28 | }) 29 | 30 | export default app 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **Reproducible test case** 13 | Include a URL (codepen.io, jsfiddle.net, Git repository, codesandbox.io, stackblitz.com, etc.) that demonstrates the problem. 14 | 15 | **Expected behavior** 16 | A clear and concise description of what you expected to happen. 17 | 18 | **Desktop (please complete the following information):** 19 | 20 | - Browser [e.g. chrome, safari] 21 | - Version 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /examples/sveltekit-app/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type { import("eslint").Linter.Config } */ 2 | module.exports = { 3 | root: true, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:svelte/recommended' 8 | ], 9 | parser: '@typescript-eslint/parser', 10 | plugins: ['@typescript-eslint'], 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020, 14 | extraFileExtensions: ['.svelte'] 15 | }, 16 | env: { 17 | browser: true, 18 | es2017: true, 19 | node: true 20 | }, 21 | overrides: [ 22 | { 23 | files: ['*.svelte'], 24 | parser: 'svelte-eslint-parser', 25 | parserOptions: { 26 | parser: '@typescript-eslint/parser' 27 | } 28 | } 29 | ] 30 | }; 31 | -------------------------------------------------------------------------------- /src/utils/camelize.js: -------------------------------------------------------------------------------- 1 | // Camelize taken from humps 2 | // humps is copyright © 2012+ Dom Christie 3 | // Released under the MIT license. 4 | 5 | // Performant way to determine if object coerces to a number 6 | function _isNumerical(obj) { 7 | obj = obj - 0 8 | 9 | // eslint-disable-next-line no-self-compare 10 | return obj === obj 11 | } 12 | 13 | export default function camelize(string) { 14 | if (_isNumerical(string)) { 15 | return string 16 | } 17 | 18 | // eslint-disable-next-line no-useless-escape 19 | string = string.replace(/[\-_\s]+(.)?/g, function(match, chr) { 20 | return chr ? chr.toUpperCase() : '' 21 | }) 22 | 23 | // Ensure 1st char is always lowercase 24 | return string.substr(0, 1).toLowerCase() + string.substr(1) 25 | } 26 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "resolveJsonModule": true, 8 | "baseUrl": ".", 9 | /** 10 | * Typecheck JS in `.svelte` and `.js` files by default. 11 | * Disable checkJs if you'd like to use dynamic types in JS. 12 | * Note that setting allowJs false does not prevent the use 13 | * of JS in `.svelte` files. 14 | */ 15 | "allowJs": true, 16 | "checkJs": true, 17 | "isolatedModules": true 18 | }, 19 | "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /examples/sveltekit-app/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /src/utils/__tests__/object-with-key.test.js: -------------------------------------------------------------------------------- 1 | import objectWithKey from '../object-with-key' 2 | 3 | describe('object with key', () => { 4 | const KEY = 'my-key' 5 | 6 | test('value is array length greater than 1', () => { 7 | const VALUE = [1] 8 | expect(objectWithKey(KEY, [1])).toStrictEqual({ 9 | [KEY]: VALUE 10 | }) 11 | }) 12 | 13 | test('value array empty', () => { 14 | expect(objectWithKey(KEY, [])).toStrictEqual({}) 15 | }) 16 | 17 | test('value is not array', () => { 18 | const VALUE = 'value' 19 | expect(objectWithKey(KEY, VALUE)).toStrictEqual({ 20 | [KEY]: VALUE 21 | }) 22 | }) 23 | 24 | test('value not truthy', () => { 25 | expect(objectWithKey(KEY)).toStrictEqual({}) 26 | expect(objectWithKey(KEY, null)).toStrictEqual({}) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app-typescript", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "check": "svelte-check --tsconfig ./tsconfig.json" 11 | }, 12 | "devDependencies": { 13 | "@fortawesome/fontawesome-svg-core": "^7.0.0", 14 | "@fortawesome/free-brands-svg-icons": "^7.0.0", 15 | "@fortawesome/free-solid-svg-icons": "^7.0.0", 16 | "@fortawesome/svelte-fontawesome": "^0.2.0", 17 | "@sveltejs/vite-plugin-svelte": "^1.0.1", 18 | "@tsconfig/svelte": "^3.0.0", 19 | "svelte": "^3.49.0", 20 | "svelte-check": "^2.8.0", 21 | "svelte-preprocess": "^4.10.7", 22 | "tslib": "^2.4.0", 23 | "typescript": "^4.6.4", 24 | "vite": "^3.0.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/__tests__/normalize-icon-args.test.js: -------------------------------------------------------------------------------- 1 | import normalizeIconArgs from '../normalize-icon-args' 2 | 3 | describe('normalize icon args', () => { 4 | const PREFIX = 'far' 5 | const NAME = 'circle' 6 | 7 | test('handle null', () => { 8 | expect(normalizeIconArgs(null)).toBeNull() 9 | }) 10 | 11 | test('handle object', () => { 12 | const icon = { 13 | prefix: 'far', 14 | iconName: 'circle' 15 | } 16 | expect(normalizeIconArgs(icon)).toStrictEqual(icon) 17 | }) 18 | 19 | test('handle array', () => { 20 | const icon = [PREFIX, NAME] 21 | expect(normalizeIconArgs(icon)).toStrictEqual({ 22 | prefix: PREFIX, 23 | iconName: NAME 24 | }) 25 | }) 26 | 27 | test('handle string', () => { 28 | const DEFAULT_PREFIX = 'fas' 29 | expect(normalizeIconArgs(NAME)).toStrictEqual({ 30 | prefix: DEFAULT_PREFIX, 31 | iconName: NAME 32 | }) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve' 2 | import commonJs from '@rollup/plugin-commonjs' 3 | import svelte from 'rollup-plugin-svelte' 4 | 5 | const name = 'svelte-fontawesome' 6 | const globals = { 7 | '@fortawesome/fontawesome-svg-core': 'FontAwesome' 8 | } 9 | 10 | export default { 11 | external: ['@fortawesome/fontawesome-svg-core'], 12 | input: 'src/index.js', 13 | output: [ 14 | { 15 | name, 16 | globals, 17 | format: 'umd', 18 | file: 'index.js', 19 | }, 20 | { 21 | name, 22 | globals, 23 | format: 'es', 24 | file: 'index.es.js', 25 | }, 26 | ], 27 | plugins: [ 28 | resolve({ 29 | jsnext: true, 30 | main: true, 31 | }), 32 | commonJs(), 33 | svelte({ 34 | exclude: 'node_modules/**', 35 | compilerOptions: { 36 | generate: 'ssr', 37 | hydratable: true 38 | } 39 | }), 40 | ], 41 | } 42 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node: [22] 12 | svelte: [3.x, 4.x, 5.x] 13 | fontawesome: 14 | - { core: 7.x, icons: 5.x } 15 | - { core: 6.x, icons: 6.x } 16 | - { core: 7.x, icons: 7.x } 17 | 18 | steps: 19 | - uses: actions/checkout@v1 20 | - uses: actions/setup-node@v1 21 | with: 22 | node-version: ${{ matrix.node }} 23 | - name: npm install, build, and test 24 | run: | 25 | npm install 26 | npm run build 27 | npm install --no-save svelte@${{ matrix.svelte }} 28 | npm install --force --no-save @fortawesome/fontawesome-svg-core@${{ matrix.fontawesome.core }} @fortawesome/free-solid-svg-icons@${{ matrix.fontawesome.icons }} 29 | npm run lint 30 | npm run test 31 | - name: dist 32 | run: | 33 | npm run dist 34 | -------------------------------------------------------------------------------- /src/components/SvgElement.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | 34 | {@html markup} 35 | 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018 Fonticons, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /examples/sveltekit-app/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /examples/sveltekit-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sveltekit-app", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 11 | "lint": "eslint ." 12 | }, 13 | "devDependencies": { 14 | "@fortawesome/fontawesome-svg-core": "^7.0.0", 15 | "@fortawesome/free-solid-svg-icons": "^7.0.0", 16 | "@fortawesome/svelte-fontawesome": "^0.2.0", 17 | "@sveltejs/adapter-auto": "^3.0.0", 18 | "@sveltejs/kit": "^2.0.0", 19 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 20 | "@types/eslint": "8.56.0", 21 | "@typescript-eslint/eslint-plugin": "^6.0.0", 22 | "@typescript-eslint/parser": "^6.0.0", 23 | "eslint": "^8.56.0", 24 | "eslint-plugin-svelte": "^2.35.1", 25 | "svelte": "^4.2.7", 26 | "svelte-check": "^3.6.0", 27 | "tslib": "^2.4.1", 28 | "typescript": "^5.0.0", 29 | "vite": "^5.0.3" 30 | }, 31 | "type": "module" 32 | } 33 | -------------------------------------------------------------------------------- /examples/svelte-app/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "Node", 4 | "target": "ESNext", 5 | "module": "ESNext", 6 | /** 7 | * svelte-preprocess cannot figure out whether you have 8 | * a value or a type, so tell TypeScript to enforce using 9 | * `import type` instead of `import` for Types. 10 | */ 11 | "importsNotUsedAsValues": "error", 12 | "isolatedModules": true, 13 | "resolveJsonModule": true, 14 | /** 15 | * To have warnings / errors of the Svelte compiler at the 16 | * correct position, enable source maps by default. 17 | */ 18 | "sourceMap": true, 19 | "esModuleInterop": true, 20 | "skipLibCheck": true, 21 | "forceConsistentCasingInFileNames": true, 22 | "baseUrl": ".", 23 | /** 24 | * Typecheck JS in `.svelte` and `.js` files by default. 25 | * Disable this if you'd like to use dynamic types. 26 | */ 27 | "checkJs": true 28 | }, 29 | /** 30 | * Use global.d.ts instead of compilerOptions.types 31 | * to avoid limiting type declarations. 32 | */ 33 | "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/normalize-icon-args.js: -------------------------------------------------------------------------------- 1 | import { parse as faParse } from '@fortawesome/fontawesome-svg-core' 2 | 3 | // Normalize icon arguments 4 | export default function normalizeIconArgs(icon) { 5 | // this has everything that it needs to be rendered which means it was probably imported 6 | // directly from an icon svg package 7 | if (icon && typeof icon === 'object' && icon.prefix && icon.iconName && icon.icon) { 8 | return icon 9 | } 10 | 11 | if (faParse.icon) { 12 | return faParse.icon(icon) 13 | } 14 | 15 | // if the icon is null, there's nothing to do 16 | if (icon === null) { 17 | return null 18 | } 19 | 20 | // if the icon is an object and has a prefix and an icon name, return it 21 | if (icon && typeof icon === 'object' && icon.prefix && icon.iconName) { 22 | return icon 23 | } 24 | 25 | // if it's an array with length of two 26 | if (Array.isArray(icon) && icon.length === 2) { 27 | // use the first item as prefix, second as icon name 28 | return { prefix: icon[0], iconName: icon[1] } 29 | } 30 | 31 | // if it's a string, use it as the icon name 32 | if (typeof icon === 'string') { 33 | return { prefix: 'fas', iconName: icon } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/components/__fixtures__/icons.js: -------------------------------------------------------------------------------- 1 | export const faCoffee = { 2 | prefix: 'fas', 3 | iconName: 'coffee', 4 | icon: [ 5 | 640, 6 | 512, 7 | [], 8 | 'f0f4', 9 | 'M192 384h192c53 0 96-43 96-96h32c70.6 0 128-57.4 128-128S582.6 32 512 32H120c-13.3 0-24 10.7-24 24v232c0 53 43 96 96 96zM512 96c35.3 0 64 28.7 64 64s-28.7 64-64 64h-32V96h32zm47.7 384H48.3c-47.6 0-61-64-36-64h583.3c25 0 11.8 64-35.9 64z' 10 | ] 11 | } 12 | 13 | export const faCircle = { 14 | prefix: 'fas', 15 | iconName: 'circle', 16 | icon: [ 17 | 640, 18 | 512, 19 | [], 20 | 'f0f4', 21 | 'M192 384h192c53 0 96-43 96-96h32c70.6 0 128-57.4 128-128S582.6 32 512 32H120c-13.3 0-24 10.7-24 24v232c0 53 43 96 96 96zM512 96c35.3 0 64 28.7 64 64s-28.7 64-64 64h-32V96h32zm47.7 384H48.3c-47.6 0-61-64-36-64h583.3c25 0 11.8 64-35.9 64z' 22 | ] 23 | } 24 | 25 | export const faSpartan = { 26 | prefix: 'fat', 27 | iconName: 'spartan', 28 | icon: [ 29 | 640, 30 | 512, 31 | [], 32 | 'f0f4', 33 | 'M192 384h192c53 0 96-43 96-96h32c70.6 0 128-57.4 128-128S582.6 32 512 32H120c-13.3 0-24 10.7-24 24v232c0 53 43 96 96 96zM512 96c35.3 0 64 28.7 64 64s-28.7 64-64 64h-32V96h32zm47.7 384H48.3c-47.6 0-61-64-36-64h583.3c25 0 11.8 64-35.9 64z' 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "plugins": ["svelte3"], 4 | "rules": { 5 | "space-before-function-paren": 0 6 | }, 7 | "env": { 8 | "node": true, 9 | "browser": true, 10 | "es2022": true 11 | }, 12 | "parser": "@babel/eslint-parser", 13 | "parserOptions": { 14 | "ecmaVersion": 2022, 15 | "sourceType": "module", 16 | "requireConfigFile": false, 17 | "babelOptions": { 18 | "presets": ["@babel/preset-env"] 19 | } 20 | }, 21 | "globals": { 22 | "test": "readonly", 23 | "describe": "readonly", 24 | "expect": "readonly", 25 | "beforeEach": "readonly", 26 | "afterEach": "readonly", 27 | "vi": "readonly" 28 | }, 29 | "overrides": [ 30 | { 31 | "files": ["*.svelte"], 32 | "processor": "svelte3/svelte3", 33 | "rules": { 34 | "import/first": "off", 35 | "import/no-duplicates": "off", 36 | "import/no-mutable-exports": "off", 37 | "import/no-unresolved": "off", 38 | "import/prefer-default-export": "off", 39 | "no-multiple-empty-lines": [ 40 | "error", 41 | { 42 | "max": 1, 43 | "maxBOF": 2, 44 | "maxEOF": 0 45 | } 46 | ] 47 | } 48 | 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | --- 8 | 9 | ## [0.2.4](https://github.com/FortAwesome/svelte-fontawesome/releases/tag/0.2.4) - 2025-08-15 10 | 11 | ### Changed 12 | 13 | - Support for Font Awesome 7 14 | - Added explicit support and testing for Svelte 4 & 5 15 | 16 | ## [0.2.3](https://github.com/FortAwesome/svelte-fontawesome/releases/tag/0.2.3) - 2024-11-12 17 | 18 | ### Fixed 19 | 20 | - Color and style props can now be set as epected #11 21 | 22 | ## [0.2.2](https://github.com/FortAwesome/svelte-fontawesome/releases/tag/0.2.2) - 2024-02-16 23 | 24 | ### Fixed 25 | 26 | - Types are not recognized when using TypeScript #8 27 | 28 | ## [0.2.1](https://github.com/FortAwesome/svelte-fontawesome/releases/tag/0.2.1) - 2023-12-21 29 | 30 | ### Fixed 31 | 32 | - Support Sveltekit 2 by adding exports to package.json #6 33 | 34 | ## [0.2.0](https://github.com/FortAwesome/svelte-fontawesome/releases/tag/0.2.0) - 2022-08-02 35 | 36 | Special thanks to [@seantimm](https://github.com/seantimm) for putting the work in to port this to Svelte. 37 | 38 | ### Added 39 | 40 | * Initial release based largely on the @fortawesome/react-fontawesome component 41 | -------------------------------------------------------------------------------- /examples/svelte-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as CSS from 'csstype'; 3 | import { SvelteComponentTyped } from 'svelte'; 4 | import { 5 | Transform, 6 | IconName, 7 | IconProp, 8 | FlipProp, 9 | SizeProp, 10 | PullProp, 11 | RotateProp, 12 | FaSymbol 13 | } from '@fortawesome/fontawesome-svg-core' 14 | 15 | export class FontAwesomeIcon extends SvelteComponentTyped {} 16 | 17 | // This is identical to the version of Omit in Typescript 3.5. It is included for compatibility with older versions of Typescript. 18 | type BackwardCompatibleOmit = Pick>; 19 | 20 | type WithPrefix = `fa-${T} fa-${IconName}` 21 | 22 | export interface FontAwesomeIconProps { 23 | icon: WithPrefix<'solid'> | WithPrefix<'regular'> | WithPrefix<'light'> | WithPrefix<'thin'> | WithPrefix<'duotone'> | WithPrefix<'brands'> | IconProp 24 | mask?: IconProp 25 | maskId?: string 26 | class?: string 27 | spin?: boolean 28 | spinPulse?: boolean 29 | spinReverse?: boolean 30 | pulse?: boolean 31 | beat?: boolean 32 | fade?: boolean 33 | beatFade?: boolean 34 | bounce?: boolean 35 | shake?: boolean 36 | border?: boolean 37 | fixedWidth?: boolean 38 | inverse?: boolean 39 | listItem?: boolean 40 | flip?: FlipProp 41 | size?: SizeProp 42 | pull?: PullProp 43 | rotation?: RotateProp 44 | transform?: string | Transform 45 | symbol?: FaSymbol 46 | style?: CSS.PropertiesHyphen | string 47 | tabIndex?: number; 48 | title?: string; 49 | titleId?: string; 50 | swapOpacity?: boolean; 51 | } 52 | -------------------------------------------------------------------------------- /src/utils/get-class-list-from-props.js: -------------------------------------------------------------------------------- 1 | // Get CSS class list from a props object 2 | export default function classList(props) { 3 | const { 4 | beat, 5 | fade, 6 | beatFade, 7 | bounce, 8 | shake, 9 | flash, 10 | spin, 11 | spinPulse, 12 | spinReverse, 13 | pulse, 14 | fixedWidth, 15 | inverse, 16 | border, 17 | listItem, 18 | flip, 19 | size, 20 | rotation, 21 | pull 22 | } = props 23 | 24 | // map of CSS class names to properties 25 | const classes = { 26 | 'fa-beat': beat, 27 | 'fa-fade': fade, 28 | 'fa-beat-fade': beatFade, 29 | 'fa-bounce': bounce, 30 | 'fa-shake': shake, 31 | 'fa-flash': flash, 32 | 'fa-spin': spin, 33 | 'fa-spin-reverse': spinReverse, 34 | 'fa-spin-pulse': spinPulse, 35 | 'fa-pulse': pulse, 36 | 'fa-fw': fixedWidth, 37 | 'fa-inverse': inverse, 38 | 'fa-border': border, 39 | 'fa-li': listItem, 40 | 'fa-flip': flip === true, 41 | 'fa-flip-horizontal': flip === 'horizontal' || flip === 'both', 42 | 'fa-flip-vertical': flip === 'vertical' || flip === 'both', 43 | [`fa-${size}`]: typeof size !== 'undefined' && size !== null, 44 | [`fa-rotate-${rotation}`]: 45 | typeof rotation !== 'undefined' && rotation !== null && rotation !== 0, 46 | [`fa-pull-${pull}`]: typeof pull !== 'undefined' && pull !== null, 47 | 'fa-swap-opacity': props.swapOpacity 48 | } 49 | 50 | // map over all the keys in the classes object 51 | // return an array of the keys where the value for the key is not null 52 | return Object.keys(classes) 53 | .map(key => (classes[key] ? key : null)) 54 | .filter(key => key) 55 | } 56 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | # Developing Svelte Fontawesome 2 | 3 | ## Tasks 4 | 5 | The following commands are available through `npm run` 6 | 7 | | Command | Purpose | 8 | | ------- | ------------------------------------- | 9 | | build | Build this project | 10 | | dist | Build this project in production mode | 11 | | lint | Check linting using ESLint | 12 | | test | Run tests | 13 | 14 | ## Releasing a new version 15 | 16 | 17 | 18 | 1. Edit `package.json` and update the version number 19 | 1. Add new contributors to the `contributors` section 20 | 1. Update the `CHANGELOG.md` 21 | 1. Update the `README.md` contributors section 22 | 1. `npm run build` 23 | 1. `npm publish --tag latest` 24 | 1. `npm publish --tag latest --registry https://npm.fontawesome.com` (publish to Pro registry) 25 | 1. `git add . && git commit -m 'Release VERSION'` 26 | 1. `git push` 27 | 1. Create a [new release](https://github.com/FortAwesome/svelte-fontawesome/releases/new) with `CHANGELOG` details 28 | 29 | ## Authenticating with the npm.fontawesome.com registry 30 | 31 | Contributors with authorization to publish to npm.fontawesome.com will receive an invite 32 | from a Font Awesome project owner. 33 | 34 | 1. Respond to the invite in your email 35 | 1. Let the owner know when you've setup your account 36 | 1. Owner will add you to the team 37 | 38 | You can then run: 39 | 40 | ``` 41 | npm login --registry https://npm.fontawesome.com 42 | ``` 43 | 44 | - The username is the "slug" for your Cloudsmith account. For example mine is "rob-madole". 45 | - Enter the password that you setup just a few minutes ago. 46 | - It says the your email is PUBLIC. Pretty sure that's false since the auth is through Cloudsmith. 47 | - This doesn't overwrite your standard login, just adds to your `~/.npmrc` 48 | -------------------------------------------------------------------------------- /src/converter.js: -------------------------------------------------------------------------------- 1 | import camelize from './utils/camelize' 2 | 3 | function capitalize(val) { 4 | return val.charAt(0).toUpperCase() + val.slice(1) 5 | } 6 | 7 | export function styleToObject(style) { 8 | return style 9 | ? style 10 | .split(';') 11 | .map((s) => s.trim()) 12 | .filter((s) => s) 13 | .reduce((acc, pair) => { 14 | const i = pair.indexOf(':') 15 | const prop = camelize(pair.slice(0, i)) 16 | const value = pair.slice(i + 1).trim() 17 | 18 | prop.startsWith('webkit') 19 | ? (acc[capitalize(prop)] = value) 20 | : (acc[prop] = value) 21 | 22 | return acc 23 | }, {}) 24 | : null 25 | } 26 | 27 | export function styleToString(style) { 28 | if (typeof style === 'string') { 29 | return style 30 | } 31 | 32 | return Object.keys(style).reduce((acc, key) => ( 33 | acc + key.split(/(?=[A-Z])/).join('-').toLowerCase() + ':' + style[key] + ';' 34 | ), '') 35 | } 36 | 37 | function convert(createElement, element, extraProps = {}) { 38 | if (typeof element === 'string') { 39 | return element 40 | } 41 | 42 | const children = (element.children || []).map((child) => { 43 | return convert(createElement, child) 44 | }) 45 | 46 | /* eslint-disable dot-notation */ 47 | const mixins = Object.keys(element.attributes || {}).reduce( 48 | (acc, key) => { 49 | const val = element.attributes[key] 50 | 51 | if (key === 'style') { 52 | acc.attrs['style'] = styleToString(val) 53 | } else { 54 | if (key.indexOf('aria-') === 0 || key.indexOf('data-') === 0) { 55 | acc.attrs[key.toLowerCase()] = val 56 | } else { 57 | acc.attrs[camelize(key)] = val 58 | } 59 | } 60 | 61 | return acc 62 | }, 63 | { attrs: {} } 64 | ) 65 | 66 | /* eslint-enable */ 67 | 68 | return createElement(element.tag, { ...mixins.attrs }, children) 69 | } 70 | 71 | export default convert 72 | -------------------------------------------------------------------------------- /examples/svelte-app/src/App.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 |
9 |
10 |

11 | svelte-fontawesome 12 |

13 | 14 |
    15 | 18 | 21 | 29 | 37 | 44 | 51 | 58 | 65 |
66 |
67 |
68 |
69 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | This is the repository for the _official_ Font Awesome Svelte component, _initialized_ by the team behind Font Awesome, 2 | but intended to evolve over time with _community_ contributions. 3 | 4 | # Ways to Contribute 5 | 6 | ## Ask a Question 7 | 8 | Trying to figure out how to make it work? Or how to use it in your scenario? 9 | 10 | 1. Review the [README](README.md) 11 | 1. Get familiar with the documentation for the [SVG with JavaScript](https://fontawesome.com/how-to-use/svg-with-js) implementation, 12 | the framework upon which this component is built. Sometimes the answers you need may be there. 13 | 1. Post any remaining questions on [StackOverflow](https://stackoverflow.com/questions/tagged/svelte-fontawesome) with the tag `svelte-fontawesome`. 14 | 15 | ## Report a Bug 16 | 17 | 1. Create a test case that reproduces the unexpected behavior 18 | 1. [Open a new issue with this template](https://github.com/FortAwesome/svelte-fontawesome/issues/new?template=bug-report.md), 19 | and be sure to include a link to the reproduction you made with StackBlitz. 20 | 21 | ## Submit a Pull Request 22 | 23 | Add tests if you add code. 24 | 25 | ## Everything Else 26 | 27 | - [Request a feature](https://github.com/FortAwesome/svelte-fontawesome/issues/new??title=Feature%20request:feature-name&template=feature-request.md) 28 | - [Request a new icon](https://github.com/FortAwesome/Font-Awesome/issues/new?title=Icon%20request:%20icon-name&template=icon-request.md) 29 | 30 | # Project Goals 31 | 32 | 1. Achieve and maintain feature parity with Font Awesome's [SVG with JavaScript](https://fontawesome.com/how-to-use/svg-with-js) method. 33 | 34 | 1. Keep with best practices in the Svelte development community. 35 | 36 | 1. Stay current with major developments in Svelte and SvelteKit 37 | 38 | 1. Maintain a reasonable level of consistency between this component and the other Font Awesome official JavaScript 39 | framework components. 40 | 41 | # Code of Conduct 42 | 43 | We'll contribute according to the [Code of Conduct](CODE_OF_CONDUCT.md). 44 | 45 | # Wanted: Core Contributors 46 | 47 | We're seeking core contributors to help drive this project. Core contributors: 48 | 49 | 1. Share these goals 50 | 1. Demonstrate competence through contributions 51 | 1. Contribute with conduct fitting with our code of conduct 52 | 1. Want to make this project awesome 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Official Javascript Component 3 | 4 | 5 | # svelte-fontawesome 6 | 7 | [![npm](https://img.shields.io/npm/v/@fortawesome/svelte-fontawesome.svg?style=flat-square)](https://www.npmjs.com/package/@fortawesome/svelte-fontawesome) 8 | 9 | > Font Awesome Svelte component using SVG with JS 10 | 11 | 12 | 13 | - [Documentation](#documentation) 14 | - [How to Help](#how-to-help) 15 | - [Contributors](#contributors) 16 | - [Releasing this project (only project owners can do this)](#releasing-this-project-only-project-owners-can-do-this) 17 | 18 | 19 | 20 | 21 | 22 | ## Compatibility 23 | | Svelte version | svelte-fontawesome version | 24 | | - | - | 25 | | >= 3.x | 0.2.x | 26 | 27 | _Documentation is not currently available. Check out the `examples` directory to get started._ 28 | 29 | _We'll be working on documentation (either in this repo or on fontawesome.com) when time allows._ 30 | 31 | ## How to Help 32 | 33 | Review the following docs before diving in: 34 | 35 | - [CONTRIBUTING.md](CONTRIBUTING.md) 36 | - [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) 37 | 38 | And then: 39 | 40 | 1. Check the existing issue and see if you can help! 41 | 42 | ## Contributors 43 | 44 | The following contributors have either helped to start this project, have contributed 45 | code, are actively maintaining it (including documentation), or in other ways 46 | being awesome contributors to this project. **We'd like to take a moment to recognize them.** 47 | 48 | | Name | GitHub | 49 | | ----------------- | ---------------------------------------------------------- | 50 | | Sean Timm | [@seantimm](https://github.com/seantimm) | 51 | | Akiomi Kamakura | [@akiomik](https://github.com/akiomik) | 52 | | Daniel Senff | [@Dahie](https://github.com/Dahie) | 53 | | Konnng Digital | [@konnng-dev](https://github.com/konnng-dev) | 54 | | Martin Blasko | [@MartinBspheroid](https://github.com/MartinBspheroid) | 55 | | Font Awesome Team | [@FortAwesome](https://github.com/orgs/FortAwesome/people) | 56 | 57 | If we've missed someone (which is quite likely) submit a Pull Request to us and we'll get it resolved. 58 | 59 | ## Releasing this project (only project owners can do this) 60 | 61 | See [DEVELOPMENT.md](DEVELOPMENT.md#release) 62 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/src/App.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 |
26 |
27 |
28 |

29 | svelte-fontawesome (TypeScript edition) 30 |

31 | 32 |
    33 | 36 | 39 | 47 | 55 | 62 | 69 | 76 | 83 |
84 |
85 |
86 |
87 | -------------------------------------------------------------------------------- /examples/svelte-app/README.md: -------------------------------------------------------------------------------- 1 | # Svelte + Vite 2 | 3 | This template should help get you started developing with Svelte in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). 8 | 9 | ## Need an official Svelte framework? 10 | 11 | Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. 12 | 13 | ## Technical considerations 14 | 15 | **Why use this over SvelteKit?** 16 | 17 | - It brings its own routing solution which might not be preferable for some users. 18 | - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. 19 | `vite dev` and `vite build` wouldn't work in a SvelteKit environment, for example. 20 | 21 | This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. 22 | 23 | Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. 24 | 25 | **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** 26 | 27 | Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. 28 | 29 | **Why include `.vscode/extensions.json`?** 30 | 31 | Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. 32 | 33 | **Why enable `checkJs` in the JS template?** 34 | 35 | It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate. This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of JavaScript, it is trivial to change the configuration. 36 | 37 | **Why is HMR not preserving my local component state?** 38 | 39 | HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). 40 | 41 | If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. 42 | 43 | ```js 44 | // store.js 45 | // An extremely simple external store 46 | import { writable } from 'svelte/store' 47 | export default writable(0) 48 | ``` 49 | -------------------------------------------------------------------------------- /src/components/__fixtures__/helpers.js: -------------------------------------------------------------------------------- 1 | import FontAwesomeIcon from '../FontAwesomeIcon.svelte' 2 | import { styleToObject, styleToString } from '../../converter' 3 | import { cleanup, render, screen } from '@testing-library/svelte' 4 | import { parse } from '@fortawesome/fontawesome-svg-core' 5 | import semver from 'semver' 6 | 7 | import svgCorePackageJson from '@fortawesome/fontawesome-svg-core/package.json' with { type: 'json' } 8 | import svgIconsPackageJson from '@fortawesome/free-solid-svg-icons/package.json' with { type: 'json' } 9 | 10 | const SVG_CORE_VERSION = semver.parse(svgCorePackageJson.version) 11 | const SVG_ICONS_VERSION = semver.parse(svgIconsPackageJson.version) 12 | 13 | export const REFERENCE_ICON_BY_STYLE = 0x00 14 | export const ICON_ALIASES = 0x01 15 | export const REFERENCE_ICON_USING_STRING = 0x02 16 | export const USES_A11Y_TITLE = 0x03 17 | 18 | export function coreHasFeature(feature) { 19 | if (feature === ICON_ALIASES) { 20 | // Aliases were not introduced until version 6 so we need to check the 21 | // installed free-solid-svg-icons package as well. 22 | return parse.icon && SVG_ICONS_VERSION.major >= 6 23 | } 24 | 25 | if (feature === USES_A11Y_TITLE) { 26 | // Accessibility changed in version 7 and the title attribute is no longer used 27 | return SVG_CORE_VERSION.major < 7 28 | } 29 | 30 | if ( 31 | feature === REFERENCE_ICON_BY_STYLE || 32 | feature === REFERENCE_ICON_USING_STRING 33 | ) { 34 | return parse.icon 35 | } 36 | } 37 | 38 | function convertToTestResult(component, props) { 39 | const attributes = component.getAttributeNames().reduce((acc, name) => { 40 | return { 41 | ...acc, 42 | [name]: component.getAttribute(name) 43 | } 44 | }, {}) 45 | 46 | attributes.style = styleToObject(attributes.style) 47 | 48 | let nodeName = component.nodeName.toLowerCase() 49 | if (component.nodeName === 'svelte:element') { 50 | // temp extreme silliness due to svelte-testing-library issue w/ svelte:options resulting 51 | // in svelte:element instead of proper nodeName - grossly inaccurate but works for now 52 | if (props?.symbol) { 53 | nodeName = 'symbol' 54 | } else if (props?.title) { 55 | nodeName = 'title' 56 | } else { 57 | nodeName = 'svg' 58 | } 59 | } 60 | 61 | return { 62 | id: component.id, 63 | type: nodeName, 64 | props: attributes, 65 | children: component.children.length 66 | ? Array.from(component.children).map((child) => 67 | convertToTestResult(child, props) 68 | ) 69 | : [component.innerHTML] 70 | } 71 | } 72 | 73 | export function mount(props = {}, { createNodeMock } = {}) { 74 | let result = null 75 | 76 | // Conversion for test values to make it easy to copy over new tests from react-fontawesome 77 | if (props.style) { 78 | props.style = styleToString(props.style) 79 | } 80 | 81 | props.class = props.class || props.className 82 | 83 | render(FontAwesomeIcon, { props }) 84 | const domComponent = screen.queryByRole('img', { hidden: true }) 85 | if (domComponent) { 86 | result = convertToTestResult(domComponent, props) 87 | } 88 | 89 | cleanup() 90 | 91 | return result 92 | } 93 | -------------------------------------------------------------------------------- /examples/svelte-app-typescript/README.md: -------------------------------------------------------------------------------- 1 | # Svelte + TS + Vite 2 | 3 | This template should help get you started developing with Svelte and TypeScript in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). 8 | 9 | ## Need an official Svelte framework? 10 | 11 | Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less, and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more. 12 | 13 | ## Technical considerations 14 | 15 | **Why use this over SvelteKit?** 16 | 17 | - It brings its own routing solution which might not be preferable for some users. 18 | - It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app. 19 | `vite dev` and `vite build` wouldn't work in a SvelteKit environment, for example. 20 | 21 | This template contains as little as possible to get started with Vite + TypeScript + Svelte, while taking into account the developer experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite` templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project. 22 | 23 | Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been structured similarly to SvelteKit so that it is easy to migrate. 24 | 25 | **Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?** 26 | 27 | Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash references keeps the default TypeScript setting of accepting type information from the entire workspace, while also adding `svelte` and `vite/client` type information. 28 | 29 | **Why include `.vscode/extensions.json`?** 30 | 31 | Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to install the recommended extension upon opening the project. 32 | 33 | **Why enable `allowJs` in the TS template?** 34 | 35 | While `allowJs: false` would indeed prevent the use of `.js` files in the project, it does not prevent the use of JavaScript syntax in `.svelte` files. In addition, it would force `checkJs: false`, bringing the worst of both worlds: not being able to guarantee the entire codebase is TypeScript, and also having worse typechecking for the existing JavaScript. In addition, there are valid use cases in which a mixed codebase may be relevant. 36 | 37 | **Why is HMR not preserving my local component state?** 38 | 39 | HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr` and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the details [here](https://github.com/rixo/svelte-hmr#svelte-hmr). 40 | 41 | If you have state that's important to retain within a component, consider creating an external store which would not be replaced by HMR. 42 | 43 | ```ts 44 | // store.ts 45 | // An extremely simple external store 46 | import { writable } from 'svelte/store' 47 | export default writable(0) 48 | ``` 49 | -------------------------------------------------------------------------------- /src/components/FontAwesomeIcon.svelte: -------------------------------------------------------------------------------- 1 | 100 | 101 | {#if result} 102 | 103 | {/if} 104 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [https://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: https://contributor-covenant.org 74 | [version]: https://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@fortawesome/svelte-fontawesome", 3 | "description": "Svelte component for Font Awesome", 4 | "version": "0.2.4", 5 | "type": "module", 6 | "svelte": "src/index.js", 7 | "exports": { 8 | ".": { 9 | "types": "./index.d.ts", 10 | "svelte": "./src/index.js" 11 | } 12 | }, 13 | "main": "index.js", 14 | "module": "index.es.js", 15 | "jsnext:main": "index.es.js", 16 | "types": "index.d.ts", 17 | "homepage": "https://github.com/FortAwesome/svelte-fontawesome", 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/FortAwesome/svelte-fontawesome.git" 21 | }, 22 | "contributors": [ 23 | "Font Awesome Team ", 24 | "Sean Timm ", 25 | "Akiomi Kamakura ", 26 | "Daniel Senff ", 27 | "Konnng Digital ", 28 | "Martin Blasko " 29 | ], 30 | "license": "MIT", 31 | "scripts": { 32 | "build": "rollup -c rollup.config.js", 33 | "dist": "cross-env NODE_ENV=production npm run build", 34 | "lint": "eslint src", 35 | "prettier": "pretty-quick --pattern src/** --staged", 36 | "prepack": "npm run dist", 37 | "test": "vitest run", 38 | "test:watch": "vitest", 39 | "test:ui": "vitest --ui", 40 | "install.5": "npm --no-save install @fortawesome/fontawesome-svg-core@1.2.x @fortawesome/free-solid-svg-icons@5.x", 41 | "install.6": "npm --no-save install @fortawesome/fontawesome-svg-core@6.x @fortawesome/free-solid-svg-icons@6.x", 42 | "clean": "rm -f index.js && rm -f index.es.js" 43 | }, 44 | "lint-staged": { 45 | "README.md": [ 46 | "markdown-toc -i", 47 | "git add README.md" 48 | ] 49 | }, 50 | "peerDependencies": { 51 | "@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7", 52 | "svelte": "~3 || ~4 || ~5" 53 | }, 54 | "devDependencies": { 55 | "@babel/core": "^7.18.6", 56 | "@babel/eslint-parser": "^7.18.2", 57 | "@babel/plugin-external-helpers": "^7.18.6", 58 | "@babel/preset-env": "^7.18.6", 59 | "@babel/preset-stage-3": "^7.8.3", 60 | "@fortawesome/fontawesome-svg-core": "^7", 61 | "@fortawesome/free-solid-svg-icons": "^7", 62 | "@pyoner/svelte-types": "^3.4.4-2", 63 | "@rollup/plugin-babel": "^5.3.1", 64 | "@rollup/plugin-commonjs": "^22.0.1", 65 | "@rollup/plugin-node-resolve": "^13.3.0", 66 | "@sveltejs/vite-plugin-svelte": "^2.5.3", 67 | "@testing-library/jest-dom": "^5.17.0", 68 | "@testing-library/svelte": "^5.2.8", 69 | "@vitest/ui": "^3.2.4", 70 | "browserslist": "^4.21.2", 71 | "caniuse-lite": "^1.0.30001299", 72 | "cross-env": "^7.0.3", 73 | "eslint": "^8.16.0", 74 | "eslint-config-standard": "^17.0.0", 75 | "eslint-plugin-compat": "^4.0.2", 76 | "eslint-plugin-import": "^2.26.0", 77 | "eslint-plugin-n": "^15.2.4", 78 | "eslint-plugin-promise": "^6.0.0", 79 | "eslint-plugin-svelte3": "^4.0.0", 80 | "husky": "^7.0.4", 81 | "jsdom": "^26.1.0", 82 | "lint-staged": "^12.1.7", 83 | "markdown-toc": "^1.2.0", 84 | "prettier": "^2.7.1", 85 | "pretty-quick": "^3.1.3", 86 | "rollup": "^2.76.0", 87 | "rollup-plugin-svelte": "^7.1.0", 88 | "semver": "^7.3.7", 89 | "svelte": ">=3.x", 90 | "vitest": "^3.2.4" 91 | }, 92 | "files": [ 93 | "index.js", 94 | "index.es.js", 95 | "index.d.ts", 96 | "src" 97 | ], 98 | "browserslist": [ 99 | "> 1%", 100 | "last 2 versions", 101 | "ie > 10" 102 | ], 103 | "husky": { 104 | "hooks": { 105 | "pre-commit": "npm run lint && npm run prettier && lint-staged" 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/utils/__tests__/get-class-list-from-props.test.js: -------------------------------------------------------------------------------- 1 | import getClassList from '../get-class-list-from-props' 2 | 3 | describe('get class list', () => { 4 | test('test the booleans', () => { 5 | const props = { 6 | border: true, 7 | fixedWidth: true, 8 | inverse: true, 9 | listItem: true, 10 | pulse: true, 11 | spin: true, 12 | spinPulse: true, 13 | spinReverse: true, 14 | beat: true, 15 | fade: true, 16 | beatFade: true, 17 | bounce: true, 18 | shake: true, 19 | swapOpacity: true, 20 | flip: true 21 | } 22 | 23 | const classList = getClassList(props) 24 | 25 | expect(classList).toStrictEqual([ 26 | 'fa-beat', 27 | 'fa-fade', 28 | 'fa-beat-fade', 29 | 'fa-bounce', 30 | 'fa-shake', 31 | 'fa-spin', 32 | 'fa-spin-reverse', 33 | 'fa-spin-pulse', 34 | 'fa-pulse', 35 | 'fa-fw', 36 | 'fa-inverse', 37 | 'fa-border', 38 | 'fa-li', 39 | 'fa-flip', 40 | 'fa-swap-opacity' 41 | ]) 42 | }) 43 | 44 | test('size', () => { 45 | function testSize(size) { 46 | expect(getClassList({ size })).toStrictEqual([`fa-${size}`]) 47 | } 48 | 49 | testSize('xs') 50 | }) 51 | 52 | test('flip', () => { 53 | const HORIZONTAL = 'fa-flip-horizontal' 54 | const VERTICAL = 'fa-flip-vertical' 55 | const FLIP_ANIMATION = 'fa-flip' 56 | 57 | const horizontalList = getClassList({ 58 | flip: 'horizontal' 59 | }) 60 | 61 | const verticalList = getClassList({ 62 | flip: 'vertical' 63 | }) 64 | 65 | const bothList = getClassList({ 66 | flip: 'both' 67 | }) 68 | 69 | const flipAnimationOnly = getClassList({ 70 | flip: true 71 | }) 72 | 73 | expect(horizontalList).toContain(HORIZONTAL) 74 | expect(verticalList).toContain(VERTICAL) 75 | 76 | expect(bothList.length).toBe(2) 77 | expect(bothList).toContain(HORIZONTAL) 78 | expect(bothList).toContain(VERTICAL) 79 | 80 | expect(flipAnimationOnly).toContain(FLIP_ANIMATION) 81 | }) 82 | 83 | test('size', () => { 84 | function testSize(size) { 85 | expect(getClassList({ size })).toStrictEqual([`fa-${size}`]) 86 | } 87 | 88 | testSize('xs') 89 | }) 90 | 91 | test('rotation', () => { 92 | function testRotation(rotation) { 93 | expect(getClassList({ rotation })).toStrictEqual([ 94 | `fa-rotate-${rotation}` 95 | ]) 96 | } 97 | 98 | testRotation(90) 99 | testRotation(180) 100 | testRotation(270) 101 | }) 102 | 103 | test('pull', () => { 104 | function testPull(pull) { 105 | expect(getClassList({ pull })).toStrictEqual([`fa-pull-${pull}`]) 106 | } 107 | 108 | testPull('left') 109 | testPull('right') 110 | }) 111 | 112 | describe('when some props are null', () => { 113 | function testNulls(prop) { 114 | const NUM_CLASSES = 6 115 | 116 | const props = { 117 | spin: true, 118 | pulse: true, 119 | fixedWidth: true, 120 | inverse: true, 121 | border: true, 122 | listItem: true, 123 | [prop]: null 124 | } 125 | 126 | const classList = getClassList(props) 127 | expect(classList.length).toBe(NUM_CLASSES) 128 | expect(classList).toStrictEqual([ 129 | 'fa-spin', 130 | 'fa-pulse', 131 | 'fa-fw', 132 | 'fa-inverse', 133 | 'fa-border', 134 | 'fa-li' 135 | ]) 136 | } 137 | 138 | test('pull', () => { 139 | testNulls('pull') 140 | }) 141 | 142 | test('rotation', () => { 143 | testNulls('rotation') 144 | }) 145 | 146 | test('size', () => { 147 | testNulls('size') 148 | }) 149 | }) 150 | }) 151 | -------------------------------------------------------------------------------- /src/components/__tests__/FontAwesomeIcon.test.js: -------------------------------------------------------------------------------- 1 | import { vi } from 'vitest' 2 | import * as fontawesome from '@fortawesome/fontawesome-svg-core' 3 | import log from '../../logger' 4 | import { faTimes } from '@fortawesome/free-solid-svg-icons' 5 | import { faCoffee, faCircle, faSpartan } from '../__fixtures__/icons' 6 | import { 7 | coreHasFeature, 8 | REFERENCE_ICON_USING_STRING, 9 | REFERENCE_ICON_BY_STYLE, 10 | ICON_ALIASES, 11 | USES_A11Y_TITLE, 12 | mount 13 | } from '../__fixtures__/helpers' 14 | 15 | vi.mock('../../logger') 16 | 17 | beforeEach(() => { 18 | fontawesome.library.add(faCoffee, faCircle, faSpartan) 19 | }) 20 | 21 | afterEach(() => { 22 | fontawesome.library.reset() 23 | }) 24 | 25 | test('using a FAT icon using array format', () => { 26 | const vm = mount({ 27 | icon: ['fat', 'spartan'] 28 | }) 29 | 30 | expect(vm.type).toBe('svg') 31 | expect(vm.props.class.includes('fa-spartan')).toBeTruthy() 32 | }) 33 | 34 | if (coreHasFeature(ICON_ALIASES)) { 35 | test('find a free-solid-svg-icon with array format', () => { 36 | fontawesome.library.add(faTimes) 37 | const vm = mount({ icon: ['fas', 'xmark'] }) 38 | 39 | expect(vm.type).toBe('svg') 40 | expect(vm.props.class.includes('fa-xmark')).toBeTruthy() 41 | }) 42 | 43 | test('find a free-solid-svg-icon that is an alias ', () => { 44 | fontawesome.library.add(faTimes) 45 | const vm = mount({ icon: ['fas', 'close'] }) 46 | 47 | expect(vm.type).toBe('svg') 48 | expect(vm.props.class.includes('fa-xmark')).toBeTruthy() 49 | }) 50 | } 51 | 52 | if (coreHasFeature(REFERENCE_ICON_USING_STRING)) { 53 | test('find an icon using string format', () => { 54 | const vm = mount({ icon: 'fa-coffee' }) 55 | 56 | expect(vm.type).toBe('svg') 57 | expect(vm.props.class.includes('fa-coffee')).toBeTruthy() 58 | }) 59 | 60 | test('find an icon using string format with style', () => { 61 | const vm = mount({ icon: 'fa-solid fa-coffee' }) 62 | 63 | expect(vm.type).toBe('svg') 64 | expect(vm.props.class.includes('fa-coffee')).toBeTruthy() 65 | }) 66 | } 67 | 68 | if (coreHasFeature(REFERENCE_ICON_BY_STYLE)) { 69 | test('find a THIN icon with array format', () => { 70 | const vm = mount({ icon: ['thin', 'spartan'] }) 71 | 72 | expect(vm.type).toBe('svg') 73 | expect(vm.props.class.includes('fa-spartan')).toBeTruthy() 74 | }) 75 | 76 | test('find a FA-THIN icon with array format', () => { 77 | const vm = mount({ icon: ['fa-thin', 'spartan'] }) 78 | 79 | expect(vm.type).toBe('svg') 80 | expect(vm.props.class.includes('fa-spartan')).toBeTruthy() 81 | }) 82 | } 83 | 84 | test('using imported object from svg icons package', () => { 85 | const vm = mount({ 86 | icon: faTimes 87 | }) 88 | 89 | expect(vm.type).toBe('svg') 90 | }) 91 | 92 | test('using pack and name', () => { 93 | const vm = mount({ 94 | icon: ['fas', 'coffee'], 95 | style: { backgroundColor: 'white' } 96 | }) 97 | 98 | expect(vm.type).toBe('svg') 99 | expect(vm.props.class.includes('fa-coffee')).toBeTruthy() 100 | expect(vm.props['aria-hidden']).toBe('true') 101 | expect(vm.props['data-icon']).toBe('coffee') 102 | expect(vm.props.style).toEqual({ backgroundColor: 'white' }) 103 | }) 104 | 105 | test('using pack common names', () => { 106 | const vm = mount({ icon: 'coffee' }) 107 | 108 | expect(vm.type).toBe('svg') 109 | expect(vm.props.class.includes('fa-coffee')).toBeTruthy() 110 | }) 111 | 112 | test('using pack common names not added to library', () => { 113 | const vm = mount({ icon: 'spinner' }) 114 | expect(vm).toBeNull() 115 | expect(log.mock.calls.length).toBe(1) 116 | expect(log.mock.calls[0][0]).toEqual( 117 | expect.stringContaining('Could not find icon') 118 | ) 119 | }) 120 | 121 | test('using icon', () => { 122 | const vm = mount({ icon: faCoffee }) 123 | 124 | expect(vm.type).toBe('svg') 125 | expect(vm.props.class.includes('fa-coffee')).toBeTruthy() 126 | }) 127 | 128 | test('using border', () => { 129 | const vm = mount({ icon: faCoffee, border: true }) 130 | 131 | expect(vm.props.class.includes('fa-border')).toBeTruthy() 132 | }) 133 | 134 | test('using fixedWidth', () => { 135 | const vm = mount({ icon: faCoffee, fixedWidth: true }) 136 | 137 | expect(vm.props.class.includes('fa-fw')).toBeTruthy() 138 | }) 139 | 140 | test('using inverse', () => { 141 | const vm = mount({ icon: faCoffee, inverse: true }) 142 | 143 | expect(vm.props.class.includes('fa-inverse')).toBeTruthy() 144 | }) 145 | 146 | describe('using flip', () => { 147 | test('horizontal', () => { 148 | const vm = mount({ icon: faCoffee, flip: 'horizontal' }) 149 | 150 | expect(vm.props.class.includes('fa-flip-horizontal')).toBeTruthy() 151 | }) 152 | 153 | test('vertical', () => { 154 | const vm = mount({ icon: faCoffee, flip: 'vertical' }) 155 | 156 | expect(vm.props.class.includes('fa-flip-vertical')).toBeTruthy() 157 | }) 158 | 159 | test('both', () => { 160 | const vm = mount({ icon: faCoffee, flip: 'both' }) 161 | 162 | expect(vm.props.class.includes('fa-flip-horizontal')).toBeTruthy() 163 | expect(vm.props.class.includes('fa-flip-vertical')).toBeTruthy() 164 | }) 165 | 166 | test('animation', () => { 167 | const vm = mount({ icon: faCoffee, flip: true }) 168 | 169 | expect(vm.props.class.includes('fa-flip')).toBeTruthy() 170 | }) 171 | }) 172 | 173 | test('using listItem', () => { 174 | const vm = mount({ icon: faCoffee, listItem: true }) 175 | 176 | expect(vm.props.class.includes('fa-li')).toBeTruthy() 177 | }) 178 | 179 | describe('using pull', () => { 180 | test('right', () => { 181 | const vm = mount({ icon: faCoffee, pull: 'right' }) 182 | 183 | expect(vm.props.class.includes('fa-pull-right')).toBeTruthy() 184 | }) 185 | 186 | test('left', () => { 187 | const vm = mount({ icon: faCoffee, pull: 'left' }) 188 | 189 | expect(vm.props.class.includes('fa-pull-left')).toBeTruthy() 190 | }) 191 | }) 192 | 193 | test('using pulse', () => { 194 | const vm = mount({ icon: faCoffee, pulse: true }) 195 | 196 | expect(vm.props.class.includes('fa-pulse')).toBeTruthy() 197 | }) 198 | 199 | describe('using rotation', () => { 200 | test('0', () => { 201 | const vm = mount({ icon: faCoffee, rotation: 0 }) 202 | 203 | expect(vm.props.class.includes('fa-rotate-')).toBeFalsy() 204 | }) 205 | 206 | test('90', () => { 207 | const vm = mount({ icon: faCoffee, rotation: 90 }) 208 | 209 | expect(vm.props.class.includes('fa-rotate-90')).toBeTruthy() 210 | }) 211 | 212 | test('180', () => { 213 | const vm = mount({ icon: faCoffee, rotation: 180 }) 214 | 215 | expect(vm.props.class.includes('fa-rotate-180')).toBeTruthy() 216 | }) 217 | 218 | test('270', () => { 219 | const vm = mount({ icon: faCoffee, rotation: 270 }) 220 | 221 | expect(vm.props.class.includes('fa-rotate-270')).toBeTruthy() 222 | }) 223 | }) 224 | 225 | test('using size', () => { 226 | ;[ 227 | '2xs', 228 | 'xs', 229 | 'sm', 230 | 'lg', 231 | 'xl', 232 | '2xl', 233 | '1x', 234 | '2x', 235 | '3x', 236 | '4x', 237 | '5x', 238 | '6x', 239 | '7x', 240 | '8x', 241 | '9x', 242 | '10x' 243 | ].forEach((size) => { 244 | const vm = mount({ icon: faCoffee, size }) 245 | 246 | expect(vm.props.class.includes(`fa-${size}`)).toBeTruthy() 247 | }) 248 | }) 249 | 250 | describe('using beat', () => { 251 | test('setting beat prop to true adds fa-beat class', () => { 252 | const vm = mount({ icon: faCoffee, beat: true }) 253 | 254 | expect(vm.props.class.includes('fa-beat')).toBeTruthy() 255 | }) 256 | 257 | test('setting beat prop to false after setting it to true results in no fa-beat class', () => { 258 | let vm = mount({ icon: faCoffee, beat: true }) 259 | expect(vm.props.class.includes('fa-beat')).toBeTruthy() 260 | vm = mount({ icon: faCoffee, beat: false }) 261 | expect(vm.props.class.includes('fa-beat')).toBeFalsy() 262 | }) 263 | }) 264 | 265 | describe('using fade', () => { 266 | test('setting fade prop to true adds fa-fade class', () => { 267 | const vm = mount({ icon: faCoffee, fade: true }) 268 | 269 | expect(vm.props.class.includes('fa-fade')).toBeTruthy() 270 | }) 271 | 272 | test('setting fade prop to false after setting it to true results in no fa-fade class', () => { 273 | let vm = mount({ icon: faCoffee, fade: true }) 274 | expect(vm.props.class.includes('fa-fade')).toBeTruthy() 275 | vm = mount({ icon: faCoffee, fade: false }) 276 | expect(vm.props.class.includes('fa-fade')).toBeFalsy() 277 | }) 278 | }) 279 | 280 | describe('using beatFade', () => { 281 | test('setting beatFade prop to true adds fa-beat-fade class', () => { 282 | const vm = mount({ icon: faCoffee, beatFade: true }) 283 | 284 | expect(vm.props.class.includes('fa-beat-fade')).toBeTruthy() 285 | }) 286 | 287 | test('setting beatFade prop to false after setting it to true results in no fa-beat-fade class', () => { 288 | let vm = mount({ icon: faCoffee, beatFade: true }) 289 | expect(vm.props.class.includes('fa-beat-fade')).toBeTruthy() 290 | vm = mount({ icon: faCoffee, beatFade: false }) 291 | expect(vm.props.class.includes('fa-beat-fade')).toBeFalsy() 292 | }) 293 | }) 294 | 295 | describe('using bounce', () => { 296 | test('setting bounce prop to true adds fa-bounce class', () => { 297 | const vm = mount({ icon: faCoffee, bounce: true }) 298 | 299 | expect(vm.props.class.includes('fa-bounce')).toBeTruthy() 300 | }) 301 | 302 | test('setting bounce prop to false after setting it to true results in no fa-bounce class', () => { 303 | let vm = mount({ icon: faCoffee, bounce: true }) 304 | expect(vm.props.class.includes('fa-bounce')).toBeTruthy() 305 | vm = mount({ icon: faCoffee, bounce: false }) 306 | expect(vm.props.class.includes('fa-bounce')).toBeFalsy() 307 | }) 308 | }) 309 | 310 | describe('using shake', () => { 311 | test('setting shake prop to true adds fa-shake class', () => { 312 | const vm = mount({ icon: faCoffee, shake: true }) 313 | 314 | expect(vm.props.class.includes('fa-shake')).toBeTruthy() 315 | }) 316 | 317 | test('setting shake prop to false after setting it to true results in no fa-shake class', () => { 318 | let vm = mount({ icon: faCoffee, shake: true }) 319 | expect(vm.props.class.includes('fa-shake')).toBeTruthy() 320 | vm = mount({ icon: faCoffee, shake: false }) 321 | expect(vm.props.class.includes('fa-shake')).toBeFalsy() 322 | }) 323 | }) 324 | 325 | describe('using spin', () => { 326 | test('setting spin prop to true adds fa-spin class', () => { 327 | const vm = mount({ icon: faCoffee, spin: true }) 328 | 329 | expect(vm.props.class.includes('fa-spin')).toBeTruthy() 330 | }) 331 | 332 | test('setting spinReverse and spinPulse prop to true adds fa-spin-reverse and fa-spin-pulse class', () => { 333 | const vm = mount({ icon: faCoffee, spinReverse: true, spinPulse: true }) 334 | 335 | expect(vm.props.class.includes('fa-spin-reverse')).toBeTruthy() 336 | expect(vm.props.class.includes('fa-spin-pulse')).toBeTruthy() 337 | }) 338 | 339 | test('setting spin prop to false after setting it to true results in no fa-spin class', () => { 340 | let vm = mount({ icon: faCoffee, spin: true }) 341 | expect(vm.props.class.includes('fa-spin')).toBeTruthy() 342 | vm = mount({ icon: faCoffee, spin: false }) 343 | expect(vm.props.class.includes('fa-spin')).toBeFalsy() 344 | }) 345 | 346 | test('setting spinPulse prop to false after setting it to true results in no fa-spin-pulse class', () => { 347 | let vm = mount({ icon: faCoffee, spinPulse: true }) 348 | expect(vm.props.class.includes('fa-spin-pulse')).toBeTruthy() 349 | vm = mount({ icon: faCoffee, spinPulse: false }) 350 | expect(vm.props.class.includes('fa-spin-pulse')).toBeFalsy() 351 | }) 352 | 353 | test('setting spinReverse prop to false after setting it to true results in no fa-spin-reverse class', () => { 354 | let vm = mount({ icon: faCoffee, spinReverse: true }) 355 | expect(vm.props.class.includes('fa-spin-reverse')).toBeTruthy() 356 | vm = mount({ icon: faCoffee, spinReverse: false }) 357 | expect(vm.props.class.includes('fa-spin-reverse')).toBeFalsy() 358 | }) 359 | }) 360 | 361 | test('using class', () => { 362 | const vm = mount({ icon: faCoffee, class: 'highlight' }) 363 | 364 | expect(vm.props.class.includes('highlight')).toBeTruthy() 365 | }) 366 | 367 | describe('using transform', () => { 368 | test('string', () => { 369 | const vm = mount({ 370 | icon: faCoffee, 371 | transform: 'grow-40 left-4 rotate-15', 372 | style: { backgroundColor: 'white' } 373 | }) 374 | 375 | expect(vm.props.style).toEqual({ 376 | backgroundColor: 'white', 377 | transformOrigin: '0.375em 0.5em' 378 | }) 379 | }) 380 | 381 | test('object', () => { 382 | const vm = mount({ 383 | icon: faCoffee, 384 | transform: { 385 | flipX: false, 386 | flipY: false, 387 | rotate: 15, 388 | size: 56, 389 | x: -4, 390 | y: 0 391 | } 392 | }) 393 | 394 | expect(vm.props.style).toEqual({ transformOrigin: '0.375em 0.5em' }) 395 | }) 396 | }) 397 | 398 | describe('mask', () => { 399 | test('will add icon', () => { 400 | const vm = mount({ icon: faCoffee, mask: faCircle }) 401 | 402 | expect(vm.children.length).toBe(2) 403 | expect(vm.children[1].props.hasOwnProperty('clippath')).toBeTruthy() // eslint-disable-line no-prototype-builtins 404 | }) 405 | 406 | test('will use maskId', () => { 407 | const vm = mount({ icon: faCoffee, mask: faCircle, maskId: 'circle-mask' }) 408 | 409 | expect(vm.children[0].children[0].props.id).toEqual('clip-circle-mask') 410 | expect(vm.children[0].children[1].props.id).toEqual('mask-circle-mask') 411 | expect(vm.children[1].props.mask).toEqual('url(#mask-circle-mask)') 412 | expect(vm.children[1].props.clippath).toEqual('url(#clip-circle-mask)') 413 | }) 414 | }) 415 | 416 | describe('symbol', () => { 417 | test('will not create a symbol', () => { 418 | const vm = mount({ icon: faCoffee }) 419 | expect(vm.type).toBe('svg') 420 | }) 421 | 422 | test('will create a symbol', () => { 423 | const vm = mount({ icon: faCoffee, symbol: 'coffee-icon' }) 424 | 425 | expect(vm.type).toBe('symbol') 426 | expect(vm.id).toBe('coffee-icon') 427 | }) 428 | }) 429 | 430 | describe('swap opacity', () => { 431 | test('setting swapOpacity prop to true adds fa-swap-opacity class', () => { 432 | const vm = mount({ icon: faCoffee, swapOpacity: true }) 433 | 434 | expect(vm.props.class.includes('fa-swap-opacity')).toBeTruthy() 435 | }) 436 | 437 | test('setting swapOpacity prop to false after setting it to true results in no fa-swap-opacity class', () => { 438 | let vm = mount({ icon: faCoffee, swapOpacity: true }) 439 | expect(vm.props.class.includes('fa-swap-opacity')).toBeTruthy() 440 | vm = mount({ icon: faCoffee, swapOpacity: false }) 441 | expect(vm.props.class.includes('fa-swap-opacity')).toBeFalsy() 442 | }) 443 | }) 444 | 445 | if (coreHasFeature(USES_A11Y_TITLE)) { 446 | describe('title', () => { 447 | test('will not add a title element', () => { 448 | const vm = mount({ icon: faCoffee }) 449 | 450 | expect(vm.children[0].type).not.toBe('title') 451 | }) 452 | 453 | test('will add a title element', () => { 454 | const vm = mount({ icon: faCoffee, title: 'Coffee' }) 455 | 456 | expect(vm.children[0].type).toBe('title') 457 | expect(vm.children[0].children[0]).toBe('Coffee') 458 | }) 459 | 460 | test('will use an explicit titleId', () => { 461 | const vm = mount({ 462 | icon: faCoffee, 463 | title: 'Coffee', 464 | titleId: 'coffee-title' 465 | }) 466 | 467 | expect(vm.props['aria-labelledby']).toBe( 468 | 'svg-inline--fa-title-coffee-title' 469 | ) 470 | expect(vm.children[0].props).toEqual( 471 | expect.objectContaining({ id: 'svg-inline--fa-title-coffee-title' }) 472 | ) 473 | }) 474 | }) 475 | 476 | describe('using titleId', () => { 477 | test('setting titleId prop reflects in the aria-labelledby attribute', () => { 478 | const titleId = 'foo' 479 | const vm = mount({ icon: faCoffee, titleId, title: 'Coffee' }) 480 | const ariaLabelledby = vm.props['aria-labelledby'] 481 | expect(ariaLabelledby.includes(titleId)).toBeTruthy() 482 | }) 483 | }) 484 | } 485 | -------------------------------------------------------------------------------- /index.es.js: -------------------------------------------------------------------------------- 1 | import { parse, icon } from '@fortawesome/fontawesome-svg-core'; 2 | 3 | function run(fn) { 4 | return fn(); 5 | } 6 | function blank_object() { 7 | return Object.create(null); 8 | } 9 | function run_all(fns) { 10 | fns.forEach(run); 11 | } 12 | function compute_rest_props(props, keys) { 13 | const rest = {}; 14 | keys = new Set(keys); 15 | for (const k in props) 16 | if (!keys.has(k) && k[0] !== '$') 17 | rest[k] = props[k]; 18 | return rest; 19 | } 20 | 21 | let current_component; 22 | function set_current_component(component) { 23 | current_component = component; 24 | } 25 | 26 | const _boolean_attributes = [ 27 | 'allowfullscreen', 28 | 'allowpaymentrequest', 29 | 'async', 30 | 'autofocus', 31 | 'autoplay', 32 | 'checked', 33 | 'controls', 34 | 'default', 35 | 'defer', 36 | 'disabled', 37 | 'formnovalidate', 38 | 'hidden', 39 | 'inert', 40 | 'ismap', 41 | 'loop', 42 | 'multiple', 43 | 'muted', 44 | 'nomodule', 45 | 'novalidate', 46 | 'open', 47 | 'playsinline', 48 | 'readonly', 49 | 'required', 50 | 'reversed', 51 | 'selected' 52 | ]; 53 | /** 54 | * List of HTML boolean attributes (e.g. ``). 55 | * Source: https://html.spec.whatwg.org/multipage/indices.html 56 | */ 57 | const boolean_attributes = new Set([..._boolean_attributes]); 58 | 59 | const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; 60 | // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 61 | // https://infra.spec.whatwg.org/#noncharacter 62 | function spread(args, attrs_to_add) { 63 | const attributes = Object.assign({}, ...args); 64 | if (attrs_to_add) { 65 | const classes_to_add = attrs_to_add.classes; 66 | const styles_to_add = attrs_to_add.styles; 67 | if (classes_to_add) { 68 | if (attributes.class == null) { 69 | attributes.class = classes_to_add; 70 | } 71 | else { 72 | attributes.class += ' ' + classes_to_add; 73 | } 74 | } 75 | if (styles_to_add) { 76 | if (attributes.style == null) { 77 | attributes.style = style_object_to_string(styles_to_add); 78 | } 79 | else { 80 | attributes.style = style_object_to_string(merge_ssr_styles(attributes.style, styles_to_add)); 81 | } 82 | } 83 | } 84 | let str = ''; 85 | Object.keys(attributes).forEach(name => { 86 | if (invalid_attribute_name_character.test(name)) 87 | return; 88 | const value = attributes[name]; 89 | if (value === true) 90 | str += ' ' + name; 91 | else if (boolean_attributes.has(name.toLowerCase())) { 92 | if (value) 93 | str += ' ' + name; 94 | } 95 | else if (value != null) { 96 | str += ` ${name}="${value}"`; 97 | } 98 | }); 99 | return str; 100 | } 101 | function merge_ssr_styles(style_attribute, style_directive) { 102 | const style_object = {}; 103 | for (const individual_style of style_attribute.split(';')) { 104 | const colon_index = individual_style.indexOf(':'); 105 | const name = individual_style.slice(0, colon_index).trim(); 106 | const value = individual_style.slice(colon_index + 1).trim(); 107 | if (!name) 108 | continue; 109 | style_object[name] = value; 110 | } 111 | for (const name in style_directive) { 112 | const value = style_directive[name]; 113 | if (value) { 114 | style_object[name] = value; 115 | } 116 | else { 117 | delete style_object[name]; 118 | } 119 | } 120 | return style_object; 121 | } 122 | const ATTR_REGEX = /[&"]/g; 123 | const CONTENT_REGEX = /[&<]/g; 124 | /** 125 | * Note: this method is performance sensitive and has been optimized 126 | * https://github.com/sveltejs/svelte/pull/5701 127 | */ 128 | function escape(value, is_attr = false) { 129 | const str = String(value); 130 | const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; 131 | pattern.lastIndex = 0; 132 | let escaped = ''; 133 | let last = 0; 134 | while (pattern.test(str)) { 135 | const i = pattern.lastIndex - 1; 136 | const ch = str[i]; 137 | escaped += str.substring(last, i) + (ch === '&' ? '&' : (ch === '"' ? '"' : '<')); 138 | last = i + 1; 139 | } 140 | return escaped + str.substring(last); 141 | } 142 | function escape_attribute_value(value) { 143 | // keep booleans, null, and undefined for the sake of `spread` 144 | const should_escape = typeof value === 'string' || (value && typeof value === 'object'); 145 | return should_escape ? escape(value, true) : value; 146 | } 147 | function escape_object(obj) { 148 | const result = {}; 149 | for (const key in obj) { 150 | result[key] = escape_attribute_value(obj[key]); 151 | } 152 | return result; 153 | } 154 | function validate_component(component, name) { 155 | if (!component || !component.$$render) { 156 | if (name === 'svelte:component') 157 | name += ' this={...}'; 158 | throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <${name}>.`); 159 | } 160 | return component; 161 | } 162 | let on_destroy; 163 | function create_ssr_component(fn) { 164 | function $$render(result, props, bindings, slots, context) { 165 | const parent_component = current_component; 166 | const $$ = { 167 | on_destroy, 168 | context: new Map(context || (parent_component ? parent_component.$$.context : [])), 169 | // these will be immediately discarded 170 | on_mount: [], 171 | before_update: [], 172 | after_update: [], 173 | callbacks: blank_object() 174 | }; 175 | set_current_component({ $$ }); 176 | const html = fn(result, props, bindings, slots); 177 | set_current_component(parent_component); 178 | return html; 179 | } 180 | return { 181 | render: (props = {}, { $$slots = {}, context = new Map() } = {}) => { 182 | on_destroy = []; 183 | const result = { title: '', head: '', css: new Set() }; 184 | const html = $$render(result, props, {}, $$slots, context); 185 | run_all(on_destroy); 186 | return { 187 | html, 188 | css: { 189 | code: Array.from(result.css).map(css => css.code).join('\n'), 190 | map: null // TODO 191 | }, 192 | head: result.title + result.head 193 | }; 194 | }, 195 | $$render 196 | }; 197 | } 198 | function add_attribute(name, value, boolean) { 199 | if (value == null || (boolean && !value)) 200 | return ''; 201 | const assignment = (boolean && value === true) ? '' : `="${escape(value, true)}"`; 202 | return ` ${name}${assignment}`; 203 | } 204 | function style_object_to_string(style_object) { 205 | return Object.keys(style_object) 206 | .filter(key => style_object[key]) 207 | .map(key => `${key}: ${escape_attribute_value(style_object[key])};`) 208 | .join(' '); 209 | } 210 | 211 | // Get CSS class list from a props object 212 | function classList(props) { 213 | const { 214 | beat, 215 | fade, 216 | beatFade, 217 | bounce, 218 | shake, 219 | flash, 220 | spin, 221 | spinPulse, 222 | spinReverse, 223 | pulse, 224 | fixedWidth, 225 | inverse, 226 | border, 227 | listItem, 228 | flip, 229 | size, 230 | rotation, 231 | pull 232 | } = props; 233 | 234 | // map of CSS class names to properties 235 | const classes = { 236 | 'fa-beat': beat, 237 | 'fa-fade': fade, 238 | 'fa-beat-fade': beatFade, 239 | 'fa-bounce': bounce, 240 | 'fa-shake': shake, 241 | 'fa-flash': flash, 242 | 'fa-spin': spin, 243 | 'fa-spin-reverse': spinReverse, 244 | 'fa-spin-pulse': spinPulse, 245 | 'fa-pulse': pulse, 246 | 'fa-fw': fixedWidth, 247 | 'fa-inverse': inverse, 248 | 'fa-border': border, 249 | 'fa-li': listItem, 250 | 'fa-flip': flip === true, 251 | 'fa-flip-horizontal': flip === 'horizontal' || flip === 'both', 252 | 'fa-flip-vertical': flip === 'vertical' || flip === 'both', 253 | [`fa-${size}`]: typeof size !== 'undefined' && size !== null, 254 | [`fa-rotate-${rotation}`]: 255 | typeof rotation !== 'undefined' && rotation !== null && rotation !== 0, 256 | [`fa-pull-${pull}`]: typeof pull !== 'undefined' && pull !== null, 257 | 'fa-swap-opacity': props.swapOpacity 258 | }; 259 | 260 | // map over all the keys in the classes object 261 | // return an array of the keys where the value for the key is not null 262 | return Object.keys(classes) 263 | .map(key => (classes[key] ? key : null)) 264 | .filter(key => key) 265 | } 266 | 267 | // Camelize taken from humps 268 | // humps is copyright © 2012+ Dom Christie 269 | // Released under the MIT license. 270 | 271 | // Performant way to determine if object coerces to a number 272 | function _isNumerical(obj) { 273 | obj = obj - 0; 274 | 275 | // eslint-disable-next-line no-self-compare 276 | return obj === obj 277 | } 278 | 279 | function camelize(string) { 280 | if (_isNumerical(string)) { 281 | return string 282 | } 283 | 284 | // eslint-disable-next-line no-useless-escape 285 | string = string.replace(/[\-_\s]+(.)?/g, function(match, chr) { 286 | return chr ? chr.toUpperCase() : '' 287 | }); 288 | 289 | // Ensure 1st char is always lowercase 290 | return string.substr(0, 1).toLowerCase() + string.substr(1) 291 | } 292 | 293 | function styleToString(style) { 294 | if (typeof style === 'string') { 295 | return style 296 | } 297 | 298 | return Object.keys(style).reduce((acc, key) => ( 299 | acc + key.split(/(?=[A-Z])/).join('-').toLowerCase() + ':' + style[key] + ';' 300 | ), '') 301 | } 302 | 303 | function convert(createElement, element, extraProps = {}) { 304 | if (typeof element === 'string') { 305 | return element 306 | } 307 | 308 | const children = (element.children || []).map((child) => { 309 | return convert(createElement, child) 310 | }); 311 | 312 | /* eslint-disable dot-notation */ 313 | const mixins = Object.keys(element.attributes || {}).reduce( 314 | (acc, key) => { 315 | const val = element.attributes[key]; 316 | 317 | if (key === 'style') { 318 | acc.attrs['style'] = styleToString(val); 319 | } else { 320 | if (key.indexOf('aria-') === 0 || key.indexOf('data-') === 0) { 321 | acc.attrs[key.toLowerCase()] = val; 322 | } else { 323 | acc.attrs[camelize(key)] = val; 324 | } 325 | } 326 | 327 | return acc 328 | }, 329 | { attrs: {} } 330 | ); 331 | 332 | /* eslint-enable */ 333 | 334 | return createElement(element.tag, { ...mixins.attrs }, children) 335 | } 336 | 337 | let PRODUCTION = false; 338 | 339 | try { 340 | PRODUCTION = process.env.NODE_ENV === 'production'; 341 | } catch (e) {} 342 | 343 | function log(...args) { 344 | if (!PRODUCTION && console && typeof console.error === 'function') { 345 | console.error(...args); 346 | } 347 | } 348 | 349 | // Normalize icon arguments 350 | function normalizeIconArgs(icon) { 351 | // this has everything that it needs to be rendered which means it was probably imported 352 | // directly from an icon svg package 353 | if (icon && typeof icon === 'object' && icon.prefix && icon.iconName && icon.icon) { 354 | return icon 355 | } 356 | 357 | if (parse.icon) { 358 | return parse.icon(icon) 359 | } 360 | 361 | // if the icon is null, there's nothing to do 362 | if (icon === null) { 363 | return null 364 | } 365 | 366 | // if the icon is an object and has a prefix and an icon name, return it 367 | if (icon && typeof icon === 'object' && icon.prefix && icon.iconName) { 368 | return icon 369 | } 370 | 371 | // if it's an array with length of two 372 | if (Array.isArray(icon) && icon.length === 2) { 373 | // use the first item as prefix, second as icon name 374 | return { prefix: icon[0], iconName: icon[1] } 375 | } 376 | 377 | // if it's a string, use it as the icon name 378 | if (typeof icon === 'string') { 379 | return { prefix: 'fas', iconName: icon } 380 | } 381 | } 382 | 383 | // creates an object with a key of key 384 | // and a value of value 385 | // if certain conditions are met 386 | function objectWithKey(key, value) { 387 | // if the value is a non-empty array 388 | // or it's not an array but it is truthy 389 | // then create the object with the key and the value 390 | // if not, return an empty array 391 | return (Array.isArray(value) && value.length > 0) || 392 | (!Array.isArray(value) && value) 393 | ? { [key]: value } 394 | : {} 395 | } 396 | 397 | /* src/components/SvgElement.svelte generated by Svelte v3.59.2 */ 398 | 399 | const SvgElement = create_ssr_component(($$result, $$props, $$bindings, slots) => { 400 | let { tag } = $$props; 401 | let { props } = $$props; 402 | let { children } = $$props; 403 | let { style = null } = $$props; 404 | let { ref = null } = $$props; 405 | 406 | if (tag !== 'svg') { 407 | throw new Error('SvgElement requires a tag of "svg"'); 408 | } 409 | 410 | function processChildren(children) { 411 | return children?.reduce( 412 | (acc, child) => { 413 | return acc + (child.tag ? generateMarkup(child) : child); 414 | }, 415 | '' 416 | ) || ''; 417 | } 418 | 419 | function generateMarkup({ tag, props, children }) { 420 | // Generate a string setting key = value for each prop 421 | const attributes = Object.keys(props).map(key => `${key}="${props[key]}"`).join(' '); 422 | 423 | return `<${tag} ${attributes}>${processChildren(children)}`; 424 | } 425 | 426 | const markup = processChildren(children); 427 | const elementStyle = (props?.style) ? `${props.style}${style || ''}` : style; 428 | const elementProps = { ...props, style: elementStyle }; 429 | if ($$props.tag === void 0 && $$bindings.tag && tag !== void 0) $$bindings.tag(tag); 430 | if ($$props.props === void 0 && $$bindings.props && props !== void 0) $$bindings.props(props); 431 | if ($$props.children === void 0 && $$bindings.children && children !== void 0) $$bindings.children(children); 432 | if ($$props.style === void 0 && $$bindings.style && style !== void 0) $$bindings.style(style); 433 | if ($$props.ref === void 0 && $$bindings.ref && ref !== void 0) $$bindings.ref(ref); 434 | return `${markup}`; 435 | }); 436 | 437 | /* src/components/FontAwesomeIcon.svelte generated by Svelte v3.59.2 */ 438 | 439 | const FontAwesomeIcon = create_ssr_component(($$result, $$props, $$bindings, slots) => { 440 | let $$restProps = compute_rest_props($$props, [ 441 | "border","mask","maskId","fixedWidth","inverse","flip","icon","listItem","pull","pulse","rotation","size","spin","spinPulse","spinReverse","beat","fade","beatFade","bounce","shake","symbol","title","titleId","transform","swapOpacity","ref","style" 442 | ]); 443 | 444 | let { border = false } = $$props; 445 | let { mask = null } = $$props; 446 | let { maskId = null } = $$props; 447 | let { fixedWidth = false } = $$props; 448 | let { inverse = false } = $$props; 449 | let { flip = false } = $$props; 450 | let { icon: icon$1 = null } = $$props; 451 | let { listItem = false } = $$props; 452 | let { pull = null } = $$props; 453 | let { pulse = false } = $$props; 454 | let { rotation = null } = $$props; 455 | let { size = null } = $$props; 456 | let { spin = false } = $$props; 457 | let { spinPulse = false } = $$props; 458 | let { spinReverse = false } = $$props; 459 | let { beat = false } = $$props; 460 | let { fade = false } = $$props; 461 | let { beatFade = false } = $$props; 462 | let { bounce = false } = $$props; 463 | let { shake = false } = $$props; 464 | let { symbol = false } = $$props; 465 | let { title = '' } = $$props; 466 | let { titleId = null } = $$props; 467 | let { transform = null } = $$props; 468 | let { swapOpacity = false } = $$props; 469 | let { ref = null } = $$props; 470 | let { style = null } = $$props; 471 | const iconLookup = normalizeIconArgs(icon$1); 472 | const classes = objectWithKey('classes', [...classList($$props), ...($$props.class || '').split(' ')]); 473 | 474 | const transformObj = objectWithKey('transform', typeof transform === 'string' 475 | ? parse.transform(transform) 476 | : transform); 477 | 478 | const maskObj = objectWithKey('mask', normalizeIconArgs(mask)); 479 | 480 | const renderedIcon = icon(iconLookup, { 481 | ...classes, 482 | ...transformObj, 483 | ...maskObj, 484 | symbol, 485 | title, 486 | titleId, 487 | maskId 488 | }); 489 | 490 | let result = null; 491 | 492 | if (!renderedIcon) { 493 | log('Could not find icon', iconLookup); 494 | } else { 495 | const { abstract } = renderedIcon; 496 | 497 | result = convert( 498 | (tag, props, children) => { 499 | return { tag, props, children }; 500 | }, 501 | abstract[0], 502 | $$restProps 503 | ); 504 | } 505 | 506 | if ($$props.border === void 0 && $$bindings.border && border !== void 0) $$bindings.border(border); 507 | if ($$props.mask === void 0 && $$bindings.mask && mask !== void 0) $$bindings.mask(mask); 508 | if ($$props.maskId === void 0 && $$bindings.maskId && maskId !== void 0) $$bindings.maskId(maskId); 509 | if ($$props.fixedWidth === void 0 && $$bindings.fixedWidth && fixedWidth !== void 0) $$bindings.fixedWidth(fixedWidth); 510 | if ($$props.inverse === void 0 && $$bindings.inverse && inverse !== void 0) $$bindings.inverse(inverse); 511 | if ($$props.flip === void 0 && $$bindings.flip && flip !== void 0) $$bindings.flip(flip); 512 | if ($$props.icon === void 0 && $$bindings.icon && icon$1 !== void 0) $$bindings.icon(icon$1); 513 | if ($$props.listItem === void 0 && $$bindings.listItem && listItem !== void 0) $$bindings.listItem(listItem); 514 | if ($$props.pull === void 0 && $$bindings.pull && pull !== void 0) $$bindings.pull(pull); 515 | if ($$props.pulse === void 0 && $$bindings.pulse && pulse !== void 0) $$bindings.pulse(pulse); 516 | if ($$props.rotation === void 0 && $$bindings.rotation && rotation !== void 0) $$bindings.rotation(rotation); 517 | if ($$props.size === void 0 && $$bindings.size && size !== void 0) $$bindings.size(size); 518 | if ($$props.spin === void 0 && $$bindings.spin && spin !== void 0) $$bindings.spin(spin); 519 | if ($$props.spinPulse === void 0 && $$bindings.spinPulse && spinPulse !== void 0) $$bindings.spinPulse(spinPulse); 520 | if ($$props.spinReverse === void 0 && $$bindings.spinReverse && spinReverse !== void 0) $$bindings.spinReverse(spinReverse); 521 | if ($$props.beat === void 0 && $$bindings.beat && beat !== void 0) $$bindings.beat(beat); 522 | if ($$props.fade === void 0 && $$bindings.fade && fade !== void 0) $$bindings.fade(fade); 523 | if ($$props.beatFade === void 0 && $$bindings.beatFade && beatFade !== void 0) $$bindings.beatFade(beatFade); 524 | if ($$props.bounce === void 0 && $$bindings.bounce && bounce !== void 0) $$bindings.bounce(bounce); 525 | if ($$props.shake === void 0 && $$bindings.shake && shake !== void 0) $$bindings.shake(shake); 526 | if ($$props.symbol === void 0 && $$bindings.symbol && symbol !== void 0) $$bindings.symbol(symbol); 527 | if ($$props.title === void 0 && $$bindings.title && title !== void 0) $$bindings.title(title); 528 | if ($$props.titleId === void 0 && $$bindings.titleId && titleId !== void 0) $$bindings.titleId(titleId); 529 | if ($$props.transform === void 0 && $$bindings.transform && transform !== void 0) $$bindings.transform(transform); 530 | if ($$props.swapOpacity === void 0 && $$bindings.swapOpacity && swapOpacity !== void 0) $$bindings.swapOpacity(swapOpacity); 531 | if ($$props.ref === void 0 && $$bindings.ref && ref !== void 0) $$bindings.ref(ref); 532 | if ($$props.style === void 0 && $$bindings.style && style !== void 0) $$bindings.style(style); 533 | let $$settled; 534 | let $$rendered; 535 | 536 | do { 537 | $$settled = true; 538 | 539 | $$rendered = `${result 540 | ? `${validate_component(SvgElement, "SvgElement").$$render( 541 | $$result, 542 | Object.assign({}, result, { style }, { ref }), 543 | { 544 | ref: $$value => { 545 | ref = $$value; 546 | $$settled = false; 547 | } 548 | }, 549 | {} 550 | )}` 551 | : ``}`; 552 | } while (!$$settled); 553 | 554 | return $$rendered; 555 | }); 556 | 557 | export { FontAwesomeIcon }; 558 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@fortawesome/fontawesome-svg-core')) : 3 | typeof define === 'function' && define.amd ? define(['exports', '@fortawesome/fontawesome-svg-core'], factory) : 4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["svelte-fontawesome"] = {}, global.FontAwesome)); 5 | })(this, (function (exports, fontawesomeSvgCore) { 'use strict'; 6 | 7 | function run(fn) { 8 | return fn(); 9 | } 10 | function blank_object() { 11 | return Object.create(null); 12 | } 13 | function run_all(fns) { 14 | fns.forEach(run); 15 | } 16 | function compute_rest_props(props, keys) { 17 | const rest = {}; 18 | keys = new Set(keys); 19 | for (const k in props) 20 | if (!keys.has(k) && k[0] !== '$') 21 | rest[k] = props[k]; 22 | return rest; 23 | } 24 | 25 | let current_component; 26 | function set_current_component(component) { 27 | current_component = component; 28 | } 29 | 30 | const _boolean_attributes = [ 31 | 'allowfullscreen', 32 | 'allowpaymentrequest', 33 | 'async', 34 | 'autofocus', 35 | 'autoplay', 36 | 'checked', 37 | 'controls', 38 | 'default', 39 | 'defer', 40 | 'disabled', 41 | 'formnovalidate', 42 | 'hidden', 43 | 'inert', 44 | 'ismap', 45 | 'loop', 46 | 'multiple', 47 | 'muted', 48 | 'nomodule', 49 | 'novalidate', 50 | 'open', 51 | 'playsinline', 52 | 'readonly', 53 | 'required', 54 | 'reversed', 55 | 'selected' 56 | ]; 57 | /** 58 | * List of HTML boolean attributes (e.g. ``). 59 | * Source: https://html.spec.whatwg.org/multipage/indices.html 60 | */ 61 | const boolean_attributes = new Set([..._boolean_attributes]); 62 | 63 | const invalid_attribute_name_character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u; 64 | // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 65 | // https://infra.spec.whatwg.org/#noncharacter 66 | function spread(args, attrs_to_add) { 67 | const attributes = Object.assign({}, ...args); 68 | if (attrs_to_add) { 69 | const classes_to_add = attrs_to_add.classes; 70 | const styles_to_add = attrs_to_add.styles; 71 | if (classes_to_add) { 72 | if (attributes.class == null) { 73 | attributes.class = classes_to_add; 74 | } 75 | else { 76 | attributes.class += ' ' + classes_to_add; 77 | } 78 | } 79 | if (styles_to_add) { 80 | if (attributes.style == null) { 81 | attributes.style = style_object_to_string(styles_to_add); 82 | } 83 | else { 84 | attributes.style = style_object_to_string(merge_ssr_styles(attributes.style, styles_to_add)); 85 | } 86 | } 87 | } 88 | let str = ''; 89 | Object.keys(attributes).forEach(name => { 90 | if (invalid_attribute_name_character.test(name)) 91 | return; 92 | const value = attributes[name]; 93 | if (value === true) 94 | str += ' ' + name; 95 | else if (boolean_attributes.has(name.toLowerCase())) { 96 | if (value) 97 | str += ' ' + name; 98 | } 99 | else if (value != null) { 100 | str += ` ${name}="${value}"`; 101 | } 102 | }); 103 | return str; 104 | } 105 | function merge_ssr_styles(style_attribute, style_directive) { 106 | const style_object = {}; 107 | for (const individual_style of style_attribute.split(';')) { 108 | const colon_index = individual_style.indexOf(':'); 109 | const name = individual_style.slice(0, colon_index).trim(); 110 | const value = individual_style.slice(colon_index + 1).trim(); 111 | if (!name) 112 | continue; 113 | style_object[name] = value; 114 | } 115 | for (const name in style_directive) { 116 | const value = style_directive[name]; 117 | if (value) { 118 | style_object[name] = value; 119 | } 120 | else { 121 | delete style_object[name]; 122 | } 123 | } 124 | return style_object; 125 | } 126 | const ATTR_REGEX = /[&"]/g; 127 | const CONTENT_REGEX = /[&<]/g; 128 | /** 129 | * Note: this method is performance sensitive and has been optimized 130 | * https://github.com/sveltejs/svelte/pull/5701 131 | */ 132 | function escape(value, is_attr = false) { 133 | const str = String(value); 134 | const pattern = is_attr ? ATTR_REGEX : CONTENT_REGEX; 135 | pattern.lastIndex = 0; 136 | let escaped = ''; 137 | let last = 0; 138 | while (pattern.test(str)) { 139 | const i = pattern.lastIndex - 1; 140 | const ch = str[i]; 141 | escaped += str.substring(last, i) + (ch === '&' ? '&' : (ch === '"' ? '"' : '<')); 142 | last = i + 1; 143 | } 144 | return escaped + str.substring(last); 145 | } 146 | function escape_attribute_value(value) { 147 | // keep booleans, null, and undefined for the sake of `spread` 148 | const should_escape = typeof value === 'string' || (value && typeof value === 'object'); 149 | return should_escape ? escape(value, true) : value; 150 | } 151 | function escape_object(obj) { 152 | const result = {}; 153 | for (const key in obj) { 154 | result[key] = escape_attribute_value(obj[key]); 155 | } 156 | return result; 157 | } 158 | function validate_component(component, name) { 159 | if (!component || !component.$$render) { 160 | if (name === 'svelte:component') 161 | name += ' this={...}'; 162 | throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a <${name}>.`); 163 | } 164 | return component; 165 | } 166 | let on_destroy; 167 | function create_ssr_component(fn) { 168 | function $$render(result, props, bindings, slots, context) { 169 | const parent_component = current_component; 170 | const $$ = { 171 | on_destroy, 172 | context: new Map(context || (parent_component ? parent_component.$$.context : [])), 173 | // these will be immediately discarded 174 | on_mount: [], 175 | before_update: [], 176 | after_update: [], 177 | callbacks: blank_object() 178 | }; 179 | set_current_component({ $$ }); 180 | const html = fn(result, props, bindings, slots); 181 | set_current_component(parent_component); 182 | return html; 183 | } 184 | return { 185 | render: (props = {}, { $$slots = {}, context = new Map() } = {}) => { 186 | on_destroy = []; 187 | const result = { title: '', head: '', css: new Set() }; 188 | const html = $$render(result, props, {}, $$slots, context); 189 | run_all(on_destroy); 190 | return { 191 | html, 192 | css: { 193 | code: Array.from(result.css).map(css => css.code).join('\n'), 194 | map: null // TODO 195 | }, 196 | head: result.title + result.head 197 | }; 198 | }, 199 | $$render 200 | }; 201 | } 202 | function add_attribute(name, value, boolean) { 203 | if (value == null || (boolean && !value)) 204 | return ''; 205 | const assignment = (boolean && value === true) ? '' : `="${escape(value, true)}"`; 206 | return ` ${name}${assignment}`; 207 | } 208 | function style_object_to_string(style_object) { 209 | return Object.keys(style_object) 210 | .filter(key => style_object[key]) 211 | .map(key => `${key}: ${escape_attribute_value(style_object[key])};`) 212 | .join(' '); 213 | } 214 | 215 | // Get CSS class list from a props object 216 | function classList(props) { 217 | const { 218 | beat, 219 | fade, 220 | beatFade, 221 | bounce, 222 | shake, 223 | flash, 224 | spin, 225 | spinPulse, 226 | spinReverse, 227 | pulse, 228 | fixedWidth, 229 | inverse, 230 | border, 231 | listItem, 232 | flip, 233 | size, 234 | rotation, 235 | pull 236 | } = props; 237 | 238 | // map of CSS class names to properties 239 | const classes = { 240 | 'fa-beat': beat, 241 | 'fa-fade': fade, 242 | 'fa-beat-fade': beatFade, 243 | 'fa-bounce': bounce, 244 | 'fa-shake': shake, 245 | 'fa-flash': flash, 246 | 'fa-spin': spin, 247 | 'fa-spin-reverse': spinReverse, 248 | 'fa-spin-pulse': spinPulse, 249 | 'fa-pulse': pulse, 250 | 'fa-fw': fixedWidth, 251 | 'fa-inverse': inverse, 252 | 'fa-border': border, 253 | 'fa-li': listItem, 254 | 'fa-flip': flip === true, 255 | 'fa-flip-horizontal': flip === 'horizontal' || flip === 'both', 256 | 'fa-flip-vertical': flip === 'vertical' || flip === 'both', 257 | [`fa-${size}`]: typeof size !== 'undefined' && size !== null, 258 | [`fa-rotate-${rotation}`]: 259 | typeof rotation !== 'undefined' && rotation !== null && rotation !== 0, 260 | [`fa-pull-${pull}`]: typeof pull !== 'undefined' && pull !== null, 261 | 'fa-swap-opacity': props.swapOpacity 262 | }; 263 | 264 | // map over all the keys in the classes object 265 | // return an array of the keys where the value for the key is not null 266 | return Object.keys(classes) 267 | .map(key => (classes[key] ? key : null)) 268 | .filter(key => key) 269 | } 270 | 271 | // Camelize taken from humps 272 | // humps is copyright © 2012+ Dom Christie 273 | // Released under the MIT license. 274 | 275 | // Performant way to determine if object coerces to a number 276 | function _isNumerical(obj) { 277 | obj = obj - 0; 278 | 279 | // eslint-disable-next-line no-self-compare 280 | return obj === obj 281 | } 282 | 283 | function camelize(string) { 284 | if (_isNumerical(string)) { 285 | return string 286 | } 287 | 288 | // eslint-disable-next-line no-useless-escape 289 | string = string.replace(/[\-_\s]+(.)?/g, function(match, chr) { 290 | return chr ? chr.toUpperCase() : '' 291 | }); 292 | 293 | // Ensure 1st char is always lowercase 294 | return string.substr(0, 1).toLowerCase() + string.substr(1) 295 | } 296 | 297 | function styleToString(style) { 298 | if (typeof style === 'string') { 299 | return style 300 | } 301 | 302 | return Object.keys(style).reduce((acc, key) => ( 303 | acc + key.split(/(?=[A-Z])/).join('-').toLowerCase() + ':' + style[key] + ';' 304 | ), '') 305 | } 306 | 307 | function convert(createElement, element, extraProps = {}) { 308 | if (typeof element === 'string') { 309 | return element 310 | } 311 | 312 | const children = (element.children || []).map((child) => { 313 | return convert(createElement, child) 314 | }); 315 | 316 | /* eslint-disable dot-notation */ 317 | const mixins = Object.keys(element.attributes || {}).reduce( 318 | (acc, key) => { 319 | const val = element.attributes[key]; 320 | 321 | if (key === 'style') { 322 | acc.attrs['style'] = styleToString(val); 323 | } else { 324 | if (key.indexOf('aria-') === 0 || key.indexOf('data-') === 0) { 325 | acc.attrs[key.toLowerCase()] = val; 326 | } else { 327 | acc.attrs[camelize(key)] = val; 328 | } 329 | } 330 | 331 | return acc 332 | }, 333 | { attrs: {} } 334 | ); 335 | 336 | /* eslint-enable */ 337 | 338 | return createElement(element.tag, { ...mixins.attrs }, children) 339 | } 340 | 341 | let PRODUCTION = false; 342 | 343 | try { 344 | PRODUCTION = process.env.NODE_ENV === 'production'; 345 | } catch (e) {} 346 | 347 | function log(...args) { 348 | if (!PRODUCTION && console && typeof console.error === 'function') { 349 | console.error(...args); 350 | } 351 | } 352 | 353 | // Normalize icon arguments 354 | function normalizeIconArgs(icon) { 355 | // this has everything that it needs to be rendered which means it was probably imported 356 | // directly from an icon svg package 357 | if (icon && typeof icon === 'object' && icon.prefix && icon.iconName && icon.icon) { 358 | return icon 359 | } 360 | 361 | if (fontawesomeSvgCore.parse.icon) { 362 | return fontawesomeSvgCore.parse.icon(icon) 363 | } 364 | 365 | // if the icon is null, there's nothing to do 366 | if (icon === null) { 367 | return null 368 | } 369 | 370 | // if the icon is an object and has a prefix and an icon name, return it 371 | if (icon && typeof icon === 'object' && icon.prefix && icon.iconName) { 372 | return icon 373 | } 374 | 375 | // if it's an array with length of two 376 | if (Array.isArray(icon) && icon.length === 2) { 377 | // use the first item as prefix, second as icon name 378 | return { prefix: icon[0], iconName: icon[1] } 379 | } 380 | 381 | // if it's a string, use it as the icon name 382 | if (typeof icon === 'string') { 383 | return { prefix: 'fas', iconName: icon } 384 | } 385 | } 386 | 387 | // creates an object with a key of key 388 | // and a value of value 389 | // if certain conditions are met 390 | function objectWithKey(key, value) { 391 | // if the value is a non-empty array 392 | // or it's not an array but it is truthy 393 | // then create the object with the key and the value 394 | // if not, return an empty array 395 | return (Array.isArray(value) && value.length > 0) || 396 | (!Array.isArray(value) && value) 397 | ? { [key]: value } 398 | : {} 399 | } 400 | 401 | /* src/components/SvgElement.svelte generated by Svelte v3.59.2 */ 402 | 403 | const SvgElement = create_ssr_component(($$result, $$props, $$bindings, slots) => { 404 | let { tag } = $$props; 405 | let { props } = $$props; 406 | let { children } = $$props; 407 | let { style = null } = $$props; 408 | let { ref = null } = $$props; 409 | 410 | if (tag !== 'svg') { 411 | throw new Error('SvgElement requires a tag of "svg"'); 412 | } 413 | 414 | function processChildren(children) { 415 | return children?.reduce( 416 | (acc, child) => { 417 | return acc + (child.tag ? generateMarkup(child) : child); 418 | }, 419 | '' 420 | ) || ''; 421 | } 422 | 423 | function generateMarkup({ tag, props, children }) { 424 | // Generate a string setting key = value for each prop 425 | const attributes = Object.keys(props).map(key => `${key}="${props[key]}"`).join(' '); 426 | 427 | return `<${tag} ${attributes}>${processChildren(children)}`; 428 | } 429 | 430 | const markup = processChildren(children); 431 | const elementStyle = (props?.style) ? `${props.style}${style || ''}` : style; 432 | const elementProps = { ...props, style: elementStyle }; 433 | if ($$props.tag === void 0 && $$bindings.tag && tag !== void 0) $$bindings.tag(tag); 434 | if ($$props.props === void 0 && $$bindings.props && props !== void 0) $$bindings.props(props); 435 | if ($$props.children === void 0 && $$bindings.children && children !== void 0) $$bindings.children(children); 436 | if ($$props.style === void 0 && $$bindings.style && style !== void 0) $$bindings.style(style); 437 | if ($$props.ref === void 0 && $$bindings.ref && ref !== void 0) $$bindings.ref(ref); 438 | return `${markup}`; 439 | }); 440 | 441 | /* src/components/FontAwesomeIcon.svelte generated by Svelte v3.59.2 */ 442 | 443 | const FontAwesomeIcon = create_ssr_component(($$result, $$props, $$bindings, slots) => { 444 | let $$restProps = compute_rest_props($$props, [ 445 | "border","mask","maskId","fixedWidth","inverse","flip","icon","listItem","pull","pulse","rotation","size","spin","spinPulse","spinReverse","beat","fade","beatFade","bounce","shake","symbol","title","titleId","transform","swapOpacity","ref","style" 446 | ]); 447 | 448 | let { border = false } = $$props; 449 | let { mask = null } = $$props; 450 | let { maskId = null } = $$props; 451 | let { fixedWidth = false } = $$props; 452 | let { inverse = false } = $$props; 453 | let { flip = false } = $$props; 454 | let { icon = null } = $$props; 455 | let { listItem = false } = $$props; 456 | let { pull = null } = $$props; 457 | let { pulse = false } = $$props; 458 | let { rotation = null } = $$props; 459 | let { size = null } = $$props; 460 | let { spin = false } = $$props; 461 | let { spinPulse = false } = $$props; 462 | let { spinReverse = false } = $$props; 463 | let { beat = false } = $$props; 464 | let { fade = false } = $$props; 465 | let { beatFade = false } = $$props; 466 | let { bounce = false } = $$props; 467 | let { shake = false } = $$props; 468 | let { symbol = false } = $$props; 469 | let { title = '' } = $$props; 470 | let { titleId = null } = $$props; 471 | let { transform = null } = $$props; 472 | let { swapOpacity = false } = $$props; 473 | let { ref = null } = $$props; 474 | let { style = null } = $$props; 475 | const iconLookup = normalizeIconArgs(icon); 476 | const classes = objectWithKey('classes', [...classList($$props), ...($$props.class || '').split(' ')]); 477 | 478 | const transformObj = objectWithKey('transform', typeof transform === 'string' 479 | ? fontawesomeSvgCore.parse.transform(transform) 480 | : transform); 481 | 482 | const maskObj = objectWithKey('mask', normalizeIconArgs(mask)); 483 | 484 | const renderedIcon = fontawesomeSvgCore.icon(iconLookup, { 485 | ...classes, 486 | ...transformObj, 487 | ...maskObj, 488 | symbol, 489 | title, 490 | titleId, 491 | maskId 492 | }); 493 | 494 | let result = null; 495 | 496 | if (!renderedIcon) { 497 | log('Could not find icon', iconLookup); 498 | } else { 499 | const { abstract } = renderedIcon; 500 | 501 | result = convert( 502 | (tag, props, children) => { 503 | return { tag, props, children }; 504 | }, 505 | abstract[0], 506 | $$restProps 507 | ); 508 | } 509 | 510 | if ($$props.border === void 0 && $$bindings.border && border !== void 0) $$bindings.border(border); 511 | if ($$props.mask === void 0 && $$bindings.mask && mask !== void 0) $$bindings.mask(mask); 512 | if ($$props.maskId === void 0 && $$bindings.maskId && maskId !== void 0) $$bindings.maskId(maskId); 513 | if ($$props.fixedWidth === void 0 && $$bindings.fixedWidth && fixedWidth !== void 0) $$bindings.fixedWidth(fixedWidth); 514 | if ($$props.inverse === void 0 && $$bindings.inverse && inverse !== void 0) $$bindings.inverse(inverse); 515 | if ($$props.flip === void 0 && $$bindings.flip && flip !== void 0) $$bindings.flip(flip); 516 | if ($$props.icon === void 0 && $$bindings.icon && icon !== void 0) $$bindings.icon(icon); 517 | if ($$props.listItem === void 0 && $$bindings.listItem && listItem !== void 0) $$bindings.listItem(listItem); 518 | if ($$props.pull === void 0 && $$bindings.pull && pull !== void 0) $$bindings.pull(pull); 519 | if ($$props.pulse === void 0 && $$bindings.pulse && pulse !== void 0) $$bindings.pulse(pulse); 520 | if ($$props.rotation === void 0 && $$bindings.rotation && rotation !== void 0) $$bindings.rotation(rotation); 521 | if ($$props.size === void 0 && $$bindings.size && size !== void 0) $$bindings.size(size); 522 | if ($$props.spin === void 0 && $$bindings.spin && spin !== void 0) $$bindings.spin(spin); 523 | if ($$props.spinPulse === void 0 && $$bindings.spinPulse && spinPulse !== void 0) $$bindings.spinPulse(spinPulse); 524 | if ($$props.spinReverse === void 0 && $$bindings.spinReverse && spinReverse !== void 0) $$bindings.spinReverse(spinReverse); 525 | if ($$props.beat === void 0 && $$bindings.beat && beat !== void 0) $$bindings.beat(beat); 526 | if ($$props.fade === void 0 && $$bindings.fade && fade !== void 0) $$bindings.fade(fade); 527 | if ($$props.beatFade === void 0 && $$bindings.beatFade && beatFade !== void 0) $$bindings.beatFade(beatFade); 528 | if ($$props.bounce === void 0 && $$bindings.bounce && bounce !== void 0) $$bindings.bounce(bounce); 529 | if ($$props.shake === void 0 && $$bindings.shake && shake !== void 0) $$bindings.shake(shake); 530 | if ($$props.symbol === void 0 && $$bindings.symbol && symbol !== void 0) $$bindings.symbol(symbol); 531 | if ($$props.title === void 0 && $$bindings.title && title !== void 0) $$bindings.title(title); 532 | if ($$props.titleId === void 0 && $$bindings.titleId && titleId !== void 0) $$bindings.titleId(titleId); 533 | if ($$props.transform === void 0 && $$bindings.transform && transform !== void 0) $$bindings.transform(transform); 534 | if ($$props.swapOpacity === void 0 && $$bindings.swapOpacity && swapOpacity !== void 0) $$bindings.swapOpacity(swapOpacity); 535 | if ($$props.ref === void 0 && $$bindings.ref && ref !== void 0) $$bindings.ref(ref); 536 | if ($$props.style === void 0 && $$bindings.style && style !== void 0) $$bindings.style(style); 537 | let $$settled; 538 | let $$rendered; 539 | 540 | do { 541 | $$settled = true; 542 | 543 | $$rendered = `${result 544 | ? `${validate_component(SvgElement, "SvgElement").$$render( 545 | $$result, 546 | Object.assign({}, result, { style }, { ref }), 547 | { 548 | ref: $$value => { 549 | ref = $$value; 550 | $$settled = false; 551 | } 552 | }, 553 | {} 554 | )}` 555 | : ``}`; 556 | } while (!$$settled); 557 | 558 | return $$rendered; 559 | }); 560 | 561 | exports.FontAwesomeIcon = FontAwesomeIcon; 562 | 563 | Object.defineProperty(exports, '__esModule', { value: true }); 564 | 565 | })); 566 | -------------------------------------------------------------------------------- /examples/svelte-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "svelte-app", 9 | "version": "0.0.0", 10 | "devDependencies": { 11 | "@fortawesome/fontawesome-svg-core": "^7.0.0", 12 | "@fortawesome/free-brands-svg-icons": "^7.0.0", 13 | "@fortawesome/free-solid-svg-icons": "^7.0.0", 14 | "@fortawesome/svelte-fontawesome": "^0.2.0", 15 | "@sveltejs/vite-plugin-svelte": "^1.0.1", 16 | "svelte": "^3.49.0", 17 | "vite": "^3.0.0" 18 | } 19 | }, 20 | "node_modules/@esbuild/android-arm": { 21 | "version": "0.15.18", 22 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", 23 | "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", 24 | "cpu": [ 25 | "arm" 26 | ], 27 | "dev": true, 28 | "optional": true, 29 | "os": [ 30 | "android" 31 | ], 32 | "engines": { 33 | "node": ">=12" 34 | } 35 | }, 36 | "node_modules/@esbuild/linux-loong64": { 37 | "version": "0.15.18", 38 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", 39 | "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", 40 | "cpu": [ 41 | "loong64" 42 | ], 43 | "dev": true, 44 | "optional": true, 45 | "os": [ 46 | "linux" 47 | ], 48 | "engines": { 49 | "node": ">=12" 50 | } 51 | }, 52 | "node_modules/@fortawesome/fontawesome-common-types": { 53 | "version": "7.0.0", 54 | "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.0.0.tgz", 55 | "integrity": "sha512-PGMrIYXLGA5K8RWy8zwBkd4vFi4z7ubxtet6Yn13Plf6krRTwPbdlCwlcfmoX0R7B4Z643QvrtHmdQ5fNtfFCg==", 56 | "dev": true, 57 | "engines": { 58 | "node": ">=6" 59 | } 60 | }, 61 | "node_modules/@fortawesome/fontawesome-svg-core": { 62 | "version": "7.0.0", 63 | "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.0.0.tgz", 64 | "integrity": "sha512-obBEF+zd98r/KtKVW6A+8UGWeaOoyMpl6Q9P3FzHsOnsg742aXsl8v+H/zp09qSSu/a/Hxe9LNKzbBaQq1CEbA==", 65 | "dev": true, 66 | "dependencies": { 67 | "@fortawesome/fontawesome-common-types": "7.0.0" 68 | }, 69 | "engines": { 70 | "node": ">=6" 71 | } 72 | }, 73 | "node_modules/@fortawesome/free-brands-svg-icons": { 74 | "version": "7.0.0", 75 | "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-7.0.0.tgz", 76 | "integrity": "sha512-C8oY28gq/Qx/cHReJa2AunKJUHvUZDVoPlSTHtAvjriaNfi+5nugW4cx7yA/xN3f/nYkElw11gFBoJ2xUDDFgg==", 77 | "dev": true, 78 | "dependencies": { 79 | "@fortawesome/fontawesome-common-types": "7.0.0" 80 | }, 81 | "engines": { 82 | "node": ">=6" 83 | } 84 | }, 85 | "node_modules/@fortawesome/free-solid-svg-icons": { 86 | "version": "7.0.0", 87 | "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-7.0.0.tgz", 88 | "integrity": "sha512-njSLAllkOddYDCXgTFboXn54Oe5FcvpkWq+FoetOHR64PbN0608kM02Lze0xtISGpXgP+i26VyXRQA0Irh3Obw==", 89 | "dev": true, 90 | "dependencies": { 91 | "@fortawesome/fontawesome-common-types": "7.0.0" 92 | }, 93 | "engines": { 94 | "node": ">=6" 95 | } 96 | }, 97 | "node_modules/@fortawesome/svelte-fontawesome": { 98 | "version": "0.2.1", 99 | "resolved": "https://registry.npmjs.org/@fortawesome/svelte-fontawesome/-/svelte-fontawesome-0.2.1.tgz", 100 | "integrity": "sha512-GDGMow2poIHaT0y02EcMDAjWSy0OYbY0BLORDRp5eZBh8EckFyNvMjhTgWsTp4b/gyWrP9jNRYOXVaWAQFnK3g==", 101 | "dev": true, 102 | "peerDependencies": { 103 | "@fortawesome/fontawesome-svg-core": "~1 || ~6", 104 | "svelte": ">=3.x" 105 | } 106 | }, 107 | "node_modules/@sveltejs/vite-plugin-svelte": { 108 | "version": "1.4.0", 109 | "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.4.0.tgz", 110 | "integrity": "sha512-6QupI/jemMfK+yI2pMtJcu5iO2gtgTfcBdGwMZZt+lgbFELhszbDl6Qjh000HgAV8+XUA+8EY8DusOFk8WhOIg==", 111 | "dev": true, 112 | "dependencies": { 113 | "debug": "^4.3.4", 114 | "deepmerge": "^4.2.2", 115 | "kleur": "^4.1.5", 116 | "magic-string": "^0.26.7", 117 | "svelte-hmr": "^0.15.1", 118 | "vitefu": "^0.2.2" 119 | }, 120 | "engines": { 121 | "node": "^14.18.0 || >= 16" 122 | }, 123 | "peerDependencies": { 124 | "svelte": "^3.44.0", 125 | "vite": "^3.0.0" 126 | } 127 | }, 128 | "node_modules/debug": { 129 | "version": "4.3.4", 130 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 131 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 132 | "dev": true, 133 | "dependencies": { 134 | "ms": "2.1.2" 135 | }, 136 | "engines": { 137 | "node": ">=6.0" 138 | }, 139 | "peerDependenciesMeta": { 140 | "supports-color": { 141 | "optional": true 142 | } 143 | } 144 | }, 145 | "node_modules/deepmerge": { 146 | "version": "4.3.1", 147 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", 148 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", 149 | "dev": true, 150 | "engines": { 151 | "node": ">=0.10.0" 152 | } 153 | }, 154 | "node_modules/esbuild": { 155 | "version": "0.15.18", 156 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", 157 | "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", 158 | "dev": true, 159 | "hasInstallScript": true, 160 | "bin": { 161 | "esbuild": "bin/esbuild" 162 | }, 163 | "engines": { 164 | "node": ">=12" 165 | }, 166 | "optionalDependencies": { 167 | "@esbuild/android-arm": "0.15.18", 168 | "@esbuild/linux-loong64": "0.15.18", 169 | "esbuild-android-64": "0.15.18", 170 | "esbuild-android-arm64": "0.15.18", 171 | "esbuild-darwin-64": "0.15.18", 172 | "esbuild-darwin-arm64": "0.15.18", 173 | "esbuild-freebsd-64": "0.15.18", 174 | "esbuild-freebsd-arm64": "0.15.18", 175 | "esbuild-linux-32": "0.15.18", 176 | "esbuild-linux-64": "0.15.18", 177 | "esbuild-linux-arm": "0.15.18", 178 | "esbuild-linux-arm64": "0.15.18", 179 | "esbuild-linux-mips64le": "0.15.18", 180 | "esbuild-linux-ppc64le": "0.15.18", 181 | "esbuild-linux-riscv64": "0.15.18", 182 | "esbuild-linux-s390x": "0.15.18", 183 | "esbuild-netbsd-64": "0.15.18", 184 | "esbuild-openbsd-64": "0.15.18", 185 | "esbuild-sunos-64": "0.15.18", 186 | "esbuild-windows-32": "0.15.18", 187 | "esbuild-windows-64": "0.15.18", 188 | "esbuild-windows-arm64": "0.15.18" 189 | } 190 | }, 191 | "node_modules/esbuild-android-64": { 192 | "version": "0.15.18", 193 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", 194 | "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", 195 | "cpu": [ 196 | "x64" 197 | ], 198 | "dev": true, 199 | "optional": true, 200 | "os": [ 201 | "android" 202 | ], 203 | "engines": { 204 | "node": ">=12" 205 | } 206 | }, 207 | "node_modules/esbuild-android-arm64": { 208 | "version": "0.15.18", 209 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", 210 | "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", 211 | "cpu": [ 212 | "arm64" 213 | ], 214 | "dev": true, 215 | "optional": true, 216 | "os": [ 217 | "android" 218 | ], 219 | "engines": { 220 | "node": ">=12" 221 | } 222 | }, 223 | "node_modules/esbuild-darwin-64": { 224 | "version": "0.15.18", 225 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", 226 | "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", 227 | "cpu": [ 228 | "x64" 229 | ], 230 | "dev": true, 231 | "optional": true, 232 | "os": [ 233 | "darwin" 234 | ], 235 | "engines": { 236 | "node": ">=12" 237 | } 238 | }, 239 | "node_modules/esbuild-darwin-arm64": { 240 | "version": "0.15.18", 241 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", 242 | "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", 243 | "cpu": [ 244 | "arm64" 245 | ], 246 | "dev": true, 247 | "optional": true, 248 | "os": [ 249 | "darwin" 250 | ], 251 | "engines": { 252 | "node": ">=12" 253 | } 254 | }, 255 | "node_modules/esbuild-freebsd-64": { 256 | "version": "0.15.18", 257 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", 258 | "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", 259 | "cpu": [ 260 | "x64" 261 | ], 262 | "dev": true, 263 | "optional": true, 264 | "os": [ 265 | "freebsd" 266 | ], 267 | "engines": { 268 | "node": ">=12" 269 | } 270 | }, 271 | "node_modules/esbuild-freebsd-arm64": { 272 | "version": "0.15.18", 273 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", 274 | "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", 275 | "cpu": [ 276 | "arm64" 277 | ], 278 | "dev": true, 279 | "optional": true, 280 | "os": [ 281 | "freebsd" 282 | ], 283 | "engines": { 284 | "node": ">=12" 285 | } 286 | }, 287 | "node_modules/esbuild-linux-32": { 288 | "version": "0.15.18", 289 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", 290 | "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", 291 | "cpu": [ 292 | "ia32" 293 | ], 294 | "dev": true, 295 | "optional": true, 296 | "os": [ 297 | "linux" 298 | ], 299 | "engines": { 300 | "node": ">=12" 301 | } 302 | }, 303 | "node_modules/esbuild-linux-64": { 304 | "version": "0.15.18", 305 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", 306 | "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", 307 | "cpu": [ 308 | "x64" 309 | ], 310 | "dev": true, 311 | "optional": true, 312 | "os": [ 313 | "linux" 314 | ], 315 | "engines": { 316 | "node": ">=12" 317 | } 318 | }, 319 | "node_modules/esbuild-linux-arm": { 320 | "version": "0.15.18", 321 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", 322 | "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", 323 | "cpu": [ 324 | "arm" 325 | ], 326 | "dev": true, 327 | "optional": true, 328 | "os": [ 329 | "linux" 330 | ], 331 | "engines": { 332 | "node": ">=12" 333 | } 334 | }, 335 | "node_modules/esbuild-linux-arm64": { 336 | "version": "0.15.18", 337 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", 338 | "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", 339 | "cpu": [ 340 | "arm64" 341 | ], 342 | "dev": true, 343 | "optional": true, 344 | "os": [ 345 | "linux" 346 | ], 347 | "engines": { 348 | "node": ">=12" 349 | } 350 | }, 351 | "node_modules/esbuild-linux-mips64le": { 352 | "version": "0.15.18", 353 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", 354 | "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", 355 | "cpu": [ 356 | "mips64el" 357 | ], 358 | "dev": true, 359 | "optional": true, 360 | "os": [ 361 | "linux" 362 | ], 363 | "engines": { 364 | "node": ">=12" 365 | } 366 | }, 367 | "node_modules/esbuild-linux-ppc64le": { 368 | "version": "0.15.18", 369 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", 370 | "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", 371 | "cpu": [ 372 | "ppc64" 373 | ], 374 | "dev": true, 375 | "optional": true, 376 | "os": [ 377 | "linux" 378 | ], 379 | "engines": { 380 | "node": ">=12" 381 | } 382 | }, 383 | "node_modules/esbuild-linux-riscv64": { 384 | "version": "0.15.18", 385 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", 386 | "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", 387 | "cpu": [ 388 | "riscv64" 389 | ], 390 | "dev": true, 391 | "optional": true, 392 | "os": [ 393 | "linux" 394 | ], 395 | "engines": { 396 | "node": ">=12" 397 | } 398 | }, 399 | "node_modules/esbuild-linux-s390x": { 400 | "version": "0.15.18", 401 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", 402 | "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", 403 | "cpu": [ 404 | "s390x" 405 | ], 406 | "dev": true, 407 | "optional": true, 408 | "os": [ 409 | "linux" 410 | ], 411 | "engines": { 412 | "node": ">=12" 413 | } 414 | }, 415 | "node_modules/esbuild-netbsd-64": { 416 | "version": "0.15.18", 417 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", 418 | "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", 419 | "cpu": [ 420 | "x64" 421 | ], 422 | "dev": true, 423 | "optional": true, 424 | "os": [ 425 | "netbsd" 426 | ], 427 | "engines": { 428 | "node": ">=12" 429 | } 430 | }, 431 | "node_modules/esbuild-openbsd-64": { 432 | "version": "0.15.18", 433 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", 434 | "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", 435 | "cpu": [ 436 | "x64" 437 | ], 438 | "dev": true, 439 | "optional": true, 440 | "os": [ 441 | "openbsd" 442 | ], 443 | "engines": { 444 | "node": ">=12" 445 | } 446 | }, 447 | "node_modules/esbuild-sunos-64": { 448 | "version": "0.15.18", 449 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", 450 | "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", 451 | "cpu": [ 452 | "x64" 453 | ], 454 | "dev": true, 455 | "optional": true, 456 | "os": [ 457 | "sunos" 458 | ], 459 | "engines": { 460 | "node": ">=12" 461 | } 462 | }, 463 | "node_modules/esbuild-windows-32": { 464 | "version": "0.15.18", 465 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", 466 | "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", 467 | "cpu": [ 468 | "ia32" 469 | ], 470 | "dev": true, 471 | "optional": true, 472 | "os": [ 473 | "win32" 474 | ], 475 | "engines": { 476 | "node": ">=12" 477 | } 478 | }, 479 | "node_modules/esbuild-windows-64": { 480 | "version": "0.15.18", 481 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", 482 | "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", 483 | "cpu": [ 484 | "x64" 485 | ], 486 | "dev": true, 487 | "optional": true, 488 | "os": [ 489 | "win32" 490 | ], 491 | "engines": { 492 | "node": ">=12" 493 | } 494 | }, 495 | "node_modules/esbuild-windows-arm64": { 496 | "version": "0.15.18", 497 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", 498 | "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", 499 | "cpu": [ 500 | "arm64" 501 | ], 502 | "dev": true, 503 | "optional": true, 504 | "os": [ 505 | "win32" 506 | ], 507 | "engines": { 508 | "node": ">=12" 509 | } 510 | }, 511 | "node_modules/fsevents": { 512 | "version": "2.3.3", 513 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 514 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 515 | "dev": true, 516 | "hasInstallScript": true, 517 | "optional": true, 518 | "os": [ 519 | "darwin" 520 | ], 521 | "engines": { 522 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 523 | } 524 | }, 525 | "node_modules/function-bind": { 526 | "version": "1.1.2", 527 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 528 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 529 | "dev": true, 530 | "funding": { 531 | "url": "https://github.com/sponsors/ljharb" 532 | } 533 | }, 534 | "node_modules/hasown": { 535 | "version": "2.0.0", 536 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", 537 | "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", 538 | "dev": true, 539 | "dependencies": { 540 | "function-bind": "^1.1.2" 541 | }, 542 | "engines": { 543 | "node": ">= 0.4" 544 | } 545 | }, 546 | "node_modules/is-core-module": { 547 | "version": "2.13.1", 548 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", 549 | "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", 550 | "dev": true, 551 | "dependencies": { 552 | "hasown": "^2.0.0" 553 | }, 554 | "funding": { 555 | "url": "https://github.com/sponsors/ljharb" 556 | } 557 | }, 558 | "node_modules/kleur": { 559 | "version": "4.1.5", 560 | "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", 561 | "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", 562 | "dev": true, 563 | "engines": { 564 | "node": ">=6" 565 | } 566 | }, 567 | "node_modules/magic-string": { 568 | "version": "0.26.7", 569 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", 570 | "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", 571 | "dev": true, 572 | "dependencies": { 573 | "sourcemap-codec": "^1.4.8" 574 | }, 575 | "engines": { 576 | "node": ">=12" 577 | } 578 | }, 579 | "node_modules/ms": { 580 | "version": "2.1.2", 581 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 582 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 583 | "dev": true 584 | }, 585 | "node_modules/nanoid": { 586 | "version": "3.3.7", 587 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", 588 | "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", 589 | "dev": true, 590 | "funding": [ 591 | { 592 | "type": "github", 593 | "url": "https://github.com/sponsors/ai" 594 | } 595 | ], 596 | "bin": { 597 | "nanoid": "bin/nanoid.cjs" 598 | }, 599 | "engines": { 600 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 601 | } 602 | }, 603 | "node_modules/path-parse": { 604 | "version": "1.0.7", 605 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 606 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 607 | "dev": true 608 | }, 609 | "node_modules/picocolors": { 610 | "version": "1.0.0", 611 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 612 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 613 | "dev": true 614 | }, 615 | "node_modules/postcss": { 616 | "version": "8.4.33", 617 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", 618 | "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", 619 | "dev": true, 620 | "funding": [ 621 | { 622 | "type": "opencollective", 623 | "url": "https://opencollective.com/postcss/" 624 | }, 625 | { 626 | "type": "tidelift", 627 | "url": "https://tidelift.com/funding/github/npm/postcss" 628 | }, 629 | { 630 | "type": "github", 631 | "url": "https://github.com/sponsors/ai" 632 | } 633 | ], 634 | "dependencies": { 635 | "nanoid": "^3.3.7", 636 | "picocolors": "^1.0.0", 637 | "source-map-js": "^1.0.2" 638 | }, 639 | "engines": { 640 | "node": "^10 || ^12 || >=14" 641 | } 642 | }, 643 | "node_modules/resolve": { 644 | "version": "1.22.8", 645 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", 646 | "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", 647 | "dev": true, 648 | "dependencies": { 649 | "is-core-module": "^2.13.0", 650 | "path-parse": "^1.0.7", 651 | "supports-preserve-symlinks-flag": "^1.0.0" 652 | }, 653 | "bin": { 654 | "resolve": "bin/resolve" 655 | }, 656 | "funding": { 657 | "url": "https://github.com/sponsors/ljharb" 658 | } 659 | }, 660 | "node_modules/rollup": { 661 | "version": "2.79.1", 662 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", 663 | "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", 664 | "dev": true, 665 | "bin": { 666 | "rollup": "dist/bin/rollup" 667 | }, 668 | "engines": { 669 | "node": ">=10.0.0" 670 | }, 671 | "optionalDependencies": { 672 | "fsevents": "~2.3.2" 673 | } 674 | }, 675 | "node_modules/source-map-js": { 676 | "version": "1.0.2", 677 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 678 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 679 | "dev": true, 680 | "engines": { 681 | "node": ">=0.10.0" 682 | } 683 | }, 684 | "node_modules/sourcemap-codec": { 685 | "version": "1.4.8", 686 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 687 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 688 | "deprecated": "Please use @jridgewell/sourcemap-codec instead", 689 | "dev": true 690 | }, 691 | "node_modules/supports-preserve-symlinks-flag": { 692 | "version": "1.0.0", 693 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 694 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 695 | "dev": true, 696 | "engines": { 697 | "node": ">= 0.4" 698 | }, 699 | "funding": { 700 | "url": "https://github.com/sponsors/ljharb" 701 | } 702 | }, 703 | "node_modules/svelte": { 704 | "version": "3.59.2", 705 | "resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz", 706 | "integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==", 707 | "dev": true, 708 | "engines": { 709 | "node": ">= 8" 710 | } 711 | }, 712 | "node_modules/svelte-hmr": { 713 | "version": "0.15.3", 714 | "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", 715 | "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", 716 | "dev": true, 717 | "engines": { 718 | "node": "^12.20 || ^14.13.1 || >= 16" 719 | }, 720 | "peerDependencies": { 721 | "svelte": "^3.19.0 || ^4.0.0" 722 | } 723 | }, 724 | "node_modules/vite": { 725 | "version": "3.2.8", 726 | "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.8.tgz", 727 | "integrity": "sha512-EtQU16PLIJpAZol2cTLttNP1mX6L0SyI0pgQB1VOoWeQnMSvtiwovV3D6NcjN8CZQWWyESD2v5NGnpz5RvgOZA==", 728 | "dev": true, 729 | "dependencies": { 730 | "esbuild": "^0.15.9", 731 | "postcss": "^8.4.18", 732 | "resolve": "^1.22.1", 733 | "rollup": "^2.79.1" 734 | }, 735 | "bin": { 736 | "vite": "bin/vite.js" 737 | }, 738 | "engines": { 739 | "node": "^14.18.0 || >=16.0.0" 740 | }, 741 | "optionalDependencies": { 742 | "fsevents": "~2.3.2" 743 | }, 744 | "peerDependencies": { 745 | "@types/node": ">= 14", 746 | "less": "*", 747 | "sass": "*", 748 | "stylus": "*", 749 | "sugarss": "*", 750 | "terser": "^5.4.0" 751 | }, 752 | "peerDependenciesMeta": { 753 | "@types/node": { 754 | "optional": true 755 | }, 756 | "less": { 757 | "optional": true 758 | }, 759 | "sass": { 760 | "optional": true 761 | }, 762 | "stylus": { 763 | "optional": true 764 | }, 765 | "sugarss": { 766 | "optional": true 767 | }, 768 | "terser": { 769 | "optional": true 770 | } 771 | } 772 | }, 773 | "node_modules/vitefu": { 774 | "version": "0.2.5", 775 | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", 776 | "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", 777 | "dev": true, 778 | "peerDependencies": { 779 | "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" 780 | }, 781 | "peerDependenciesMeta": { 782 | "vite": { 783 | "optional": true 784 | } 785 | } 786 | } 787 | } 788 | } 789 | --------------------------------------------------------------------------------