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;
-}