2
0
mirror of https://github.com/iconify/iconify.git synced 2025-02-15 01:41:37 +00:00

Refactor SVG framework: use ES modules, generate ES module, use Jest for testing

This commit is contained in:
Vjacheslav Trushkin 2021-09-24 19:03:49 +03:00
parent a77c89a545
commit dfec3add9f
20 changed files with 429 additions and 187 deletions

View File

@ -0,0 +1,3 @@
lib
dist
tests-compiled

View File

@ -5,7 +5,8 @@
"@iconify/types", "@iconify/types",
"@iconify/core", "@iconify/core",
"@iconify/utils", "@iconify/utils",
"@cyberalien/redundancy" "@cyberalien/redundancy",
"@iconify/api-redundancy"
], ],
"compiler": {}, "compiler": {},
"apiReport": { "apiReport": {

View File

@ -5,7 +5,8 @@
"@iconify/types", "@iconify/types",
"@iconify/core", "@iconify/core",
"@iconify/utils", "@iconify/utils",
"@cyberalien/redundancy" "@cyberalien/redundancy",
"@iconify/api-redundancy"
], ],
"compiler": {}, "compiler": {},
"apiReport": { "apiReport": {

View File

@ -5,7 +5,8 @@
"@iconify/types", "@iconify/types",
"@iconify/core", "@iconify/core",
"@iconify/utils", "@iconify/utils",
"@cyberalien/redundancy" "@cyberalien/redundancy",
"@iconify/api-redundancy"
], ],
"compiler": {}, "compiler": {},
"apiReport": { "apiReport": {

View File

@ -1,3 +1,4 @@
/* eslint-disable */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const child_process = require('child_process'); const child_process = require('child_process');

View File

@ -23,6 +23,7 @@
"@types/jest": "^27.0.2", "@types/jest": "^27.0.2",
"@types/node": "^10.17.13", "@types/node": "^10.17.13",
"@typescript-eslint/eslint-plugin": "^4.31.2", "@typescript-eslint/eslint-plugin": "^4.31.2",
"cross-env": "^7.0.3",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"jest": "^27.2.1", "jest": "^27.2.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
@ -2564,6 +2565,24 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true "dev": true
}, },
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.1"
},
"bin": {
"cross-env": "src/bin/cross-env.js",
"cross-env-shell": "src/bin/cross-env-shell.js"
},
"engines": {
"node": ">=10.14",
"npm": ">=6",
"yarn": ">=1"
}
},
"node_modules/cross-fetch": { "node_modules/cross-fetch": {
"version": "3.1.4", "version": "3.1.4",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz",
@ -9451,6 +9470,15 @@
} }
} }
}, },
"cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.1"
}
},
"cross-fetch": { "cross-fetch": {
"version": "3.1.4", "version": "3.1.4",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz",

View File

@ -26,7 +26,9 @@
"build:api": "api-extractor run --local --verbose", "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", "build:api2min": "api-extractor run --local --config api-extractor.without-api.min.json",
"test": "jest --runInBand" "test:jest": "jest --runInBand",
"test:mjs": "cross-env NODE_OPTIONS=--experimental-vm-modules node tests/import-test.mjs",
"test": "npm run test:jest && npm run test:mjs"
}, },
"exports": { "exports": {
"./*": "./*", "./*": "./*",
@ -34,9 +36,17 @@
"require": "./dist/iconify.cjs", "require": "./dist/iconify.cjs",
"import": "./dist/iconify.mjs" "import": "./dist/iconify.mjs"
}, },
"./dist/iconify": {
"require": "./dist/iconify.cjs",
"import": "./dist/iconify.mjs"
},
"./offline": { "./offline": {
"require": "./dist/iconify.without-api.cjs", "require": "./dist/iconify.without-api.cjs",
"import": "./dist/iconify.without-api.mjs" "import": "./dist/iconify.without-api.mjs"
},
"./dist/iconify.without-api": {
"require": "./dist/iconify.without-api.cjs",
"import": "./dist/iconify.without-api.mjs"
} }
}, },
"dependencies": { "dependencies": {
@ -54,6 +64,7 @@
"@types/jest": "^27.0.2", "@types/jest": "^27.0.2",
"@types/node": "^10.17.13", "@types/node": "^10.17.13",
"@typescript-eslint/eslint-plugin": "^4.31.2", "@typescript-eslint/eslint-plugin": "^4.31.2",
"cross-env": "^7.0.3",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"jest": "^27.2.1", "jest": "^27.2.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",

View File

@ -22,32 +22,29 @@ const header = `/**
* @version __iconify_version__ * @version __iconify_version__
*/`; */`;
const footerJS = ` const defaultFooter = `
// Export to window or web worker // Export to window or web worker
try { try {
if (self.Iconify === void 0) { if (self.Iconify === void 0) {
self.Iconify = Iconify; self.Iconify = Iconify;
} }
} catch (err) { } catch (err) {
} }`;
// Export as module const iifeFooter = `
// Export as ES module
if (typeof exports === 'object') { if (typeof exports === 'object') {
try { try {
exports.__esModule = true; exports.__esModule = true;
exports.default = Iconify; exports.default = Iconify;
for (var key in Iconify) {
exports[key] = Iconify[key];
}
} catch (err) { } catch (err) {
} }
}`; }
const footerMJS = ` ${defaultFooter}`;
// Export to window or web worker
try {
if (self.Iconify === void 0) {
self.Iconify = Iconify;
}
} catch (err) {
}`;
// Get replacements // Get replacements
const replacements = { const replacements = {
@ -92,24 +89,30 @@ names.forEach((name) => {
return; return;
} }
// Get export format and footer
let format = ext; let format = ext;
let footer = defaultFooter;
switch (ext) { switch (ext) {
case 'js': case 'js':
format = 'iife'; format = 'iife';
footer = iifeFooter;
break; break;
case 'mjs': case 'mjs':
format = 'es'; format = 'es';
break;
} }
const item = { const item = {
input: `lib/${name}.js`, input: `lib/${name}.js`,
output: [ output: [
{ {
file: `dist/${name}${minify ? '.min' : ''}.${ext}`, file: `dist/${name}${minify ? '.min' : ''}.${ext}`,
format, format,
exports: 'named',
name: global, name: global,
banner: header, banner: header,
footer: ext === 'js' ? footerJS : footerMJS, footer,
}, },
], ],
plugins: [ plugins: [

View File

@ -6,50 +6,21 @@ import {
mergeCustomisations, mergeCustomisations,
} from '@iconify/utils/lib/customisations'; } from '@iconify/utils/lib/customisations';
import { import {
storageFunctions,
getIconData, getIconData,
addCollection,
} from '@iconify/core/lib/storage/functions'; } from '@iconify/core/lib/storage/functions';
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build'; import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
import { iconToSVG } from '@iconify/utils/lib/svg/build'; import { iconToSVG } from '@iconify/utils/lib/svg/build';
import { renderIcon } from './modules/render'; import { renderIconInPlaceholder } from './modules/render';
import { import { initObserver } from './modules/observer';
initObserver,
pauseObserver,
resumeObserver,
observeNode,
removeObservedNode,
} from './modules/observer';
import { scanDOM, scanElement } from './modules/scanner'; import { scanDOM, scanElement } from './modules/scanner';
// Finders // Finders
import { addFinder } from './modules/finder'; import { addFinder } from './modules/finder';
import { finder as iconifyFinder } from './finders/iconify'; import { finder as iconifyFinder } from './finders/iconify';
import { findRootNode, addBodyNode } from './modules/root'; import { addBodyNode } from './modules/root';
// import { finder as iconifyIconFinder } from './finders/iconify-icon'; // import { finder as iconifyIconFinder } from './finders/iconify-icon';
/**
* 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 = mergeCustomisations(
defaults,
typeof customisations === 'object' ? customisations : {}
);
// Get data
return iconToSVG(iconData, changes);
}
/** /**
* Generate icon * Generate icon
*/ */
@ -74,7 +45,7 @@ function generateIcon(
); );
// Get data // Get data
return renderIcon( return renderIconInPlaceholder(
{ {
name: iconName, name: iconName,
}, },
@ -145,67 +116,65 @@ export interface IconifyCommonFunctions {
} }
/** /**
* Global variable * Get version
*/ */
export const commonFunctions: IconifyCommonFunctions = { export function getVersion(): string {
// Version return '__iconify_version__';
getVersion: () => '__iconify_version__', }
// Render SVG /**
renderSVG: (name: string, customisations?: IconifyIconCustomisations) => { * Generate SVG element
return generateIcon(name, customisations, false) as SVGElement | null; */
}, export function renderSVG(
name: string,
customisations?: IconifyIconCustomisations
): SVGElement | null {
return generateIcon(name, customisations, false) as SVGElement | null;
}
renderHTML: (name: string, customisations?: IconifyIconCustomisations) => { /**
return generateIcon(name, customisations, true) as string | null; * Generate SVG as string
}, */
export function renderHTML(
name: string,
customisations?: IconifyIconCustomisations
): string | null {
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, * Get rendered icon as object that can be used to create SVG (use replaceIDs on body)
*/
export function renderIcon(
name: string,
customisations?: IconifyIconCustomisations
): IconifyIconBuildResult | null {
// Get icon data
const iconData = getIconData(name);
if (!iconData) {
return null;
}
// Scan DOM // Clean up customisations
scan: (root?: HTMLElement) => { const changes = mergeCustomisations(
if (root) { defaults,
scanElement(root); typeof customisations === 'object' ? customisations : {}
} else { );
scanDOM();
}
},
// Add root node // Get data
observe: (root: HTMLElement) => { return iconToSVG(iconData, changes);
observeNode(root); }
},
// Remove root node /**
stopObserving: (root: HTMLElement) => { * Scan DOM
removeObservedNode(root); */
}, export function scan(root?: HTMLElement): void {
if (root) {
// Pause observer scanElement(root);
pauseObserver: (root?: HTMLElement) => { } else {
if (root) { scanDOM();
const node = findRootNode(root); }
if (node) { }
pauseObserver(node);
}
} else {
pauseObserver();
}
},
// Resume observer
resumeObserver: (root?: HTMLElement) => {
if (root) {
const node = findRootNode(root);
if (node) {
resumeObserver(node);
}
} else {
resumeObserver();
}
},
};
/** /**
* Initialise stuff * Initialise stuff
@ -239,7 +208,7 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
typeof item.icons !== 'object' || typeof item.icons !== 'object' ||
typeof item.prefix !== 'string' || typeof item.prefix !== 'string' ||
// Add icon set // Add icon set
!storageFunctions.addCollection(item) !addCollection(item)
) { ) {
console.error(err); console.error(err);
} }

View File

@ -9,9 +9,17 @@ import type {
} from '@iconify/utils/lib/customisations'; } from '@iconify/utils/lib/customisations';
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build'; import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
import type { IconifyStorageFunctions } from '@iconify/core/lib/storage/functions'; import type { IconifyStorageFunctions } from '@iconify/core/lib/storage/functions';
import { storageFunctions } from '@iconify/core/lib/storage/functions'; import {
iconExists,
getIcon,
addIcon,
addCollection,
} from '@iconify/core/lib/storage/functions';
import { listIcons } from '@iconify/core/lib/storage/storage';
import type { IconifyBuilderFunctions } from '@iconify/core/lib/builder/functions'; import type { IconifyBuilderFunctions } from '@iconify/core/lib/builder/functions';
import { builderFunctions } from '@iconify/core/lib/builder/functions'; import { buildIcon } from '@iconify/core/lib/builder/functions';
import { replaceIDs } from '@iconify/utils/lib/svg/id';
import { calculateSize } from '@iconify/utils/lib/svg/size';
// Cache // Cache
import { storeCache, loadCache } from '@iconify/core/lib/browser-storage/'; import { storeCache, loadCache } from '@iconify/core/lib/browser-storage/';
@ -30,10 +38,6 @@ import type {
IconifyAPICustomQueryParams, IconifyAPICustomQueryParams,
IconifyAPIMergeQueryParams, IconifyAPIMergeQueryParams,
} from '@iconify/core/lib/api/functions'; } from '@iconify/core/lib/api/functions';
import {
APIFunctions,
APIInternalFunctions,
} from '@iconify/core/lib/api/functions';
import type { import type {
IconifyAPIModule, IconifyAPIModule,
IconifyAPISendQuery, IconifyAPISendQuery,
@ -45,21 +49,34 @@ import type {
IconifyAPIConfig, IconifyAPIConfig,
GetAPIConfig, GetAPIConfig,
} from '@iconify/core/lib/api/config'; } from '@iconify/core/lib/api/config';
import { setAPIConfig } from '@iconify/core/lib/api/config'; import {
addAPIProvider,
getAPIConfig,
listAPIProviders,
} from '@iconify/core/lib/api/config';
import { jsonpAPIModule } from '@iconify/core/lib/api/modules/jsonp'; import { jsonpAPIModule } from '@iconify/core/lib/api/modules/jsonp';
import { import {
fetchAPIModule, fetchAPIModule,
getFetch, getFetch,
setFetch, setFetch as setFetchFunction,
} from '@iconify/core/lib/api/modules/fetch'; } from '@iconify/core/lib/api/modules/fetch';
import type { import type {
IconifyIconLoaderCallback, IconifyIconLoaderCallback,
IconifyIconLoaderAbort, IconifyIconLoaderAbort,
} from '@iconify/core/lib/api/icons'; } from '@iconify/core/lib/api/icons';
import { loadIcons } from '@iconify/core/lib/api/icons';
import { sendAPIQuery } from '@iconify/core/lib/api/query';
import { mergeParams } from '@iconify/core/lib/api/params';
// Other // Other
import type { IconifyCommonFunctions } from './common'; import type { IconifyCommonFunctions } from './common';
import { commonFunctions } from './common'; import { getVersion, renderSVG, renderHTML, renderIcon, scan } from './common';
import {
observe,
stopObserving,
pauseObserver,
resumeObserver,
} from './modules/observer';
/** /**
* Export required types * Export required types
@ -118,36 +135,18 @@ export interface IconifyGlobal
} }
/** /**
* Browser cache functions * Enable cache
*/ */
const browserCacheFunctions: IconifyBrowserCacheFunctions = { function enableCache(storage: IconifyBrowserCacheType, enable?: boolean): void {
// enableCache() has optional second parameter for backwards compatibility toggleBrowserCache(storage, enable !== false);
enableCache: (storage: IconifyBrowserCacheType, enable?: boolean) => }
toggleBrowserCache(storage, enable !== false),
disableCache: (storage: IconifyBrowserCacheType) =>
toggleBrowserCache(storage, true),
};
/** /**
* Global variable * Disable cache
*/ */
const Iconify = { function disableCache(storage: IconifyBrowserCacheType): void {
// Exposed internal API functions toggleBrowserCache(storage, true);
_api: APIInternalFunctions, }
} as unknown as IconifyGlobal;
// Add functions
[
storageFunctions,
builderFunctions,
commonFunctions,
browserCacheFunctions,
APIFunctions,
].forEach((list) => {
for (const key in list) {
Iconify[key] = list[key];
}
});
/** /**
* Initialise stuff * Initialise stuff
@ -158,10 +157,10 @@ setAPIModule('', getFetch() ? fetchAPIModule : jsonpAPIModule);
/** /**
* Function to enable node-fetch for getting icons on server side * Function to enable node-fetch for getting icons on server side
*/ */
Iconify._api.setFetch = (nodeFetch: typeof fetch) => { function setFetch(nodeFetch: typeof fetch): void {
setFetch(nodeFetch); setFetchFunction(nodeFetch);
setAPIModule('', fetchAPIModule); setAPIModule('', fetchAPIModule);
}; }
/** /**
* Browser stuff * Browser stuff
@ -191,7 +190,7 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
) { ) {
continue; continue;
} }
if (!setAPIConfig(key, value)) { if (!addAPIProvider(key, value)) {
console.error(err); console.error(err);
} }
} catch (e) { } catch (e) {
@ -202,4 +201,89 @@ if (typeof document !== 'undefined' && typeof window !== 'undefined') {
} }
} }
/**
* Internal API
*/
const _api: IconifyAPIInternalFunctions = {
getAPIConfig,
setAPIModule,
sendAPIQuery,
setFetch,
listAPIProviders,
mergeParams,
};
/**
* Global variable
*/
const Iconify: IconifyGlobal = {
// IconifyAPIInternalFunctions
_api,
// IconifyAPIFunctions
addAPIProvider,
loadIcons,
// IconifyStorageFunctions
iconExists,
getIcon,
listIcons,
addIcon,
addCollection,
// IconifyBuilderFunctions
replaceIDs,
calculateSize,
buildIcon,
// IconifyCommonFunctions
getVersion,
renderSVG,
renderHTML,
renderIcon,
scan,
observe,
stopObserving,
pauseObserver,
resumeObserver,
// IconifyBrowserCacheFunctions
enableCache,
disableCache,
};
/**
* Default export
*/
export default Iconify; export default Iconify;
/**
* Named exports
*/
// IconifyAPIInternalFunctions
export { _api };
// IconifyAPIFunctions
export { addAPIProvider, loadIcons };
// IconifyStorageFunctions
export { iconExists, getIcon, listIcons, addIcon, addCollection };
// IconifyBuilderFunctions
export { replaceIDs, calculateSize, buildIcon };
// IconifyCommonFunctions
export {
getVersion,
renderSVG,
renderHTML,
renderIcon,
scan,
observe,
stopObserving,
pauseObserver,
resumeObserver,
};
// IconifyBrowserCacheFunctions
export { enableCache, disableCache };

View File

@ -9,13 +9,27 @@ import type {
} from '@iconify/utils/lib/customisations'; } from '@iconify/utils/lib/customisations';
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build'; import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
import type { IconifyStorageFunctions } from '@iconify/core/lib/storage/functions'; import type { IconifyStorageFunctions } from '@iconify/core/lib/storage/functions';
import { storageFunctions } from '@iconify/core/lib/storage/functions'; import {
iconExists,
getIcon,
addIcon,
addCollection,
} from '@iconify/core/lib/storage/functions';
import { listIcons } from '@iconify/core/lib/storage/storage';
import type { IconifyBuilderFunctions } from '@iconify/core/lib/builder/functions'; import type { IconifyBuilderFunctions } from '@iconify/core/lib/builder/functions';
import { builderFunctions } from '@iconify/core/lib/builder/functions'; import { buildIcon } from '@iconify/core/lib/builder/functions';
import { replaceIDs } from '@iconify/utils/lib/svg/id';
import { calculateSize } from '@iconify/utils/lib/svg/size';
// Local code // Local code
import type { IconifyCommonFunctions } from './common'; import type { IconifyCommonFunctions } from './common';
import { commonFunctions } from './common'; import { getVersion, renderSVG, renderHTML, renderIcon, scan } from './common';
import {
observe,
stopObserving,
pauseObserver,
resumeObserver,
} from './modules/observer';
/** /**
* Export required types * Export required types
@ -45,19 +59,57 @@ export interface IconifyGlobal
IconifyBuilderFunctions, IconifyBuilderFunctions,
IconifyCommonFunctions {} IconifyCommonFunctions {}
// Export dependencies
export { IconifyGlobal as IconifyGlobalCommon };
/** /**
* Global variable * Global variable
*/ */
const Iconify: IconifyGlobal = {} as IconifyGlobal; const Iconify: IconifyGlobal = {
// IconifyStorageFunctions
iconExists,
getIcon,
listIcons,
addIcon,
addCollection,
// Merge with common functions // IconifyBuilderFunctions
[storageFunctions, builderFunctions, commonFunctions].forEach((list) => { replaceIDs,
for (const key in list) { calculateSize,
Iconify[key] = list[key]; buildIcon,
}
});
// IconifyCommonFunctions
getVersion,
renderSVG,
renderHTML,
renderIcon,
scan,
observe,
stopObserving,
pauseObserver,
resumeObserver,
};
/**
* Default export
*/
export default Iconify; export default Iconify;
/**
* Named exports
*/
// IconifyStorageFunctions
export { iconExists, getIcon, listIcons, addIcon, addCollection };
// IconifyBuilderFunctions
export { replaceIDs, calculateSize, buildIcon };
// IconifyCommonFunctions
export {
getVersion,
renderSVG,
renderHTML,
renderIcon,
scan,
observe,
stopObserving,
pauseObserver,
resumeObserver,
};

View File

@ -79,7 +79,7 @@ function checkMutations(node: ObservedNode, mutations: MutationRecord[]): void {
/** /**
* Start/resume observer * Start/resume observer
*/ */
function observe(node: ObservedNode, root: HTMLElement): void { function continueObserving(node: ObservedNode, root: HTMLElement): void {
node.observer.instance.observe(root, observerParams); node.observer.instance.observe(root, observerParams);
} }
@ -108,7 +108,7 @@ function startObserver(node: ObservedNode): void {
// Create new instance, observe // Create new instance, observe
observer.instance = new MutationObserver(checkMutations.bind(null, node)); observer.instance = new MutationObserver(checkMutations.bind(null, node));
observe(node, root); continueObserving(node, root);
// Scan immediately // Scan immediately
if (!observer.paused) { if (!observer.paused) {
@ -171,9 +171,9 @@ export function initObserver(cb: ObserverCallback): void {
} }
/** /**
* Pause observer * Pause observing node
*/ */
export function pauseObserver(node?: ObservedNode): void { export function pauseObservingNode(node?: ObservedNode): void {
(node ? [node] : listRootNodes()).forEach((node) => { (node ? [node] : listRootNodes()).forEach((node) => {
if (!node.observer) { if (!node.observer) {
node.observer = { node.observer = {
@ -195,10 +195,24 @@ export function pauseObserver(node?: ObservedNode): void {
}); });
} }
/**
* Pause observer
*/
export function pauseObserver(root?: HTMLElement): void {
if (root) {
const node = findRootNode(root);
if (node) {
pauseObservingNode(node);
}
} else {
pauseObservingNode();
}
}
/** /**
* Resume observer * Resume observer
*/ */
export function resumeObserver(observer?: ObservedNode): void { export function resumeObservingNode(observer?: ObservedNode): void {
(observer ? [observer] : listRootNodes()).forEach((node) => { (observer ? [observer] : listRootNodes()).forEach((node) => {
if (!node.observer) { if (!node.observer) {
// Start observer // Start observer
@ -218,7 +232,7 @@ export function resumeObserver(observer?: ObservedNode): void {
if (!root) { if (!root) {
return; return;
} else if (observer.instance) { } else if (observer.instance) {
observe(node, root); continueObserving(node, root);
} else { } else {
startObserver(node); startObserver(node);
} }
@ -227,13 +241,24 @@ export function resumeObserver(observer?: ObservedNode): void {
}); });
} }
/**
* Resume observer
*/
export function resumeObserver(root?: HTMLElement): void {
if (root) {
const node = findRootNode(root);
if (node) {
resumeObservingNode(node);
}
} else {
resumeObservingNode();
}
}
/** /**
* Observe node * Observe node
*/ */
export function observeNode( export function observe(root: HTMLElement, autoRemove = false): ObservedNode {
root: HTMLElement,
autoRemove = false
): ObservedNode {
const node = addRootNode(root, autoRemove); const node = addRootNode(root, autoRemove);
startObserver(node); startObserver(node);
return node; return node;
@ -242,7 +267,7 @@ export function observeNode(
/** /**
* Remove observed node * Remove observed node
*/ */
export function removeObservedNode(root: HTMLElement): void { export function stopObserving(root: HTMLElement): void {
const node = findRootNode(root); const node = findRootNode(root);
if (node) { if (node) {
stopObserver(node); stopObserver(node);

View File

@ -13,7 +13,7 @@ import { elementDataProperty, elementFinderProperty } from './element';
/** /**
* Replace element with SVG * Replace element with SVG
*/ */
export function renderIcon( export function renderIconInPlaceholder(
placeholder: PlaceholderElement, placeholder: PlaceholderElement,
customisations: IconifyIconCustomisations, customisations: IconifyIconCustomisations,
iconData: FullIconifyIcon, iconData: FullIconifyIcon,

View File

@ -1,17 +1,20 @@
import type { IconifyIconName } from '@iconify/utils/lib/icon/name'; import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
import { getStorage, getIcon } from '@iconify/core/lib/storage/storage'; import {
getStorage,
getIconFromStorage,
} from '@iconify/core/lib/storage/storage';
import { isPending, loadIcons } from '@iconify/core/lib/api/icons'; import { isPending, loadIcons } from '@iconify/core/lib/api/icons';
import type { FullIconifyIcon } from '@iconify/utils/lib/icon'; import type { FullIconifyIcon } from '@iconify/utils/lib/icon';
import { findPlaceholders } from './finder'; import { findPlaceholders } from './finder';
import type { IconifyElementData } from './element'; import type { IconifyElementData } from './element';
import { elementDataProperty } from './element'; import { elementDataProperty } from './element';
import { renderIcon } from './render'; import { renderIconInPlaceholder } from './render';
import type { ObservedNode } from './observed-node'; import type { ObservedNode } from './observed-node';
import { import {
pauseObserver, pauseObservingNode,
resumeObserver, resumeObservingNode,
removeObservedNode, stopObserving,
observeNode, observe,
} from './observer'; } from './observer';
import { findRootNode, listRootNodes } from './root'; import { findRootNode, listRootNodes } from './root';
@ -133,7 +136,7 @@ export function scanDOM(node?: ObservedNode, addTempNode = false): void {
if (storage.icons[name] !== void 0) { if (storage.icons[name] !== void 0) {
// Icon exists - pause observer before replacing placeholder // Icon exists - pause observer before replacing placeholder
if (!paused && node.observer) { if (!paused && node.observer) {
pauseObserver(node); pauseObservingNode(node);
paused = true; paused = true;
} }
@ -144,10 +147,10 @@ export function scanDOM(node?: ObservedNode, addTempNode = false): void {
: item.finder.customisations(element); : item.finder.customisations(element);
// Render icon // Render icon
renderIcon( renderIconInPlaceholder(
item, item,
customisations, customisations,
getIcon(storage, name) as FullIconifyIcon getIconFromStorage(storage, name) as FullIconifyIcon
); );
return; return;
@ -189,13 +192,13 @@ export function scanDOM(node?: ObservedNode, addTempNode = false): void {
// Node stuff // Node stuff
if (node.temporary && !hasPlaceholders) { if (node.temporary && !hasPlaceholders) {
// Remove temporary node // Remove temporary node
removeObservedNode(root); stopObserving(root);
} else if (addTempNode && hasPlaceholders) { } else if (addTempNode && hasPlaceholders) {
// Add new temporary node // Add new temporary node
observeNode(root, true); observe(root, true);
} else if (paused && node.observer) { } else if (paused && node.observer) {
// Resume observer // Resume observer
resumeObserver(node); resumeObservingNode(node);
} }
}); });

View File

@ -1,4 +1,4 @@
import Iconify from '../dist/iconify'; import Iconify from '../';
describe('Testing Iconify API functions with Node.js', () => { describe('Testing Iconify API functions with Node.js', () => {
it('Cache functions', () => { it('Cache functions', () => {

View File

@ -0,0 +1,60 @@
// Main file: default and named imports
import Iconify from '@iconify/iconify';
import { addIcon } from '@iconify/iconify';
// Named import from .mjs
import { loadIcons } from '../dist/iconify.mjs';
// Shortcut for offline module
import IconifyOffline from '@iconify/iconify/offline';
import { iconExists } from '@iconify/iconify/offline';
// Direct link to offline module
import { addCollection } from '../dist/iconify.without-api.mjs';
/**
* Simple assertion function
*/
function test(value, expected, message) {
if (value !== expected) {
console.error(
'❌',
message + `: expected ${value} to equal ${expected}`
);
process.exit(1);
}
console.log('✓', message);
}
/**
* Test default export
*/
test(typeof Iconify, 'object', 'Testing default export');
test(typeof Iconify.addIcon, 'function', 'Testing addIcon in default export');
/**
* Test default export in offline module
*/
test(typeof IconifyOffline, 'object', 'Testing default offline export');
test(
typeof IconifyOffline.iconExists,
'function',
'Testing iconExists in default offline export'
);
test(
typeof IconifyOffline.loadIcons,
'undefined',
'Testing loadIcons in default offline export'
);
/**
* Test named exports
*/
test(typeof addIcon, 'function', 'Testing addIcon named export');
test(typeof loadIcons, 'function', 'Testing loadIcons named export');
/**
* Test exports without API
*/
test(typeof iconExists, 'function', 'Testing iconExists named export');
test(typeof addCollection, 'function', 'Testing addCollection named export');

View File

@ -1,4 +1,4 @@
import Iconify, { IconifyIconName } from '../dist/iconify'; import Iconify, { IconifyIconName } from '../';
import { mockAPIModule, mockAPIData } from '@iconify/core/lib/api/modules/mock'; import { mockAPIModule, mockAPIData } from '@iconify/core/lib/api/modules/mock';
// API provider and prefix for test // API provider and prefix for test

View File

@ -1,4 +1,4 @@
import Iconify from '../dist/iconify'; import Iconify from '../';
describe('Testing Iconify observer functions with Node.js', () => { describe('Testing Iconify observer functions with Node.js', () => {
it('Observer functions', () => { it('Observer functions', () => {

View File

@ -1,4 +1,4 @@
import Iconify, { IconifyIconBuildResult } from '../dist/iconify'; import Iconify, { IconifyIconBuildResult } from '../';
describe('Testing Iconify render functions with Node.js', () => { describe('Testing Iconify render functions with Node.js', () => {
const prefix = 'node-test-render'; const prefix = 'node-test-render';

View File

@ -1,6 +1,6 @@
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import { dirname } from 'path'; import { dirname } from 'path';
import Iconify, { IconifyIcon } from '../dist/iconify'; import Iconify, { IconifyIcon } from '../';
describe('Testing Iconify with Node.js', () => { describe('Testing Iconify with Node.js', () => {
it('Basic functions', () => { it('Basic functions', () => {