2
0
mirror of https://github.com/iconify/iconify.git synced 2025-01-05 23:10:40 +00:00
iconify/packages/iconify/src/iconify.ts

557 lines
11 KiB
TypeScript
Raw Normal View History

2020-04-28 09:47:35 +00:00
// 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 {
IconifyIconCustomisations,
fullCustomisations,
IconifyIconSize,
IconifyHorizontalIconAlignment,
IconifyVerticalIconAlignment,
} from '@iconify/core/lib/customisations';
import {
getStorage,
getIcon,
addIcon,
addIconSet,
listStoredProviders,
2020-04-28 09:47:35 +00:00
listStoredPrefixes,
} from '@iconify/core/lib/storage';
import { iconToSVG, IconifyIconBuildResult } from '@iconify/core/lib/builder';
import { replaceIDs } from '@iconify/core/lib/builder/ids';
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 {
API,
getRedundancyCache,
IconifyAPIInternalStorage,
} from '@iconify/core/lib/api/';
import { setAPIModule } from '@iconify/core/lib/api/modules';
import {
setAPIConfig,
PartialIconifyAPIConfig,
IconifyAPIConfig,
} from '@iconify/core/lib/api/config';
2020-04-28 09:47:35 +00:00
import { prepareQuery, sendQuery } from './modules/api-jsonp';
2020-04-28 14:35:35 +00:00
import {
IconifyIconLoaderCallback,
IconifyIconLoaderAbort,
} from '@iconify/core/lib/interfaces/loader';
2020-04-28 09:47:35 +00:00
// Observer
import { observer } from './modules/observer';
2020-04-28 14:35:35 +00:00
// Render
import { renderIcon } from './render';
2020-04-28 09:47:35 +00:00
// Scan
import { scanDOM } from './scan';
/**
* Export required types
*/
// JSON stuff
export { IconifyIcon, IconifyJSON };
// Customisations
export {
IconifyIconCustomisations,
IconifyIconSize,
IconifyHorizontalIconAlignment,
IconifyVerticalIconAlignment,
};
// Build
export { IconifyIconBuildResult };
// API
export {
IconifyAPIConfig,
IconifyIconLoaderCallback,
IconifyIconLoaderAbort,
IconifyAPIInternalStorage,
};
2020-04-28 09:47:35 +00:00
/**
* Cache types
*/
export type IconifyCacheType = 'local' | 'session' | 'all';
/**
* Exposed internal functions
*
* Used by plug-ins, such as Icon Finder
*
* Important: any changes published in a release must be backwards compatible.
*/
export interface IconifyExposedInternals {
/**
* Calculate width knowing height and width/height ratio (or vice versa)
*/
calculateSize: (
size: IconifyIconSize,
ratio: number,
precision?: number
) => IconifyIconSize;
/**
* Get internal API data, used by Icon Finder
*/
getAPI: (provider: string) => IconifyAPIInternalStorage | undefined;
}
2020-04-28 09:47:35 +00:00
/**
* Iconify interface
*/
export interface IconifyGlobal {
/* General section */
/**
* Get version
*/
getVersion: () => string;
/* Getting icons */
/**
* Check if icon exists
*/
iconExists: (name: string) => boolean;
/**
* Get icon data with all properties
*/
getIcon: (name: string) => IconifyIcon | null;
/**
* List all available icons
*/
listIcons: (provider?: string, prefix?: string) => string[];
2020-04-28 09:47:35 +00:00
2020-04-28 14:35:35 +00:00
/**
* Load icons
*/
loadIcons: (
icons: (IconifyIconName | string)[],
callback?: IconifyIconLoaderCallback
) => IconifyIconLoaderAbort;
2020-04-28 09:47:35 +00:00
/* Rendering icons */
2020-04-28 14:35:35 +00:00
renderSVG: (
name: string,
customisations: IconifyIconCustomisations
) => SVGElement | null;
renderHTML: (
name: string,
customisations: IconifyIconCustomisations
) => string | null;
2020-04-28 09:47:35 +00:00
/**
* Get icon data
*/
renderIcon: (
name: string,
customisations: IconifyIconCustomisations
) => IconifyIconBuildResult | null;
/**
2020-04-28 14:35:35 +00:00
* Replace IDs in icon body, should be used when parsing buildIcon() result
2020-04-28 09:47:35 +00:00
*/
replaceIDs: (body: string) => string;
/* Add icons */
/**
* Add icon to storage
*/
addIcon: (name: string, data: IconifyIcon) => boolean;
/**
* Add icon set to storage
*/
addCollection: (data: IconifyJSON, provider?: string) => boolean;
2020-04-28 09:47:35 +00:00
/* API stuff */
/**
* Pause DOM observer
*/
pauseObserver: () => void;
/**
* Resume DOM observer
*/
resumeObserver: () => void;
/**
* Add API provider
2020-04-28 09:47:35 +00:00
*/
addAPIProvider: (
provider: string,
customConfig: Partial<IconifyAPIConfig>
2020-04-28 09:47:35 +00:00
) => void;
/* Scan DOM */
/**
* Scan DOM
*/
scanDOM: (root?: HTMLElement) => void;
/**
* Set root node
*/
setRoot: (root: HTMLElement) => void;
/**
* Toggle local and session storage
*/
enableCache: (storage: IconifyCacheType, value: boolean) => void;
/**
* Expose internal functions
*/
_internal: IconifyExposedInternals;
2020-04-28 09:47:35 +00:00
}
/**
* 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;
2020-04-28 09:47:35 +00:00
}
/**
* Get SVG data
*/
2020-04-28 14:35:35 +00:00
function buildIcon(
2020-04-28 09:47:35 +00:00
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);
}
2020-04-28 14:35:35 +00:00
/**
* 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') {
2020-06-01 21:54:37 +00:00
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);
}
2020-04-28 09:47:35 +00:00
/**
* Global variable
*/
const Iconify: IconifyGlobal = {
// Version
getVersion: () => '__iconify_version__',
// Check if icon exists
2020-04-28 14:35:35 +00:00
iconExists: (name) => getIconData(name) !== null,
2020-04-28 09:47:35 +00:00
// Get raw icon data
getIcon: (name) => {
const result = getIconData(name);
return result ? merge(result) : null;
},
// List icons
listIcons: (provider?: string, prefix?: string) => {
2020-04-28 09:47:35 +00:00
let icons = [];
// Get providers
let providers: string[];
if (typeof provider === 'string') {
providers = [provider];
} else {
providers = listStoredProviders();
2020-04-28 09:47:35 +00:00
}
// Get all icons
providers.forEach((provider) => {
let prefixes: string[];
if (typeof prefix === 'string') {
prefixes = [prefix];
} else {
prefixes = listStoredPrefixes(provider);
2020-04-28 09:47:35 +00:00
}
prefixes.forEach((prefix) => {
const storage = getStorage(provider, prefix);
let icons = Object.keys(storage.icons).map(
(name) =>
(provider !== '' ? '@' + provider + ':' : '') +
prefix +
':' +
name
);
icons = icons.concat(icons);
});
2020-04-28 09:47:35 +00:00
});
return icons;
},
2020-04-28 14:35:35 +00:00
// 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,
2020-04-28 09:47:35 +00:00
// 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);
2020-04-28 09:47:35 +00:00
return addIcon(storage, icon.name, data);
},
// Add icon set
addCollection: addCollection,
2020-04-28 09:47:35 +00:00
// Pause observer
pauseObserver: observer.pause,
// Resume observer
resumeObserver: observer.resume,
// API providers
addAPIProvider: setAPIConfig,
2020-04-28 09:47:35 +00:00
// 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) {
case 'local':
case 'session':
config[storage] = value;
break;
case 'all':
for (const key in config) {
config[key] = value;
}
break;
}
},
// Exposed internal functions
_internal: {
// Calculate size
calculateSize: calcSize,
// Get API data
getAPI: getRedundancyCache,
},
2020-04-28 09:47:35 +00:00
};
/**
* Initialise stuff
*/
// Set API
coreModules.api = API;
setAPIModule('', {
2020-04-28 09:47:35 +00:00
send: sendQuery,
prepare: prepareQuery,
});
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<string, PartialIconifyAPIConfig>;
}
if (
((_window as unknown) as WindowWithIconifyProviders)
.IconifyProviders !== void 0
) {
const providers = ((_window as unknown) as WindowWithIconifyProviders)
.IconifyProviders;
if (typeof providers === 'object' && providers !== null) {
for (let key in providers) {
const err = 'IconifyProviders[' + key + '] is invalid.';
try {
const value = providers[key];
if (
typeof value !== 'object' ||
!value ||
value.resources === void 0
) {
continue;
}
if (!setAPIConfig(key, value)) {
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);
});
}
2020-04-28 09:47:35 +00:00
export default Iconify;