diff --git a/packages/browser-tests/tests/10-finder-iconify-test.ts b/packages/browser-tests/tests/10-finder-iconify-test.ts index e8b5df1..28b7375 100644 --- a/packages/browser-tests/tests/10-finder-iconify-test.ts +++ b/packages/browser-tests/tests/10-finder-iconify-test.ts @@ -3,7 +3,7 @@ import chai from 'chai'; import { getNode } from './node'; import { finder } from '@iconify/iconify/lib/finders/iconify'; -import { IconifyElement } from '@iconify/iconify/lib/element'; +import { IconifyElement } from '@iconify/iconify/lib/modules/element'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; const expect = chai.expect; diff --git a/packages/browser-tests/tests/10-finder-v1-test.ts b/packages/browser-tests/tests/10-finder-v1-test.ts index 1c60b85..c3a8b21 100644 --- a/packages/browser-tests/tests/10-finder-v1-test.ts +++ b/packages/browser-tests/tests/10-finder-v1-test.ts @@ -2,8 +2,11 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { addFinder, findPlaceholders } from '@iconify/iconify/lib/finder'; -import { IconifyFinder } from '@iconify/iconify/lib/interfaces/finder'; +import { + addFinder, + findPlaceholders, +} from '@iconify/iconify/lib/modules/finder'; +import { IconifyFinder } from '@iconify/iconify/lib/finders/interface'; import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify-v1'; import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-v1-icon'; import { IconifyIconName } from '@iconify/core/lib/icon/name'; diff --git a/packages/browser-tests/tests/10-finder-v2-test.ts b/packages/browser-tests/tests/10-finder-v2-test.ts index efa45a5..61a246c 100644 --- a/packages/browser-tests/tests/10-finder-v2-test.ts +++ b/packages/browser-tests/tests/10-finder-v2-test.ts @@ -2,8 +2,11 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { addFinder, findPlaceholders } from '@iconify/iconify/lib/finder'; -import { IconifyFinder } from '@iconify/iconify/lib/interfaces/finder'; +import { + addFinder, + findPlaceholders, +} from '@iconify/iconify/lib/modules/finder'; +import { IconifyFinder } from '@iconify/iconify/lib/finders/interface'; import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify'; import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon'; import { IconifyIconName } from '@iconify/core/lib/icon/name'; diff --git a/packages/browser-tests/tests/10-observer-creation-test.ts b/packages/browser-tests/tests/10-observer-creation-test.ts index be33336..ad21b3a 100644 --- a/packages/browser-tests/tests/10-observer-creation-test.ts +++ b/packages/browser-tests/tests/10-observer-creation-test.ts @@ -2,20 +2,24 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { browserModules } from '@iconify/iconify/lib/modules'; -import { observer } from '@iconify/iconify/lib/observer/observer'; +import { setRoot } from '@iconify/iconify/lib/modules/root'; +import { + initObserver, + isObserverPaused, + pauseObserver, +} from '@iconify/iconify/lib/modules/observer'; const expect = chai.expect; describe('Testing observer creation', () => { it('Creating observer and triggering event', (done) => { const node = getNode('observer-creation'); - browserModules.root = node; + setRoot(node); let counter = 0; node.innerHTML = '
'; - observer.init((root) => { + initObserver((root) => { expect(root).to.be.equal(node); counter++; @@ -23,17 +27,17 @@ describe('Testing observer creation', () => { // Should be called only once expect(counter).to.be.equal(1); - expect(observer.isPaused()).to.be.equal(false); + expect(isObserverPaused()).to.be.equal(false); // Pause observer - observer.pause(); - expect(observer.isPaused()).to.be.equal(true); + pauseObserver(); + expect(isObserverPaused()).to.be.equal(true); done(); }); // Add few nodes to trigger observer - expect(observer.isPaused()).to.be.equal(false); + expect(isObserverPaused()).to.be.equal(false); node.querySelector('div').innerHTML = 'Some text!'; }); diff --git a/packages/browser-tests/tests/10-observer-manipulation-test.ts b/packages/browser-tests/tests/10-observer-manipulation-test.ts index 99402ce..940d19f 100644 --- a/packages/browser-tests/tests/10-observer-manipulation-test.ts +++ b/packages/browser-tests/tests/10-observer-manipulation-test.ts @@ -2,23 +2,28 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { elementFinderProperty } from '@iconify/iconify/lib/element'; -import { browserModules } from '@iconify/iconify/lib/modules'; -import { observer } from '@iconify/iconify/lib/observer/observer'; +import { elementFinderProperty } from '@iconify/iconify/lib/modules/element'; +import { setRoot } from '@iconify/iconify/lib/modules/root'; +import { + initObserver, + pauseObserver, + resumeObserver, + isObserverPaused, +} from '@iconify/iconify/lib/modules/observer'; const expect = chai.expect; describe('Testing observer with DOM manipulation', () => { it('Series of events', (done) => { const node = getNode('observer-manipulation'); - browserModules.root = node; + setRoot(node); let counter = 0; let waitingCallback: string | boolean = true; node.innerHTML = '
'; - observer.init((root) => { + initObserver((root) => { expect(root).to.be.equal(node); expect(waitingCallback).to.be.equal(true); @@ -50,14 +55,14 @@ describe('Testing observer with DOM manipulation', () => { waitingCallback = 'pause test'; (() => { const item = node.querySelector('ul > li:last-child'); - observer.pause(); + pauseObserver(); item.innerHTML = 'Strong text!'; // Set timer for next step to make sure callback is not called setTimeout(() => { // Resume observer and wait a bit. Resuming observer should not trigger update waitingCallback = 'resume test'; - observer.resume(); + resumeObserver(); setTimeout(() => { // Change text of item: should remove and add new text node @@ -103,7 +108,7 @@ describe('Testing observer with DOM manipulation', () => { }); // Add few nodes to trigger observer - expect(observer.isPaused()).to.be.equal(false); + expect(isObserverPaused()).to.be.equal(false); node.querySelector('div').innerHTML = 'Some text!'; }); diff --git a/packages/browser-tests/tests/20-renderer-v1-test.ts b/packages/browser-tests/tests/20-renderer-v1-test.ts index c2c2ac0..c1d4b30 100644 --- a/packages/browser-tests/tests/20-renderer-v1-test.ts +++ b/packages/browser-tests/tests/20-renderer-v1-test.ts @@ -2,13 +2,16 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { addFinder, findPlaceholders } from '@iconify/iconify/lib/finder'; +import { + addFinder, + findPlaceholders, +} from '@iconify/iconify/lib/modules/finder'; import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify-v1'; import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-v1-icon'; import { getStorage, addIconSet, getIcon } from '@iconify/core/lib/storage'; -import { renderIcon } from '@iconify/iconify/lib/render'; +import { renderIcon } from '@iconify/iconify/lib/modules/render'; import { stringToIcon } from '@iconify/core/lib/icon/name'; -import { IconifyElement } from '@iconify/iconify/lib/element'; +import { IconifyElement } from '@iconify/iconify/lib/modules/element'; const expect = chai.expect; diff --git a/packages/browser-tests/tests/20-renderer-v2-test.ts b/packages/browser-tests/tests/20-renderer-v2-test.ts index 8fc0fe6..8f5ccfc 100644 --- a/packages/browser-tests/tests/20-renderer-v2-test.ts +++ b/packages/browser-tests/tests/20-renderer-v2-test.ts @@ -2,13 +2,16 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { addFinder, findPlaceholders } from '@iconify/iconify/lib/finder'; +import { + addFinder, + findPlaceholders, +} from '@iconify/iconify/lib/modules/finder'; import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify'; import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon'; import { getStorage, addIconSet, getIcon } from '@iconify/core/lib/storage'; -import { renderIcon } from '@iconify/iconify/lib/render'; +import { renderIcon } from '@iconify/iconify/lib/modules/render'; import { stringToIcon } from '@iconify/core/lib/icon/name'; -import { IconifyElement } from '@iconify/iconify/lib/element'; +import { IconifyElement } from '@iconify/iconify/lib/modules/element'; const expect = chai.expect; diff --git a/packages/browser-tests/tests/20-scan-dom-test.ts b/packages/browser-tests/tests/20-scan-dom-test.ts index 5dfc967..54f94f4 100644 --- a/packages/browser-tests/tests/20-scan-dom-test.ts +++ b/packages/browser-tests/tests/20-scan-dom-test.ts @@ -2,12 +2,12 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { addFinder } from '@iconify/iconify/lib/finder'; +import { addFinder } from '@iconify/iconify/lib/modules/finder'; import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify'; import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon'; import { getStorage, addIconSet } from '@iconify/core/lib/storage'; -import { browserModules } from '@iconify/iconify/lib/modules'; -import { scanDOM } from '@iconify/iconify/lib/scanner/scan'; +import { setRoot } from '@iconify/iconify/lib/modules/root'; +import { scanDOM } from '@iconify/iconify/lib/modules/scanner'; const expect = chai.expect; @@ -56,7 +56,7 @@ describe('Scanning DOM', () => { '' + ''; - browserModules.root = node; + setRoot(node); scanDOM(); // Find elements diff --git a/packages/browser-tests/tests/21-scan-dom-api-test.ts b/packages/browser-tests/tests/21-scan-dom-api-test.ts index 4b94af7..2f334d2 100644 --- a/packages/browser-tests/tests/21-scan-dom-api-test.ts +++ b/packages/browser-tests/tests/21-scan-dom-api-test.ts @@ -2,7 +2,7 @@ import mocha from 'mocha'; import chai from 'chai'; import { getNode } from './node'; -import { addFinder } from '@iconify/iconify/lib/finder'; +import { addFinder } from '@iconify/iconify/lib/modules/finder'; import { FakeData, setFakeData, prepareQuery, sendQuery } from './fake-api'; import { API } from '@iconify/core/lib/api/'; import { setAPIModule } from '@iconify/core/lib/api/modules'; @@ -10,8 +10,8 @@ import { setAPIConfig } from '@iconify/core/lib/api/config'; import { coreModules } from '@iconify/core/lib/modules'; import { finder as iconifyFinder } from '@iconify/iconify/lib/finders/iconify'; import { finder as iconifyIconFinder } from '@iconify/iconify/lib/finders/iconify-icon'; -import { browserModules } from '@iconify/iconify/lib/modules'; -import { scanDOM } from '@iconify/iconify/lib/scanner/scan'; +import { setRoot } from '@iconify/iconify/lib/modules/root'; +import { scanDOM } from '@iconify/iconify/lib/modules/scanner'; const expect = chai.expect; @@ -114,7 +114,7 @@ describe('Scanning DOM with API', () => { '' + ''; - browserModules.root = node; + setRoot(node); scanDOM(); @@ -241,7 +241,7 @@ describe('Scanning DOM with API', () => { '' + ''; - browserModules.root = node; + setRoot(node); scanDOM(); @@ -369,7 +369,7 @@ describe('Scanning DOM with API', () => { '' + ''; - browserModules.root = node; + setRoot(node); scanDOM(); diff --git a/packages/browser-tests/tests/30-iconify-without-api-test.ts b/packages/browser-tests/tests/30-iconify-without-api-test.ts new file mode 100644 index 0000000..fe331d9 --- /dev/null +++ b/packages/browser-tests/tests/30-iconify-without-api-test.ts @@ -0,0 +1,129 @@ +import mocha from 'mocha'; +import chai from 'chai'; + +import { getNode } from './node'; +import Iconify from '@iconify/iconify/lib/iconify.without-api'; + +const expect = chai.expect; + +const selector = + 'span.iconify, i.iconify, span.iconify-inline, i.iconify-inline'; + +const node1 = getNode('iconify-basic'); +const node2 = getNode('iconify-basic'); + +// Set root node +Iconify.setRoot(node1); + +describe('Testing Iconify object (without API)', () => { + const prefix = 'invalid-' + Date.now(); + + // Add mentioned icons to storage + Iconify.addCollection({ + prefix, + icons: { + 'account-box': { + body: + '', + }, + 'account-cash': { + body: + '', + }, + 'account': { + body: + '', + }, + 'home': { + body: + '', + }, + }, + width: 24, + height: 24, + }); + + // Add one icon separately + Iconify.addIcon(prefix + ':id-test', { + body: + '', + width: 128, + height: 128, + }); + + it('Check iconExists', () => { + expect(Iconify.iconExists(prefix + ':' + 'account')).to.be.equal(true); + expect(Iconify.iconExists(prefix + ':' + 'missing')).to.be.equal(false); + expect(Iconify.iconExists(prefix + '-123:' + 'missing')).to.be.equal( + false + ); + }); + + it('Get SVG node', () => { + const node = Iconify.renderSVG(prefix + ':account', { + inline: true, + }); + expect(node).to.not.be.equal(null); + + const html = node.outerHTML; + console.log('Rendered SVG:', html); + expect(html.indexOf(' { + node1.innerHTML = + '

Testing Iconify without API

' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '
'; + + node2.innerHTML = + '

This node should not be replaced

' + + ''; + + // Icons should not have been replaced yet + let list = node1.querySelectorAll(selector); + expect(list.length).to.be.equal(5); + + list = node2.querySelectorAll(selector); + expect(list.length).to.be.equal(1); + + // Check in ticks + setTimeout(() => { + setTimeout(() => { + list = node1.querySelectorAll(selector); + expect(list.length).to.be.equal(0); + + list = node2.querySelectorAll(selector); + expect(list.length).to.be.equal(1); + + // Test SVG with ID + const idTest = node1.querySelector('#ssvg-id-1st-place-medala'); + expect(idTest).to.be.equal(null, 'Expecting ID to be replaced'); + + done(); + }); + }); + }); +}); diff --git a/packages/iconify/api-extractor.without-api.min.json b/packages/iconify/api-extractor.without-api.min.json new file mode 100644 index 0000000..3d514df --- /dev/null +++ b/packages/iconify/api-extractor.without-api.min.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "lib/iconify.without-api.d.ts", + "bundledPackages": [ + "@iconify/types", + "@iconify/core", + "@cyberalien/redundancy" + ], + "compiler": {}, + "apiReport": { + "enabled": false + }, + "docModel": { + "enabled": false + }, + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/dist/iconify.without-api.min.d.ts" + }, + "tsdocMetadata": { + "enabled": false + }, + "messages": { + "compilerMessageReporting": { + "default": { + "logLevel": "none" + } + }, + "extractorMessageReporting": { + "default": { + "logLevel": "none" + }, + "ae-missing-release-tag": { + "logLevel": "none" + }, + "ae-forgotten-export": { + "logLevel": "none" + } + }, + "tsdocMessageReporting": { + "default": { + "logLevel": "none" + } + } + } +} diff --git a/packages/iconify/build.js b/packages/iconify/build.js index 57d273b..dfa2af7 100644 --- a/packages/iconify/build.js +++ b/packages/iconify/build.js @@ -80,6 +80,7 @@ if (compile.core) { // Add api2 if (compile.api) { compile.api2 = true; + compile.api2min = true; } // Compile other packages diff --git a/packages/iconify/demo/loading-icons.without-api.html b/packages/iconify/demo/loading-icons.without-api.html new file mode 100644 index 0000000..461e26f --- /dev/null +++ b/packages/iconify/demo/loading-icons.without-api.html @@ -0,0 +1,156 @@ + + + + + + Iconify Demo: Loading Icons (without API) + + + + + + +

+ This page tests various ways to dynamically load icons without API + (except for first example that uses API).
+ On success, after each line of text there should be a green icon. +

+

+ Icon loaded from API (should not load): + +

+ +

+ Icon loaded with addCollection(): + +

+

+ Icon loaded with addIcon(): + +

+

+ Icon loaded with IconifyPreload: + +

+ +

+ Icon loaded with addCollection() and custom provider: + +

+

+ Icon loaded with addIcon() and custom provider: + +

+

+ Icon loaded with IconifyPreload and custom provider: + +

+ + diff --git a/packages/iconify/package.json b/packages/iconify/package.json index 19ae682..3430bb2 100644 --- a/packages/iconify/package.json +++ b/packages/iconify/package.json @@ -19,7 +19,8 @@ "build:lib": "tsc -b", "build:dist": "rollup -c rollup.config.js", "build:api": "api-extractor run --local --verbose", - "build:api2": "api-extractor run --local --verbose --config api-extractor.without-api.json" + "build:api2": "api-extractor run --local --verbose --config api-extractor.without-api.json", + "build:api2min": "api-extractor run --local --config api-extractor.without-api.min.json" }, "devDependencies": { "@cyberalien/redundancy": "^1.0.0", diff --git a/packages/iconify/src/common.ts b/packages/iconify/src/common.ts index 3f981d4..2fa0910 100644 --- a/packages/iconify/src/common.ts +++ b/packages/iconify/src/common.ts @@ -1,10 +1,139 @@ import { IconifyJSON } from '@iconify/types'; -import { IconifyIcon } from '@iconify/core/lib/icon'; +import { merge } from '@iconify/core/lib/misc/merge'; +import { + stringToIcon, + validateIcon, + IconifyIconName, +} from '@iconify/core/lib/icon/name'; +import { IconifyIcon, FullIconifyIcon } from '@iconify/core/lib/icon'; +import { + IconifyIconCustomisations, + fullCustomisations, +} from '@iconify/core/lib/customisations'; +import { + getStorage, + getIcon, + addIcon, + addIconSet, + listStoredProviders, + listStoredPrefixes, +} from '@iconify/core/lib/storage'; +import { iconToSVG, IconifyIconBuildResult } from '@iconify/core/lib/builder'; +import { replaceIDs } from '@iconify/core/lib/builder/ids'; +import { renderIcon } from './modules/render'; +import { + initObserver, + pauseObserver, + resumeObserver, +} from './modules/observer'; +import { scanDOM } from './modules/scanner'; + +// Finders +import { addFinder } from './modules/finder'; +import { finder as iconifyFinder } from './finders/iconify'; +import { setRoot } from './modules/root'; +// import { finder as iconifyIconFinder } from './finders/iconify-icon'; + +/** + * Get icon name + */ +function getIconName(name: string): IconifyIconName | null { + const icon = stringToIcon(name); + if (!validateIcon(icon)) { + return null; + } + return icon; +} + +/** + * Get icon data + */ +function getIconData(name: string): FullIconifyIcon | null { + const icon = getIconName(name); + return icon + ? getIcon(getStorage(icon.provider, icon.prefix), icon.name) + : null; +} + +/** + * Get SVG data + */ +function buildIcon( + name: string, + customisations: IconifyIconCustomisations +): IconifyIconBuildResult | null { + // Get icon data + const iconData = getIconData(name); + if (!iconData) { + return null; + } + + // Clean up customisations + const changes = fullCustomisations(customisations); + + // Get data + return iconToSVG(iconData, changes); +} + +/** + * Generate icon + */ +function generateIcon( + name: string, + customisations: IconifyIconCustomisations, + returnString: boolean +): SVGElement | string | null { + // Get icon data + const iconData = getIconData(name); + if (!iconData) { + return null; + } + + // Split name + const iconName = stringToIcon(name); + + // Clean up customisations + const changes = fullCustomisations(customisations); + + // Get data + return (renderIcon( + { + name: iconName, + }, + changes, + iconData, + returnString + ) as unknown) as SVGElement | string | null; +} + +/** + * Add icon set + */ +export function addCollection(data: IconifyJSON, provider?: string) { + if (typeof provider !== 'string') { + provider = typeof data.provider === 'string' ? data.provider : ''; + } + + if ( + typeof data !== 'object' || + typeof data.prefix !== 'string' || + !validateIcon({ + provider, + prefix: data.prefix, + name: 'a', + }) + ) { + return false; + } + + const storage = getStorage(provider, data.prefix); + return !!addIconSet(storage, data); +} /** * Iconify interface */ -export interface IconifyGlobalCommon { +export interface IconifyGlobal { /* General section */ /** * Get version @@ -37,4 +166,203 @@ export interface IconifyGlobalCommon { * Add icon set to storage */ addCollection: (data: IconifyJSON, provider?: string) => boolean; + + /** + * Render icons + */ + renderSVG: ( + name: string, + customisations: IconifyIconCustomisations + ) => SVGElement | null; + + renderHTML: ( + name: string, + customisations: IconifyIconCustomisations + ) => string | null; + + /** + * Get icon data + */ + renderIcon: typeof buildIcon; + + /** + * Replace IDs in icon body, should be used when parsing buildIcon() result + */ + replaceIDs: typeof replaceIDs; + + /* Scanner */ + /** + * Scan DOM + */ + scanDOM: typeof scanDOM; + + /** + * Set root node + */ + setRoot: (root: HTMLElement) => void; + + /* Observer */ + /** + * Pause observer + */ + pauseObserver: typeof pauseObserver; + + /** + * Resume observer + */ + resumeObserver: typeof resumeObserver; +} + +/** + * Global variable + */ +export const IconifyCommon: IconifyGlobal = { + // Version + getVersion: () => '__iconify_version__', + + // Check if icon exists + iconExists: (name) => getIconData(name) !== null, + + // Get raw icon data + getIcon: (name) => { + const result = getIconData(name); + return result ? merge(result) : null; + }, + + // List icons + listIcons: (provider?: string, prefix?: string) => { + let icons = []; + + // Get providers + let providers: string[]; + if (typeof provider === 'string') { + providers = [provider]; + } else { + providers = listStoredProviders(); + } + + // Get all icons + providers.forEach((provider) => { + let prefixes: string[]; + + if (typeof prefix === 'string') { + prefixes = [prefix]; + } else { + prefixes = listStoredPrefixes(provider); + } + + prefixes.forEach((prefix) => { + const storage = getStorage(provider, prefix); + let icons = Object.keys(storage.icons).map( + (name) => + (provider !== '' ? '@' + provider + ':' : '') + + prefix + + ':' + + name + ); + icons = icons.concat(icons); + }); + }); + + return icons; + }, + + // Add icon + addIcon: (name, data) => { + const icon = getIconName(name); + if (!icon) { + return false; + } + const storage = getStorage(icon.provider, icon.prefix); + return addIcon(storage, icon.name, data); + }, + + // Add icon set + addCollection, + + // Render SVG + renderSVG: (name: string, customisations: IconifyIconCustomisations) => { + return generateIcon(name, customisations, false) as SVGElement | null; + }, + + renderHTML: (name: string, customisations: IconifyIconCustomisations) => { + return generateIcon(name, customisations, true) as string | null; + }, + + // Get rendered icon as object that can be used to create SVG (use replaceIDs on body) + renderIcon: buildIcon, + + // Replace IDs in body + replaceIDs, + + // Scan DOM + scanDOM, + + // Set root node + setRoot: (root: HTMLElement) => { + setRoot(root); + + // Restart observer + initObserver(scanDOM); + + // Scan DOM on next tick + setTimeout(scanDOM); + }, + + // Pause observer + pauseObserver, + + // Resume observer + resumeObserver, +}; + +/** + * Initialise stuff + */ +if (typeof document !== 'undefined' && typeof window !== 'undefined') { + // Add finder modules + // addFinder(iconifyIconFinder); + addFinder(iconifyFinder); + + const _window = window; + + // Load icons from global "IconifyPreload" + interface WindowWithIconifyPreload { + IconifyPreload: IconifyJSON[] | IconifyJSON; + } + if ( + ((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !== + void 0 + ) { + const preload = ((_window as unknown) as WindowWithIconifyPreload) + .IconifyPreload; + const err = 'Invalid IconifyPreload syntax.'; + if (typeof preload === 'object' && preload !== null) { + (preload instanceof Array ? preload : [preload]).forEach((item) => { + try { + if ( + // Check if item is an object and not null/array + typeof item !== 'object' || + item === null || + item instanceof Array || + // Check for 'icons' and 'prefix' + typeof item.icons !== 'object' || + typeof item.prefix !== 'string' || + // Add icon set + !addCollection(item) + ) { + console.error(err); + } + } catch (e) { + console.error(err); + } + }); + } + } + + // Load observer + setTimeout(() => { + // Init on next tick when entire document has been parsed + initObserver(scanDOM); + }); } diff --git a/packages/iconify/src/finders/iconify-icon.ts b/packages/iconify/src/finders/iconify-icon.ts index ffb7a5a..f565c7c 100644 --- a/packages/iconify/src/finders/iconify-icon.ts +++ b/packages/iconify/src/finders/iconify-icon.ts @@ -1,5 +1,5 @@ -import { IconifyFinder } from '../interfaces/finder'; -import { IconifyElement } from '../element'; +import { IconifyFinder } from './interface'; +import { IconifyElement } from '../modules/element'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; import { finder as iconifyFinder } from './iconify'; diff --git a/packages/iconify/src/finders/iconify-v1-icon.ts b/packages/iconify/src/finders/iconify-v1-icon.ts index 4cade3f..4b9b1d1 100644 --- a/packages/iconify/src/finders/iconify-v1-icon.ts +++ b/packages/iconify/src/finders/iconify-v1-icon.ts @@ -1,5 +1,5 @@ -import { IconifyFinder } from '../interfaces/finder'; -import { IconifyElement } from '../element'; +import { IconifyFinder } from './interface'; +import { IconifyElement } from '../modules/element'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; import { finder as iconifyFinder } from './iconify-v1'; diff --git a/packages/iconify/src/finders/iconify-v1.ts b/packages/iconify/src/finders/iconify-v1.ts index ac9b578..b61d90a 100644 --- a/packages/iconify/src/finders/iconify-v1.ts +++ b/packages/iconify/src/finders/iconify-v1.ts @@ -1,5 +1,5 @@ -import { IconifyFinder } from '../interfaces/finder'; -import { IconifyElement } from '../element'; +import { IconifyFinder } from './interface'; +import { IconifyElement } from '../modules/element'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; import { rotateFromString } from '@iconify/core/lib/customisations/rotate'; import { @@ -118,7 +118,7 @@ const finder: IconifyFinder = { } // Boolean attributes - booleanAttributes.forEach(attr => { + booleanAttributes.forEach((attr) => { if (hasAttribute(element, 'data-' + attr)) { const value = getBooleanAttribute(element, 'data-' + attr); if (typeof value === 'boolean') { @@ -128,7 +128,7 @@ const finder: IconifyFinder = { }); // String attributes - stringAttributes.forEach(attr => { + stringAttributes.forEach((attr) => { if (hasAttribute(element, 'data-' + attr)) { const value = getAttribute(element, 'data-' + attr); if (value !== '') { @@ -145,7 +145,7 @@ const finder: IconifyFinder = { */ classFilter: (classList: string[]): string[] => { let result: string[] = []; - classList.forEach(className => { + classList.forEach((className) => { if ( className !== 'iconify' && className !== '' && diff --git a/packages/iconify/src/finders/iconify.ts b/packages/iconify/src/finders/iconify.ts index 552257d..c16f72b 100644 --- a/packages/iconify/src/finders/iconify.ts +++ b/packages/iconify/src/finders/iconify.ts @@ -1,5 +1,5 @@ -import { IconifyFinder } from '../interfaces/finder'; -import { IconifyElement } from '../element'; +import { IconifyFinder } from './interface'; +import { IconifyElement } from '../modules/element'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; import { rotateFromString } from '@iconify/core/lib/customisations/rotate'; import { @@ -134,7 +134,7 @@ const finder: IconifyFinder = { } // Boolean attributes - booleanAttributes.forEach(attr => { + booleanAttributes.forEach((attr) => { if (hasAttribute(element, 'data-' + attr)) { const value = getBooleanAttribute(element, 'data-' + attr); if (typeof value === 'boolean') { @@ -144,7 +144,7 @@ const finder: IconifyFinder = { }); // String attributes - stringAttributes.forEach(attr => { + stringAttributes.forEach((attr) => { if (hasAttribute(element, 'data-' + attr)) { const value = getAttribute(element, 'data-' + attr); if (value !== '') { @@ -161,7 +161,7 @@ const finder: IconifyFinder = { */ classFilter: (classList: string[]): string[] => { let result: string[] = []; - classList.forEach(className => { + classList.forEach((className) => { if ( className !== 'iconify' && className !== '' && diff --git a/packages/iconify/src/interfaces/finder.ts b/packages/iconify/src/finders/interface.ts similarity index 94% rename from packages/iconify/src/interfaces/finder.ts rename to packages/iconify/src/finders/interface.ts index 5744e10..615f0f1 100644 --- a/packages/iconify/src/interfaces/finder.ts +++ b/packages/iconify/src/finders/interface.ts @@ -1,4 +1,4 @@ -import { IconifyElement } from '../element'; +import { IconifyElement } from '../modules/element'; import { IconifyIconName } from '@iconify/core/lib/icon/name'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; diff --git a/packages/iconify/src/iconify.ts b/packages/iconify/src/iconify.ts index 611c5ec..6bd8b83 100644 --- a/packages/iconify/src/iconify.ts +++ b/packages/iconify/src/iconify.ts @@ -1,45 +1,28 @@ // Core import { IconifyJSON } from '@iconify/types'; -import { merge } from '@iconify/core/lib/misc/merge'; -import { - stringToIcon, - validateIcon, - IconifyIconName, -} from '@iconify/core/lib/icon/name'; -import { IconifyIcon, FullIconifyIcon } from '@iconify/core/lib/icon'; +import { IconifyIconName } from '@iconify/core/lib/icon/name'; +import { IconifyIcon } from '@iconify/core/lib/icon'; import { IconifyIconCustomisations, - fullCustomisations, IconifyIconSize, IconifyHorizontalIconAlignment, IconifyVerticalIconAlignment, } from '@iconify/core/lib/customisations'; -import { - getStorage, - getIcon, - addIcon, - addIconSet, - listStoredProviders, - listStoredPrefixes, -} from '@iconify/core/lib/storage'; -import { iconToSVG, IconifyIconBuildResult } from '@iconify/core/lib/builder'; -import { replaceIDs } from '@iconify/core/lib/builder/ids'; +import { IconifyIconBuildResult } from '@iconify/core/lib/builder'; import { calcSize } from '@iconify/core/lib/builder/calc-size'; // Modules import { coreModules } from '@iconify/core/lib/modules'; -import { browserModules } from './modules'; - -// Finders -import { addFinder } from './finder'; -import { finder as iconifyFinder } from './finders/iconify'; -// import { finder as iconifyIconFinder } from './finders/iconify-icon'; // Cache import { storeCache, loadCache, config } from '@iconify/core/lib/cache/storage'; // API -import { IconifyAPI, IconifyExposedAPIInternals } from './api'; +import { + IconifyAPI, + IconifyExposedAPIInternals, + IconifyCacheType, +} from './modules/api'; import { API, getRedundancyCache, @@ -66,22 +49,9 @@ import { IconifyIconLoaderAbort, } from '@iconify/core/lib/interfaces/loader'; -// Observer -import { IconifyObserver } from './observer'; -import { observer } from './observer/observer'; - -// Render -import { IconifyRenderer } from './renderer'; -import { renderIcon } from './renderer/render'; - -// Scan -import { IconifyScanner } from './scanner'; -import { scanDOM } from './scanner/scan'; - // Other import { IconifyExposedCommonInternals } from './internals'; -import { IconifyGlobalCommon } from './common'; -import { IconifyCacheType } from '../dist/iconify'; +import { IconifyGlobal as IconifyGlobal1, IconifyCommon } from './common'; /** * Export required types @@ -125,221 +95,33 @@ export interface IconifyExposedInternals IconifyExposedCommonInternals {} /** - * Iconify interface + * Exported functions */ -export interface IconifyGlobal - extends IconifyGlobalCommon, - IconifyScanner, - IconifyObserver, - IconifyRenderer, - IconifyAPI { +export interface IconifyGlobal2 extends IconifyAPI { /** * Expose internal functions */ _internal: IconifyExposedInternals; } +/** + * Iconify interface + */ +export interface IconifyGlobal extends IconifyGlobal1, IconifyGlobal2 {} + // Export dependencies -export { IconifyObserver, IconifyScanner, IconifyRenderer, IconifyAPI }; - -/** - * Get icon name - */ -function getIconName(name: string): IconifyIconName | null { - const icon = stringToIcon(name); - if (!validateIcon(icon)) { - return null; - } - return icon; -} - -/** - * Get icon data - */ -function getIconData(name: string): FullIconifyIcon | null { - const icon = getIconName(name); - return icon - ? getIcon(getStorage(icon.provider, icon.prefix), icon.name) - : null; -} - -/** - * Get SVG data - */ -function buildIcon( - name: string, - customisations: IconifyIconCustomisations -): IconifyIconBuildResult | null { - // Get icon data - const iconData = getIconData(name); - if (!iconData) { - return null; - } - - // Clean up customisations - const changes = fullCustomisations(customisations); - - // Get data - return iconToSVG(iconData, changes); -} - -/** - * Generate icon - */ -function generateIcon( - name: string, - customisations: IconifyIconCustomisations, - returnString: boolean -): SVGElement | string | null { - // Get icon data - const iconData = getIconData(name); - if (!iconData) { - return null; - } - - // Split name - const iconName = stringToIcon(name); - - // Clean up customisations - const changes = fullCustomisations(customisations); - - // Get data - return (renderIcon( - { - name: iconName, - }, - changes, - iconData, - returnString - ) as unknown) as SVGElement | string | null; -} - -/** - * Add icon set - */ -function addCollection(data: IconifyJSON, provider?: string) { - if (typeof provider !== 'string') { - provider = typeof data.provider === 'string' ? data.provider : ''; - } - - if ( - typeof data !== 'object' || - typeof data.prefix !== 'string' || - !validateIcon({ - provider, - prefix: data.prefix, - name: 'a', - }) - ) { - return false; - } - - const storage = getStorage(provider, data.prefix); - return !!addIconSet(storage, data); -} +export { IconifyGlobal as IconifyGlobalCommon, IconifyAPI }; /** * Global variable */ -const Iconify: IconifyGlobal = { - // Version - getVersion: () => '__iconify_version__', - - // Check if icon exists - iconExists: (name) => getIconData(name) !== null, - - // Get raw icon data - getIcon: (name) => { - const result = getIconData(name); - return result ? merge(result) : null; - }, - - // List icons - listIcons: (provider?: string, prefix?: string) => { - let icons = []; - - // Get providers - let providers: string[]; - if (typeof provider === 'string') { - providers = [provider]; - } else { - providers = listStoredProviders(); - } - - // Get all icons - providers.forEach((provider) => { - let prefixes: string[]; - - if (typeof prefix === 'string') { - prefixes = [prefix]; - } else { - prefixes = listStoredPrefixes(provider); - } - - prefixes.forEach((prefix) => { - const storage = getStorage(provider, prefix); - let icons = Object.keys(storage.icons).map( - (name) => - (provider !== '' ? '@' + provider + ':' : '') + - prefix + - ':' + - name - ); - icons = icons.concat(icons); - }); - }); - - return icons; - }, - +const Iconify: IconifyGlobal = ({ // Load icons loadIcons: API.loadIcons, - // Render SVG - renderSVG: (name: string, customisations: IconifyIconCustomisations) => { - return generateIcon(name, customisations, false) as SVGElement | null; - }, - - renderHTML: (name: string, customisations: IconifyIconCustomisations) => { - return generateIcon(name, customisations, true) as string | null; - }, - - // Get rendered icon as object that can be used to create SVG (use replaceIDs on body) - renderIcon: buildIcon, - - // Replace IDs in body - replaceIDs: replaceIDs, - - // Add icon - addIcon: (name, data) => { - const icon = getIconName(name); - if (!icon) { - return false; - } - const storage = getStorage(icon.provider, icon.prefix); - return addIcon(storage, icon.name, data); - }, - - // Add icon set - addCollection: addCollection, - // API providers addAPIProvider: setAPIConfig, - // Scan DOM - scanDOM: scanDOM, - - // Set root node - setRoot: (root: HTMLElement) => { - browserModules.root = root; - - // Restart observer - observer.init(scanDOM); - - // Scan DOM on next tick - setTimeout(scanDOM); - }, - // Allow storage enableCache: (storage: IconifyCacheType, value: boolean) => { switch (storage) { @@ -356,10 +138,6 @@ const Iconify: IconifyGlobal = { } }, - // Observer - pauseObserver: observer.pause, - resumeObserver: observer.resume, - // Exposed internal functions _internal: { // Calculate size @@ -374,7 +152,12 @@ const Iconify: IconifyGlobal = { // Get API module setAPIModule, }, -}; +} as IconifyGlobal2) as IconifyGlobal; + +// Merge with common functions +for (const key in IconifyCommon) { + Iconify[key] = IconifyCommon[key]; +} /** * Initialise stuff @@ -394,50 +177,12 @@ try { setAPIModule('', getAPIModule(getAPIConfig)); if (typeof document !== 'undefined' && typeof window !== 'undefined') { - // Add finder modules - // addFinder(iconifyIconFinder); - addFinder(iconifyFinder); - // Set cache and load existing cache coreModules.cache = storeCache; loadCache(); const _window = window; - // Load icons from global "IconifyPreload" - interface WindowWithIconifyPreload { - IconifyPreload: IconifyJSON[] | IconifyJSON; - } - if ( - ((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !== - void 0 - ) { - const preload = ((_window as unknown) as WindowWithIconifyPreload) - .IconifyPreload; - const err = 'Invalid IconifyPreload syntax.'; - if (typeof preload === 'object' && preload !== null) { - (preload instanceof Array ? preload : [preload]).forEach((item) => { - try { - if ( - // Check if item is an object and not null/array - typeof item !== 'object' || - item === null || - item instanceof Array || - // Check for 'icons' and 'prefix' - typeof item.icons !== 'object' || - typeof item.prefix !== 'string' || - // Add icon set - !addCollection(item) - ) { - console.error(err); - } - } catch (e) { - console.error(err); - } - }); - } - } - // Set API from global "IconifyProviders" interface WindowWithIconifyProviders { IconifyProviders: Record; @@ -469,13 +214,6 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') { } } } - - // Load observer - browserModules.observer = observer; - setTimeout(() => { - // Init on next tick when entire document has been parsed - observer.init(scanDOM); - }); } export default Iconify; diff --git a/packages/iconify/src/iconify.without-api.ts b/packages/iconify/src/iconify.without-api.ts index b84b1b2..02a494f 100644 --- a/packages/iconify/src/iconify.without-api.ts +++ b/packages/iconify/src/iconify.without-api.ts @@ -1,54 +1,19 @@ // Core import { IconifyJSON } from '@iconify/types'; -import { merge } from '@iconify/core/lib/misc/merge'; -import { - stringToIcon, - validateIcon, - IconifyIconName, -} from '@iconify/core/lib/icon/name'; -import { IconifyIcon, FullIconifyIcon } from '@iconify/core/lib/icon'; +import { IconifyIconName } from '@iconify/core/lib/icon/name'; +import { IconifyIcon } from '@iconify/core/lib/icon'; import { IconifyIconCustomisations, - fullCustomisations, IconifyIconSize, IconifyHorizontalIconAlignment, IconifyVerticalIconAlignment, } from '@iconify/core/lib/customisations'; -import { - getStorage, - getIcon, - addIcon, - addIconSet, - listStoredProviders, - listStoredPrefixes, -} from '@iconify/core/lib/storage'; -import { iconToSVG, IconifyIconBuildResult } from '@iconify/core/lib/builder'; -import { replaceIDs } from '@iconify/core/lib/builder/ids'; +import { IconifyIconBuildResult } from '@iconify/core/lib/builder'; import { calcSize } from '@iconify/core/lib/builder/calc-size'; -// Modules -import { browserModules } from './modules'; - -// Finders -import { addFinder } from './finder'; -import { finder as iconifyFinder } from './finders/iconify'; -// import { finder as iconifyIconFinder } from './finders/iconify-icon'; - -// Observer -import { IconifyObserver } from './observer'; -import { observer } from './observer/observer'; - -// Render -import { IconifyRenderer } from './renderer'; -import { renderIcon } from './renderer/render'; - -// Scan -import { IconifyScanner } from './scanner'; -import { scanDOM } from './scanner/scan'; - -// Other +// Local code import { IconifyExposedCommonInternals } from './internals'; -import { IconifyGlobalCommon } from './common'; +import { IconifyGlobal as IconifyGlobal1, IconifyCommon } from './common'; /** * Export required types @@ -78,275 +43,37 @@ export interface IconifyExposedInternals extends IconifyExposedCommonInternals {} /** - * Iconify interface + * Exported functions */ -export interface IconifyGlobal - extends IconifyGlobalCommon, - IconifyScanner, - IconifyObserver, - IconifyRenderer { +export interface IconifyGlobal2 { /** * Expose internal functions */ _internal: IconifyExposedInternals; } +/** + * Iconify interface + */ +export interface IconifyGlobal extends IconifyGlobal1, IconifyGlobal2 {} + // Export dependencies -export { IconifyObserver, IconifyScanner, IconifyRenderer }; - -/** - * Get icon name - */ -function getIconName(name: string): IconifyIconName | null { - const icon = stringToIcon(name); - if (!validateIcon(icon)) { - return null; - } - return icon; -} - -/** - * Get icon data - */ -function getIconData(name: string): FullIconifyIcon | null { - const icon = getIconName(name); - return icon - ? getIcon(getStorage(icon.provider, icon.prefix), icon.name) - : null; -} - -/** - * Get SVG data - */ -function buildIcon( - name: string, - customisations: IconifyIconCustomisations -): IconifyIconBuildResult | null { - // Get icon data - const iconData = getIconData(name); - if (!iconData) { - return null; - } - - // Clean up customisations - const changes = fullCustomisations(customisations); - - // Get data - return iconToSVG(iconData, changes); -} - -/** - * Generate icon - */ -function generateIcon( - name: string, - customisations: IconifyIconCustomisations, - returnString: boolean -): SVGElement | string | null { - // Get icon data - const iconData = getIconData(name); - if (!iconData) { - return null; - } - - // Split name - const iconName = stringToIcon(name); - - // Clean up customisations - const changes = fullCustomisations(customisations); - - // Get data - return (renderIcon( - { - name: iconName, - }, - changes, - iconData, - returnString - ) as unknown) as SVGElement | string | null; -} - -/** - * Add icon set - */ -function addCollection(data: IconifyJSON, provider?: string) { - if (typeof provider !== 'string') { - provider = typeof data.provider === 'string' ? data.provider : ''; - } - - if ( - typeof data !== 'object' || - typeof data.prefix !== 'string' || - !validateIcon({ - provider, - prefix: data.prefix, - name: 'a', - }) - ) { - return false; - } - - const storage = getStorage(provider, data.prefix); - return !!addIconSet(storage, data); -} +export { IconifyGlobal as IconifyGlobalCommon }; /** * Global variable */ -const Iconify: IconifyGlobal = { - // Version - getVersion: () => '__iconify_version__', - - // Check if icon exists - iconExists: (name) => getIconData(name) !== null, - - // Get raw icon data - getIcon: (name) => { - const result = getIconData(name); - return result ? merge(result) : null; - }, - - // List icons - listIcons: (provider?: string, prefix?: string) => { - let icons = []; - - // Get providers - let providers: string[]; - if (typeof provider === 'string') { - providers = [provider]; - } else { - providers = listStoredProviders(); - } - - // Get all icons - providers.forEach((provider) => { - let prefixes: string[]; - - if (typeof prefix === 'string') { - prefixes = [prefix]; - } else { - prefixes = listStoredPrefixes(provider); - } - - prefixes.forEach((prefix) => { - const storage = getStorage(provider, prefix); - let icons = Object.keys(storage.icons).map( - (name) => - (provider !== '' ? '@' + provider + ':' : '') + - prefix + - ':' + - name - ); - icons = icons.concat(icons); - }); - }); - - return icons; - }, - - // Render SVG - renderSVG: (name: string, customisations: IconifyIconCustomisations) => { - return generateIcon(name, customisations, false) as SVGElement | null; - }, - - renderHTML: (name: string, customisations: IconifyIconCustomisations) => { - return generateIcon(name, customisations, true) as string | null; - }, - - // Get rendered icon as object that can be used to create SVG (use replaceIDs on body) - renderIcon: buildIcon, - - // Replace IDs in body - replaceIDs: replaceIDs, - - // Add icon - addIcon: (name, data) => { - const icon = getIconName(name); - if (!icon) { - return false; - } - const storage = getStorage(icon.provider, icon.prefix); - return addIcon(storage, icon.name, data); - }, - - // Add icon set - addCollection: addCollection, - - // Scan DOM - scanDOM: scanDOM, - - // Set root node - setRoot: (root: HTMLElement) => { - browserModules.root = root; - - // Restart observer - observer.init(scanDOM); - - // Scan DOM on next tick - setTimeout(scanDOM); - }, - - // Observer - pauseObserver: observer.pause, - resumeObserver: observer.resume, - +const Iconify: IconifyGlobal = ({ // Exposed internal functions _internal: { // Calculate size calculateSize: calcSize, }, -}; +} as IconifyGlobal2) as IconifyGlobal; -/** - * Initialise stuff - */ -if (typeof document !== 'undefined' && typeof window !== 'undefined') { - // Add finder modules - // addFinder(iconifyIconFinder); - addFinder(iconifyFinder); - - const _window = window; - - // Load icons from global "IconifyPreload" - interface WindowWithIconifyPreload { - IconifyPreload: IconifyJSON[] | IconifyJSON; - } - if ( - ((_window as unknown) as WindowWithIconifyPreload).IconifyPreload !== - void 0 - ) { - const preload = ((_window as unknown) as WindowWithIconifyPreload) - .IconifyPreload; - const err = 'Invalid IconifyPreload syntax.'; - if (typeof preload === 'object' && preload !== null) { - (preload instanceof Array ? preload : [preload]).forEach((item) => { - try { - if ( - // Check if item is an object and not null/array - typeof item !== 'object' || - item === null || - item instanceof Array || - // Check for 'icons' and 'prefix' - typeof item.icons !== 'object' || - typeof item.prefix !== 'string' || - // Add icon set - !addCollection(item) - ) { - console.error(err); - } - } catch (e) { - console.error(err); - } - }); - } - } - - // Load observer - browserModules.observer = observer; - setTimeout(() => { - // Init on next tick when entire document has been parsed - observer.init(scanDOM); - }); +// Merge with common functions +for (const key in IconifyCommon) { + Iconify[key] = IconifyCommon[key]; } export default Iconify; diff --git a/packages/iconify/src/interfaces/observer.ts b/packages/iconify/src/interfaces/observer.ts deleted file mode 100644 index 2eb59ad..0000000 --- a/packages/iconify/src/interfaces/observer.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Observer callback function - */ -export type ObserverCallback = (root: HTMLElement) => void; - -/** - * Observer functions - */ -type InitObserver = (callback: ObserverCallback) => void; -type PauseObserver = () => void; -type ResumeObserver = () => void; -type IsObserverPaused = () => boolean; - -/** - * Observer functions - */ -export interface Observer { - init: InitObserver; - pause: PauseObserver; - resume: ResumeObserver; - isPaused: IsObserverPaused; -} diff --git a/packages/iconify/src/modules.ts b/packages/iconify/src/modules.ts deleted file mode 100644 index 0b4c0f1..0000000 --- a/packages/iconify/src/modules.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Observer } from './interfaces/observer'; - -/** - * Dynamic modules. - * - * Also see modules.ts in core package. - */ -interface Modules { - // Root element - root?: HTMLElement; - - // Observer module - observer?: Observer; -} - -export const browserModules: Modules = {}; - -/** - * Get root element - */ -export function getRoot(): HTMLElement { - return browserModules.root - ? browserModules.root - : (document.querySelector('body') as HTMLElement); -} diff --git a/packages/iconify/src/api/index.ts b/packages/iconify/src/modules/api.ts similarity index 100% rename from packages/iconify/src/api/index.ts rename to packages/iconify/src/modules/api.ts diff --git a/packages/iconify/src/element.ts b/packages/iconify/src/modules/element.ts similarity index 95% rename from packages/iconify/src/element.ts rename to packages/iconify/src/modules/element.ts index ed5c12c..3a51154 100644 --- a/packages/iconify/src/element.ts +++ b/packages/iconify/src/modules/element.ts @@ -1,6 +1,6 @@ import { IconifyIconName } from '@iconify/core/lib/icon/name'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; -import { IconifyFinder } from './interfaces/finder'; +import { IconifyFinder } from '../finders/interface'; /** * Icon status diff --git a/packages/iconify/src/finder.ts b/packages/iconify/src/modules/finder.ts similarity index 98% rename from packages/iconify/src/finder.ts rename to packages/iconify/src/modules/finder.ts index 3e10b0d..ad2d45e 100644 --- a/packages/iconify/src/finder.ts +++ b/packages/iconify/src/modules/finder.ts @@ -9,7 +9,7 @@ import { validateIcon, } from '@iconify/core/lib/icon/name'; import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; -import { IconifyFinder } from './interfaces/finder'; +import { IconifyFinder } from '../finders/interface'; /** * List of modules diff --git a/packages/iconify/src/observer/observer.ts b/packages/iconify/src/modules/observer.ts similarity index 60% rename from packages/iconify/src/observer/observer.ts rename to packages/iconify/src/modules/observer.ts index 9be90e6..7dffba6 100644 --- a/packages/iconify/src/observer/observer.ts +++ b/packages/iconify/src/modules/observer.ts @@ -1,12 +1,16 @@ -import { elementFinderProperty, IconifyElement } from '../element'; -import { ObserverCallback, Observer } from '../interfaces/observer'; -import { getRoot } from '../modules'; +import { elementFinderProperty, IconifyElement } from './element'; +import { getRoot } from './root'; /** * MutationObserver instance, null until DOM is ready */ let instance: MutationObserver | null = null; +/** + * Observer callback function + */ +export type ObserverCallback = (root: HTMLElement) => void; + /** * Callback */ @@ -110,68 +114,68 @@ interface OldIEElement extends HTMLElement { /** * Export module */ -export const observer: Observer = { - /** - * Start observer when DOM is ready - */ - init: (cb: ObserverCallback): void => { - callback = cb; +/** + * Start observer when DOM is ready + */ +export function initObserver(cb: ObserverCallback): void { + callback = cb; - if (instance && !paused) { - // Restart observer - instance.disconnect(); - observe(); - return; - } - - setTimeout(() => { - const doc = document; - if ( - doc.readyState === 'complete' || - (doc.readyState !== 'loading' && - !(doc.documentElement as OldIEElement).doScroll) - ) { - startObserver(); - } else { - doc.addEventListener('DOMContentLoaded', startObserver); - window.addEventListener('load', startObserver); - } - }); - }, - - /** - * Pause observer - */ - pause: (): void => { - paused++; - if (paused > 1 || instance === null) { - return; - } - - // Check pending records, stop observer - checkMutations(instance.takeRecords()); + if (instance && !paused) { + // Restart observer instance.disconnect(); - }, + observe(); + return; + } - /** - * Resume observer - */ - resume: (): void => { - if (!paused) { - return; + setTimeout(() => { + const doc = document; + if ( + doc.readyState === 'complete' || + (doc.readyState !== 'loading' && + !(doc.documentElement as OldIEElement).doScroll) + ) { + startObserver(); + } else { + doc.addEventListener('DOMContentLoaded', startObserver); + window.addEventListener('load', startObserver); } - paused--; + }); +} - if (!paused && instance) { - observe(); - if (scanPending) { - queueScan(); - } +/** + * Pause observer + */ +export function pauseObserver(): void { + paused++; + if (paused > 1 || instance === null) { + return; + } + + // Check pending records, stop observer + checkMutations(instance.takeRecords()); + instance.disconnect(); +} + +/** + * Resume observer + */ +export function resumeObserver(): void { + if (!paused) { + return; + } + paused--; + + if (!paused && instance) { + observe(); + if (scanPending) { + queueScan(); } - }, + } +} - /** - * Check if observer is paused - */ - isPaused: (): boolean => paused > 0, -}; +/** + * Check if observer is paused + */ +export function isObserverPaused(): boolean { + return paused > 0; +} diff --git a/packages/iconify/src/renderer/render.ts b/packages/iconify/src/modules/render.ts similarity index 98% rename from packages/iconify/src/renderer/render.ts rename to packages/iconify/src/modules/render.ts index ba6dfc8..b9bc316 100644 --- a/packages/iconify/src/renderer/render.ts +++ b/packages/iconify/src/modules/render.ts @@ -5,13 +5,13 @@ import { } from '@iconify/core/lib/customisations'; import { iconToSVG } from '@iconify/core/lib/builder'; import { replaceIDs } from '@iconify/core/lib/builder/ids'; -import { PlaceholderElement } from '../finder'; +import { PlaceholderElement } from './finder'; import { IconifyElement, IconifyElementData, elementDataProperty, elementFinderProperty, -} from '../element'; +} from './element'; /** * Replace element with SVG diff --git a/packages/iconify/src/modules/root.ts b/packages/iconify/src/modules/root.ts new file mode 100644 index 0000000..e325bf4 --- /dev/null +++ b/packages/iconify/src/modules/root.ts @@ -0,0 +1,16 @@ +// Root element +let root: HTMLElement; + +/** + * Get root element + */ +export function getRoot(): HTMLElement { + return root ? root : (document.querySelector('body') as HTMLElement); +} + +/** + * Set root element + */ +export function setRoot(node: HTMLElement): void { + root = node; +} diff --git a/packages/iconify/src/scanner/scan.ts b/packages/iconify/src/modules/scanner.ts similarity index 90% rename from packages/iconify/src/scanner/scan.ts rename to packages/iconify/src/modules/scanner.ts index c4372c2..f3c28cf 100644 --- a/packages/iconify/src/scanner/scan.ts +++ b/packages/iconify/src/modules/scanner.ts @@ -2,10 +2,11 @@ import { IconifyIconName } from '@iconify/core/lib/icon/name'; import { getStorage, getIcon } from '@iconify/core/lib/storage'; import { coreModules } from '@iconify/core/lib/modules'; import { FullIconifyIcon } from '@iconify/core/lib/icon'; -import { findPlaceholders } from '../finder'; -import { browserModules, getRoot } from '../modules'; -import { IconifyElementData, elementDataProperty } from '../element'; -import { renderIcon } from '../renderer/render'; +import { findPlaceholders } from './finder'; +import { IconifyElementData, elementDataProperty } from './element'; +import { renderIcon } from './render'; +import { pauseObserver, resumeObserver } from './observer'; +import { getRoot } from './root'; /** * Flag to avoid scanning DOM too often @@ -93,8 +94,8 @@ export function scanDOM(root?: HTMLElement): void { const storage = getStorage(provider, prefix); if (storage.icons[name] !== void 0) { // Icon exists - replace placeholder - if (browserModules.observer && !paused) { - browserModules.observer.pause(); + if (!paused) { + pauseObserver(); paused = true; } @@ -169,7 +170,7 @@ export function scanDOM(root?: HTMLElement): void { }); } - if (browserModules.observer && paused) { - browserModules.observer.resume(); + if (paused) { + resumeObserver(); } } diff --git a/packages/iconify/src/observer/index.ts b/packages/iconify/src/observer/index.ts deleted file mode 100644 index 70f3180..0000000 --- a/packages/iconify/src/observer/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Iconify interface - */ -export interface IconifyObserver { - /** - * Pause DOM observer - */ - pauseObserver: () => void; - - /** - * Resume DOM observer - */ - resumeObserver: () => void; -} diff --git a/packages/iconify/src/renderer/index.ts b/packages/iconify/src/renderer/index.ts deleted file mode 100644 index edf4f63..0000000 --- a/packages/iconify/src/renderer/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { IconifyIconCustomisations } from '@iconify/core/lib/customisations'; -import { IconifyIconBuildResult } from '@iconify/core/lib/builder'; - -/** - * Iconify interface - */ -export interface IconifyRenderer { - /** - * Render icons - */ - renderSVG: ( - name: string, - customisations: IconifyIconCustomisations - ) => SVGElement | null; - - renderHTML: ( - name: string, - customisations: IconifyIconCustomisations - ) => string | null; - - /** - * Get icon data - */ - renderIcon: ( - name: string, - customisations: IconifyIconCustomisations - ) => IconifyIconBuildResult | null; - - /** - * Replace IDs in icon body, should be used when parsing buildIcon() result - */ - replaceIDs: (body: string) => string; -} diff --git a/packages/iconify/src/scanner/index.ts b/packages/iconify/src/scanner/index.ts deleted file mode 100644 index 9c170fd..0000000 --- a/packages/iconify/src/scanner/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Iconify interface - */ -export interface IconifyScanner { - /** - * Scan DOM - */ - scanDOM: (root?: HTMLElement) => void; - - /** - * Set root node - */ - setRoot: (root: HTMLElement) => void; -}