mirror of
https://github.com/iconify/iconify.git
synced 2024-12-13 14:13:06 +00:00
Add loadIcon function
This commit is contained in:
parent
035d2fe305
commit
bf8d17f97a
@ -14,6 +14,7 @@ import type {
|
||||
IconifyAPICustomQueryParams,
|
||||
} from './modules';
|
||||
import type { MergeParams, IconifyAPIMergeQueryParams } from './params';
|
||||
import type { IconifyIcon } from '@iconify/types';
|
||||
|
||||
/**
|
||||
* Iconify API functions
|
||||
@ -27,6 +28,13 @@ export interface IconifyAPIFunctions {
|
||||
callback?: IconifyIconLoaderCallback
|
||||
) => IconifyIconLoaderAbort;
|
||||
|
||||
/**
|
||||
* Load one icon, using Promise syntax
|
||||
*/
|
||||
loadIcon: (
|
||||
icon: IconifyIconName | string
|
||||
) => Promise<Required<IconifyIcon>>;
|
||||
|
||||
/**
|
||||
* Add API provider
|
||||
*/
|
||||
|
@ -1,13 +1,14 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type {
|
||||
import type { IconifyIcon, IconifyJSON } from '@iconify/types';
|
||||
import {
|
||||
IconifyIconName,
|
||||
IconifyIconSource,
|
||||
stringToIcon,
|
||||
} from '@iconify/utils/lib/icon/name';
|
||||
import type { SortedIcons } from '../icon/sort';
|
||||
import { sortIcons } from '../icon/sort';
|
||||
import { storeCallback, updateCallbacks } from './callbacks';
|
||||
import { getAPIModule } from './modules';
|
||||
import { getStorage, addIconSet } from '../storage/storage';
|
||||
import { getStorage, addIconSet, getIconFromStorage } from '../storage/storage';
|
||||
import { listToIcons } from '../icon/list';
|
||||
import { allowSimpleNames } from '../storage/functions';
|
||||
import { sendAPIQuery } from './query';
|
||||
@ -338,3 +339,36 @@ export const loadIcons: IconifyLoadIcons = (
|
||||
? storeCallback(callback, sortedIcons, sources)
|
||||
: emptyCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache for loadIcon promises
|
||||
*/
|
||||
type LoadIconResult = Promise<Required<IconifyIcon>>;
|
||||
const iconsQueue: Record<string, LoadIconResult> = Object.create(null);
|
||||
|
||||
export const loadIcon = (icon: IconifyIconName | string): LoadIconResult => {
|
||||
if (typeof icon === 'string' && iconsQueue[icon]) {
|
||||
return iconsQueue[icon];
|
||||
}
|
||||
|
||||
const result: LoadIconResult = new Promise((fulfill, reject) => {
|
||||
const iconObj = typeof icon === 'string' ? stringToIcon(icon) : icon;
|
||||
loadIcons([iconObj || icon], (loaded) => {
|
||||
if (loaded.length && iconObj) {
|
||||
const storage = getStorage(iconObj.provider, iconObj.prefix);
|
||||
const data = getIconFromStorage(storage, iconObj.name);
|
||||
if (data) {
|
||||
fulfill(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reject(icon);
|
||||
});
|
||||
});
|
||||
|
||||
if (typeof icon === 'string') {
|
||||
iconsQueue[icon] = result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ import type {
|
||||
IconifyAPIQueryParams,
|
||||
} from '../../lib/api/modules';
|
||||
import { setAPIModule } from '../../lib/api/modules';
|
||||
import { loadIcons, isPending } from '../../lib/api/icons';
|
||||
import { loadIcons, loadIcon, isPending } from '../../lib/api/icons';
|
||||
|
||||
describe('Testing API loadIcons', () => {
|
||||
let prefixCounter = 0;
|
||||
@ -154,6 +154,167 @@ describe('Testing API loadIcons', () => {
|
||||
asyncCounter++;
|
||||
});
|
||||
|
||||
it('Loading one icon with Promise', async () => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
|
||||
// Set config
|
||||
addAPIProvider(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): IconifyAPIIconsQueryParams[] => {
|
||||
const item: IconifyAPIIconsQueryParams = {
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
|
||||
// Test input and return as one item
|
||||
const expected: IconifyAPIIconsQueryParams = {
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon1'],
|
||||
};
|
||||
expect(item).toEqual(expected);
|
||||
|
||||
return [item];
|
||||
};
|
||||
|
||||
const sendQuery = (
|
||||
host: string,
|
||||
params: IconifyAPIQueryParams,
|
||||
item: PendingQueryItem
|
||||
): void => {
|
||||
expect(params.type).toBe('icons');
|
||||
|
||||
// Test input
|
||||
expect(host).toBe('https://api1.local');
|
||||
const expected: IconifyAPIQueryParams = {
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon1'],
|
||||
};
|
||||
expect(params).toEqual(expected);
|
||||
|
||||
// Send data
|
||||
item.done({
|
||||
prefix,
|
||||
icons: {
|
||||
icon1: {
|
||||
body: '<path d="" />',
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
setAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icon
|
||||
await loadIcon(provider + ':' + prefix + ':icon1');
|
||||
|
||||
// Test isPending
|
||||
expect(isPending({ provider, prefix, name: 'icon1' })).toBe(false);
|
||||
});
|
||||
|
||||
it('Loading one icon twice with Promise', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
|
||||
// Set config
|
||||
addAPIProvider(provider, {
|
||||
resources: ['https://api1.local', 'https://api2.local'],
|
||||
});
|
||||
|
||||
// Icon loader
|
||||
const prepareQuery = (
|
||||
provider: string,
|
||||
prefix: string,
|
||||
icons: string[]
|
||||
): IconifyAPIIconsQueryParams[] => {
|
||||
const item: IconifyAPIIconsQueryParams = {
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
icons,
|
||||
};
|
||||
|
||||
// Test input and return as one item
|
||||
const expected: IconifyAPIIconsQueryParams = {
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon1'],
|
||||
};
|
||||
expect(item).toEqual(expected);
|
||||
|
||||
return [item];
|
||||
};
|
||||
|
||||
const sendQuery = (
|
||||
host: string,
|
||||
params: IconifyAPIQueryParams,
|
||||
item: PendingQueryItem
|
||||
): void => {
|
||||
expect(params.type).toBe('icons');
|
||||
|
||||
// Test input
|
||||
expect(host).toBe('https://api1.local');
|
||||
const expected: IconifyAPIQueryParams = {
|
||||
type: 'icons',
|
||||
provider,
|
||||
prefix,
|
||||
icons: ['icon1'],
|
||||
};
|
||||
expect(params).toEqual(expected);
|
||||
|
||||
// Send data
|
||||
item.done({
|
||||
prefix,
|
||||
icons: {
|
||||
icon1: {
|
||||
body: '<path d="" />',
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
setAPIModule(provider, {
|
||||
prepare: prepareQuery,
|
||||
send: sendQuery,
|
||||
});
|
||||
|
||||
// Load icon, twice
|
||||
const p1 = loadIcon(provider + ':' + prefix + ':icon1');
|
||||
const p2 = loadIcon(provider + ':' + prefix + ':icon1');
|
||||
|
||||
// Promise instances should be the same because parameter is a string that is cached
|
||||
expect(p1).toEqual(p2);
|
||||
|
||||
// Test isPending
|
||||
expect(isPending({ provider, prefix, name: 'icon1' })).toBe(true);
|
||||
|
||||
// Wait for Promise
|
||||
p1.then((data) => {
|
||||
expect(data.body).toEqual('<path d="" />');
|
||||
done();
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
done('Failed to load icon');
|
||||
});
|
||||
});
|
||||
|
||||
it('Split results', (done) => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
|
@ -51,7 +51,7 @@ import type {
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
} from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons } from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
import { mergeParams } from '@iconify/core/lib/api/params';
|
||||
|
||||
@ -230,7 +230,7 @@ const _api: IconifyAPIInternalFunctions = {
|
||||
export { _api };
|
||||
|
||||
// IconifyAPIFunctions
|
||||
export { addAPIProvider, loadIcons };
|
||||
export { addAPIProvider, loadIcons, loadIcon };
|
||||
|
||||
// IconifyStorageFunctions
|
||||
export { iconExists, getIcon, listIcons, addIcon, addCollection, shareStorage };
|
||||
|
@ -64,7 +64,7 @@ import type {
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
} from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons } from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
import { mergeParams } from '@iconify/core/lib/api/params';
|
||||
|
||||
@ -223,6 +223,7 @@ const Iconify: IconifyGlobal = {
|
||||
// IconifyAPIFunctions
|
||||
addAPIProvider,
|
||||
loadIcons,
|
||||
loadIcon,
|
||||
|
||||
// IconifyStorageFunctions
|
||||
iconExists,
|
||||
|
@ -55,7 +55,7 @@ import type {
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
} from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons } from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
import { mergeParams } from '@iconify/core/lib/api/params';
|
||||
|
||||
@ -461,7 +461,7 @@ const _api: IconifyAPIInternalFunctions = {
|
||||
export { _api };
|
||||
|
||||
// IconifyAPIFunctions
|
||||
export { addAPIProvider, loadIcons };
|
||||
export { addAPIProvider, loadIcons, loadIcon };
|
||||
|
||||
// IconifyStorageFunctions
|
||||
export { iconExists, getIcon, listIcons, addIcon, addCollection, shareStorage };
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
replaceIDs,
|
||||
buildIcon,
|
||||
loadIcons,
|
||||
loadIcon,
|
||||
addAPIProvider,
|
||||
_api
|
||||
} from './functions';
|
||||
@ -32,6 +33,7 @@ export {
|
||||
replaceIDs,
|
||||
buildIcon,
|
||||
loadIcons,
|
||||
loadIcon,
|
||||
addAPIProvider,
|
||||
_api
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ import type {
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
} from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons } from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
import { mergeParams } from '@iconify/core/lib/api/params';
|
||||
|
||||
@ -357,7 +357,7 @@ const _api: IconifyAPIInternalFunctions = {
|
||||
export { _api };
|
||||
|
||||
// IconifyAPIFunctions
|
||||
export { addAPIProvider, loadIcons };
|
||||
export { addAPIProvider, loadIcons, loadIcon };
|
||||
|
||||
// IconifyStorageFunctions
|
||||
export { iconExists, getIcon, listIcons, addIcon, addCollection, shareStorage };
|
||||
|
@ -62,4 +62,4 @@ export {
|
||||
|
||||
export { calculateSize, replaceIDs, buildIcon } from './functions';
|
||||
|
||||
export { loadIcons, addAPIProvider, _api } from './functions';
|
||||
export { loadIcons, loadIcon, addAPIProvider, _api } from './functions';
|
||||
|
@ -64,7 +64,7 @@ import type {
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
} from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons } from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
import { mergeParams } from '@iconify/core/lib/api/params';
|
||||
|
||||
@ -397,7 +397,7 @@ const _api: IconifyAPIInternalFunctions = {
|
||||
export { _api };
|
||||
|
||||
// IconifyAPIFunctions
|
||||
export { addAPIProvider, loadIcons };
|
||||
export { addAPIProvider, loadIcons, loadIcon };
|
||||
|
||||
// IconifyStorageFunctions
|
||||
export { iconExists, getIcon, listIcons, addIcon, addCollection, shareStorage };
|
||||
|
@ -57,7 +57,7 @@ import type {
|
||||
IconifyIconLoaderCallback,
|
||||
IconifyIconLoaderAbort,
|
||||
} from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons } from '@iconify/core/lib/api/icons';
|
||||
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
import { mergeParams } from '@iconify/core/lib/api/params';
|
||||
|
||||
@ -399,7 +399,7 @@ const _api: IconifyAPIInternalFunctions = {
|
||||
export { _api };
|
||||
|
||||
// IconifyAPIFunctions
|
||||
export { addAPIProvider, loadIcons };
|
||||
export { addAPIProvider, loadIcons, loadIcon };
|
||||
|
||||
// IconifyStorageFunctions
|
||||
export { iconExists, getIcon, listIcons, addIcon, addCollection, shareStorage };
|
||||
|
Loading…
Reference in New Issue
Block a user