2024-04-27 19:17:17 +00:00
|
|
|
import {
|
|
|
|
useEffect,
|
|
|
|
useState,
|
|
|
|
forwardRef,
|
|
|
|
createElement,
|
|
|
|
type Ref,
|
|
|
|
} from 'react';
|
2021-05-24 10:25:02 +00:00
|
|
|
import type { IconifyJSON, IconifyIcon } from '@iconify/types';
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
// Core
|
2021-09-27 14:28:42 +00:00
|
|
|
import type { IconifyIconName } from '@iconify/utils/lib/icon/name';
|
2022-06-19 16:16:11 +00:00
|
|
|
import type { IconifyIconSize } from '@iconify/utils/lib/customisations/defaults';
|
2021-09-25 08:43:00 +00:00
|
|
|
import type { IconifyStorageFunctions } from '@iconify/core/lib/storage/functions';
|
2021-04-24 11:49:37 +00:00
|
|
|
import {
|
2023-07-04 16:45:04 +00:00
|
|
|
iconLoaded,
|
2021-09-25 08:43:00 +00:00
|
|
|
getIcon,
|
|
|
|
addIcon,
|
|
|
|
addCollection,
|
2021-04-24 11:49:37 +00:00
|
|
|
getIconData,
|
|
|
|
allowSimpleNames,
|
|
|
|
} from '@iconify/core/lib/storage/functions';
|
2022-05-21 19:55:01 +00:00
|
|
|
import { listIcons } from '@iconify/core/lib/storage/storage';
|
2021-09-25 08:43:00 +00:00
|
|
|
import type { IconifyBuilderFunctions } from '@iconify/core/lib/builder/functions';
|
2022-07-01 19:12:18 +00:00
|
|
|
import { iconToSVG as buildIcon } from '@iconify/utils/lib/svg/build';
|
2021-09-25 08:43:00 +00:00
|
|
|
import { replaceIDs } from '@iconify/utils/lib/svg/id';
|
|
|
|
import { calculateSize } from '@iconify/utils/lib/svg/size';
|
2021-05-24 14:02:00 +00:00
|
|
|
import type { IconifyIconBuildResult } from '@iconify/utils/lib/svg/build';
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
// API
|
2021-09-25 08:43:00 +00:00
|
|
|
import type {
|
2021-04-24 11:49:37 +00:00
|
|
|
IconifyAPIFunctions,
|
|
|
|
IconifyAPIInternalFunctions,
|
2021-09-01 08:34:58 +00:00
|
|
|
IconifyAPIQueryParams,
|
|
|
|
IconifyAPICustomQueryParams,
|
2021-04-24 11:49:37 +00:00
|
|
|
} from '@iconify/core/lib/api/functions';
|
2021-09-25 08:43:00 +00:00
|
|
|
import type {
|
2021-04-24 11:49:37 +00:00
|
|
|
IconifyAPIModule,
|
|
|
|
IconifyAPISendQuery,
|
2021-09-01 08:34:58 +00:00
|
|
|
IconifyAPIPrepareIconsQuery,
|
2021-04-24 11:49:37 +00:00
|
|
|
} from '@iconify/core/lib/api/modules';
|
2021-09-25 08:43:00 +00:00
|
|
|
import { setAPIModule } from '@iconify/core/lib/api/modules';
|
|
|
|
import type {
|
2021-04-24 11:49:37 +00:00
|
|
|
PartialIconifyAPIConfig,
|
|
|
|
IconifyAPIConfig,
|
|
|
|
GetAPIConfig,
|
|
|
|
} from '@iconify/core/lib/api/config';
|
2021-09-25 08:43:00 +00:00
|
|
|
import {
|
|
|
|
addAPIProvider,
|
|
|
|
getAPIConfig,
|
|
|
|
listAPIProviders,
|
|
|
|
} from '@iconify/core/lib/api/config';
|
2022-02-21 15:13:27 +00:00
|
|
|
import {
|
|
|
|
fetchAPIModule,
|
|
|
|
setFetch,
|
|
|
|
getFetch,
|
|
|
|
} from '@iconify/core/lib/api/modules/fetch';
|
2021-04-24 11:49:37 +00:00
|
|
|
import type {
|
|
|
|
IconifyIconLoaderCallback,
|
|
|
|
IconifyIconLoaderAbort,
|
2021-09-05 16:09:25 +00:00
|
|
|
} from '@iconify/core/lib/api/icons';
|
2022-01-13 20:19:49 +00:00
|
|
|
import { loadIcons, loadIcon } from '@iconify/core/lib/api/icons';
|
2021-09-25 08:43:00 +00:00
|
|
|
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
// Cache
|
2022-06-28 19:37:23 +00:00
|
|
|
import { initBrowserStorage } from '@iconify/core/lib/browser-storage';
|
2021-04-24 11:49:37 +00:00
|
|
|
import { toggleBrowserCache } from '@iconify/core/lib/browser-storage/functions';
|
|
|
|
import type {
|
|
|
|
IconifyBrowserCacheType,
|
|
|
|
IconifyBrowserCacheFunctions,
|
|
|
|
} from '@iconify/core/lib/browser-storage/functions';
|
|
|
|
|
|
|
|
// Properties
|
2021-04-23 20:50:17 +00:00
|
|
|
import type {
|
2021-05-11 20:27:13 +00:00
|
|
|
IconifyIconOnLoad,
|
2021-04-23 20:50:17 +00:00
|
|
|
IconifyIconCustomisations,
|
|
|
|
IconifyIconProps,
|
2022-04-30 19:04:40 +00:00
|
|
|
IconifyRenderMode,
|
2021-04-23 20:50:17 +00:00
|
|
|
IconProps,
|
2024-04-27 19:17:17 +00:00
|
|
|
IconElement,
|
2021-04-23 20:50:17 +00:00
|
|
|
} from './props';
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
// Render SVG
|
2021-04-23 20:50:17 +00:00
|
|
|
import { render } from './render';
|
2022-07-02 07:53:06 +00:00
|
|
|
import { defaultIconProps } from '@iconify/utils/lib/icon/defaults';
|
2021-04-23 20:50:17 +00:00
|
|
|
|
|
|
|
/**
|
2021-04-24 11:49:37 +00:00
|
|
|
* Export required types
|
2021-04-23 20:50:17 +00:00
|
|
|
*/
|
2021-04-24 11:49:37 +00:00
|
|
|
// Function sets
|
|
|
|
export {
|
|
|
|
IconifyStorageFunctions,
|
|
|
|
IconifyBuilderFunctions,
|
|
|
|
IconifyBrowserCacheFunctions,
|
|
|
|
IconifyAPIFunctions,
|
|
|
|
IconifyAPIInternalFunctions,
|
|
|
|
};
|
2021-04-23 20:50:17 +00:00
|
|
|
|
2021-04-24 11:49:37 +00:00
|
|
|
// JSON stuff
|
|
|
|
export { IconifyIcon, IconifyJSON, IconifyIconName };
|
|
|
|
|
2021-05-11 20:27:13 +00:00
|
|
|
// Customisations and icon props
|
2021-04-23 20:50:17 +00:00
|
|
|
export {
|
2021-04-24 11:49:37 +00:00
|
|
|
IconifyIconCustomisations,
|
|
|
|
IconifyIconSize,
|
2022-04-30 19:04:40 +00:00
|
|
|
IconifyRenderMode,
|
2021-04-24 11:49:37 +00:00
|
|
|
IconifyIconProps,
|
|
|
|
IconProps,
|
2021-05-11 20:27:13 +00:00
|
|
|
IconifyIconOnLoad,
|
2021-04-23 20:50:17 +00:00
|
|
|
};
|
|
|
|
|
2021-04-24 11:49:37 +00:00
|
|
|
// API
|
|
|
|
export {
|
|
|
|
IconifyAPIConfig,
|
|
|
|
IconifyIconLoaderCallback,
|
|
|
|
IconifyIconLoaderAbort,
|
|
|
|
IconifyAPIModule,
|
|
|
|
GetAPIConfig,
|
2021-09-01 08:34:58 +00:00
|
|
|
IconifyAPIPrepareIconsQuery,
|
2021-04-24 11:49:37 +00:00
|
|
|
IconifyAPISendQuery,
|
2021-05-01 20:39:56 +00:00
|
|
|
PartialIconifyAPIConfig,
|
2021-09-01 08:34:58 +00:00
|
|
|
IconifyAPIQueryParams,
|
|
|
|
IconifyAPICustomQueryParams,
|
2021-04-24 11:49:37 +00:00
|
|
|
};
|
|
|
|
|
2021-05-11 20:27:13 +00:00
|
|
|
// Builder functions
|
2022-06-19 16:16:11 +00:00
|
|
|
export { IconifyIconBuildResult };
|
2021-05-11 20:27:13 +00:00
|
|
|
|
2021-04-24 11:49:37 +00:00
|
|
|
/* Browser cache */
|
|
|
|
export { IconifyBrowserCacheType };
|
|
|
|
|
|
|
|
/**
|
2021-09-25 08:43:00 +00:00
|
|
|
* Enable cache
|
2021-04-24 11:49:37 +00:00
|
|
|
*/
|
2021-09-25 08:43:00 +00:00
|
|
|
function enableCache(storage: IconifyBrowserCacheType): void {
|
2021-04-24 11:49:37 +00:00
|
|
|
toggleBrowserCache(storage, true);
|
2021-09-25 08:43:00 +00:00
|
|
|
}
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
/**
|
2021-09-25 08:43:00 +00:00
|
|
|
* Disable cache
|
2021-04-24 11:49:37 +00:00
|
|
|
*/
|
2021-09-25 08:43:00 +00:00
|
|
|
function disableCache(storage: IconifyBrowserCacheType): void {
|
|
|
|
toggleBrowserCache(storage, false);
|
|
|
|
}
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialise stuff
|
|
|
|
*/
|
|
|
|
// Enable short names
|
|
|
|
allowSimpleNames(true);
|
|
|
|
|
2021-09-05 16:09:25 +00:00
|
|
|
// Set API module
|
2021-09-25 08:43:00 +00:00
|
|
|
setAPIModule('', fetchAPIModule);
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Browser stuff
|
|
|
|
*/
|
|
|
|
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
|
|
|
// Set cache and load existing cache
|
2022-06-28 19:37:23 +00:00
|
|
|
initBrowserStorage();
|
2021-04-24 11:49:37 +00:00
|
|
|
|
2021-05-13 19:33:33 +00:00
|
|
|
interface WindowWithIconifyStuff {
|
|
|
|
IconifyPreload?: IconifyJSON[] | IconifyJSON;
|
|
|
|
IconifyProviders?: Record<string, PartialIconifyAPIConfig>;
|
|
|
|
}
|
|
|
|
const _window = window as WindowWithIconifyStuff;
|
2021-04-24 11:49:37 +00:00
|
|
|
|
|
|
|
// Load icons from global "IconifyPreload"
|
2021-05-13 19:33:33 +00:00
|
|
|
if (_window.IconifyPreload !== void 0) {
|
|
|
|
const preload = _window.IconifyPreload;
|
2021-04-24 11:49:37 +00:00
|
|
|
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"
|
2021-05-13 19:33:33 +00:00
|
|
|
if (_window.IconifyProviders !== void 0) {
|
|
|
|
const providers = _window.IconifyProviders;
|
2021-04-24 11:49:37 +00:00
|
|
|
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;
|
|
|
|
}
|
2021-09-25 08:43:00 +00:00
|
|
|
if (!addAPIProvider(key, value)) {
|
2021-04-24 11:49:37 +00:00
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Component
|
2021-04-23 20:50:17 +00:00
|
|
|
*/
|
2021-04-27 16:21:35 +00:00
|
|
|
interface InternalIconProps extends IconProps {
|
2024-04-27 19:17:17 +00:00
|
|
|
_ref?: Ref<IconElement> | null;
|
2021-04-27 16:21:35 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
function IconComponent(props: InternalIconProps): JSX.Element {
|
|
|
|
interface State {
|
|
|
|
// Currently rendered icon
|
|
|
|
name: string;
|
2021-04-27 16:21:35 +00:00
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
// Icon data, null if missing
|
|
|
|
data?: IconifyIcon | null;
|
2021-04-27 16:21:35 +00:00
|
|
|
}
|
2024-04-27 19:17:17 +00:00
|
|
|
const [mounted, setMounted] = useState(!!props.ssr);
|
2021-04-27 16:21:35 +00:00
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
interface AbortState {
|
|
|
|
callback?: IconifyIconLoaderAbort;
|
2021-04-27 16:21:35 +00:00
|
|
|
}
|
2024-04-27 19:17:17 +00:00
|
|
|
const [abort, setAbort] = useState<AbortState>({});
|
|
|
|
const [state, setState] = useState<State>({
|
|
|
|
name: '',
|
|
|
|
});
|
|
|
|
|
|
|
|
// Cancel loading
|
|
|
|
function cleanup() {
|
|
|
|
const callback = abort.callback;
|
|
|
|
if (callback) {
|
|
|
|
callback();
|
|
|
|
setAbort({});
|
2021-04-27 16:21:35 +00:00
|
|
|
}
|
2021-04-23 20:50:17 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
// Update state
|
|
|
|
function updateState() {
|
|
|
|
const name = props.icon;
|
|
|
|
if (typeof name === 'object') {
|
|
|
|
// Icon as object
|
|
|
|
cleanup();
|
|
|
|
setState({
|
|
|
|
name: '',
|
|
|
|
data: name,
|
|
|
|
});
|
2021-04-27 16:21:35 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
// New icon or got icon data
|
|
|
|
const data = getIconData(name);
|
|
|
|
if (state.name !== name || data !== state.data) {
|
|
|
|
cleanup();
|
|
|
|
setState({
|
|
|
|
name,
|
2021-05-13 12:46:50 +00:00
|
|
|
data,
|
|
|
|
});
|
2024-04-27 19:17:17 +00:00
|
|
|
if (data === undefined) {
|
|
|
|
// Load icon, update state when done
|
|
|
|
const callback = loadIcons([name], updateState);
|
|
|
|
setAbort({
|
|
|
|
callback,
|
|
|
|
});
|
|
|
|
} else if (data) {
|
|
|
|
// Icon data is available: trigger onLoad callback if present
|
|
|
|
props.onLoad?.(name);
|
2021-05-11 20:27:13 +00:00
|
|
|
}
|
2021-04-27 16:21:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
// Mounted state, cleanup for loader
|
|
|
|
useEffect(() => {
|
|
|
|
setMounted(true);
|
|
|
|
return cleanup;
|
|
|
|
}, []);
|
|
|
|
|
2024-04-28 05:42:11 +00:00
|
|
|
// Icon changed or component mounted
|
2024-04-27 19:17:17 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (mounted) {
|
|
|
|
updateState();
|
2021-04-24 11:49:37 +00:00
|
|
|
}
|
2024-04-28 05:42:11 +00:00
|
|
|
}, [props.icon, mounted]);
|
2024-04-27 19:17:17 +00:00
|
|
|
|
|
|
|
// Render icon
|
|
|
|
const { name, data } = state;
|
|
|
|
if (!data) {
|
|
|
|
return props.children
|
|
|
|
? (props.children as JSX.Element)
|
|
|
|
: createElement('span', {});
|
2021-04-24 11:49:37 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
return render(
|
|
|
|
{
|
|
|
|
...defaultIconProps,
|
|
|
|
...data,
|
|
|
|
},
|
|
|
|
props,
|
|
|
|
name
|
|
|
|
);
|
2021-04-23 20:50:17 +00:00
|
|
|
}
|
|
|
|
|
2024-04-27 19:17:17 +00:00
|
|
|
// Component type
|
|
|
|
type IconComponentType = (props: IconProps) => JSX.Element;
|
|
|
|
|
2021-04-23 20:50:17 +00:00
|
|
|
/**
|
|
|
|
* Block icon
|
|
|
|
*
|
|
|
|
* @param props - Component properties
|
|
|
|
*/
|
2024-04-27 19:17:17 +00:00
|
|
|
export const Icon = forwardRef<IconElement, IconProps>((props, ref) =>
|
|
|
|
IconComponent({
|
2021-08-16 07:55:28 +00:00
|
|
|
...props,
|
|
|
|
_ref: ref,
|
2024-04-27 19:17:17 +00:00
|
|
|
})
|
|
|
|
) as IconComponentType;
|
2021-04-23 20:50:17 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Inline icon (has negative verticalAlign that makes it behave like icon font)
|
|
|
|
*
|
|
|
|
* @param props - Component properties
|
|
|
|
*/
|
2024-04-27 19:17:17 +00:00
|
|
|
export const InlineIcon = forwardRef<IconElement, IconProps>((props, ref) =>
|
|
|
|
IconComponent({
|
|
|
|
inline: true,
|
|
|
|
...props,
|
|
|
|
_ref: ref,
|
|
|
|
})
|
|
|
|
) as IconComponentType;
|
2021-09-25 08:43:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal API
|
|
|
|
*/
|
|
|
|
const _api: IconifyAPIInternalFunctions = {
|
|
|
|
getAPIConfig,
|
|
|
|
setAPIModule,
|
|
|
|
sendAPIQuery,
|
|
|
|
setFetch,
|
2022-02-21 15:13:27 +00:00
|
|
|
getFetch,
|
2021-09-25 08:43:00 +00:00
|
|
|
listAPIProviders,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Export functions
|
|
|
|
*/
|
|
|
|
// IconifyAPIInternalFunctions
|
|
|
|
export { _api };
|
|
|
|
|
|
|
|
// IconifyAPIFunctions
|
2022-01-13 20:19:49 +00:00
|
|
|
export { addAPIProvider, loadIcons, loadIcon };
|
2021-09-25 08:43:00 +00:00
|
|
|
|
|
|
|
// IconifyStorageFunctions
|
2023-07-04 16:45:04 +00:00
|
|
|
export {
|
|
|
|
iconLoaded,
|
|
|
|
iconLoaded as iconExists, // deprecated, kept to avoid breaking changes
|
|
|
|
getIcon,
|
|
|
|
listIcons,
|
|
|
|
addIcon,
|
|
|
|
addCollection,
|
|
|
|
};
|
2021-09-25 08:43:00 +00:00
|
|
|
|
|
|
|
// IconifyBuilderFunctions
|
|
|
|
export { replaceIDs, calculateSize, buildIcon };
|
|
|
|
|
|
|
|
// IconifyBrowserCacheFunctions
|
|
|
|
export { enableCache, disableCache };
|