@blueprintjs/core
Version:
Core styles & components
98 lines • 5.06 kB
JavaScript
/*
* Copyright 2017 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import classNames from "classnames";
import * as React from "react";
import { Icons, IconSize, SVGIconContainer, } from "@blueprintjs/icons";
import { Classes, DISPLAYNAME_PREFIX, removeNonHTMLProps, } from "../../common";
// re-export for convenience, since some users won't be importing from or have a direct dependency on the icons package
export { IconSize };
/**
* Icon component.
*
* @see https://blueprintjs.com/docs/#core/components/icon
*/
// eslint-disable-next-line prefer-arrow-callback
export const Icon = React.forwardRef(function (props, ref) {
const { autoLoad = true, className, color, icon, intent, tagName = "span", svgProps, title, htmlTitle, ...htmlProps } = props;
// Preserve Blueprint v4.x behavior: iconSize prop takes predecence, then size prop, then fall back to default value
// eslint-disable-next-line @typescript-eslint/no-deprecated
const size = props.iconSize ?? props.size ?? IconSize.STANDARD;
const [iconPaths, setIconPaths] = React.useState(() => typeof icon === "string" ? Icons.getPaths(icon, size) : undefined);
React.useEffect(() => {
let shouldCancelIconLoading = false;
if (typeof icon === "string") {
// The icon may have been loaded already, in which case we can simply grab it.
// N.B. when `autoLoad={true}`, we can't rely on simply calling Icons.load() here to re-load an icon module
// which has already been loaded & cached, since it may have been loaded with special loading options which
// this component knows nothing about.
const loadedIconPaths = Icons.getPaths(icon, size);
if (loadedIconPaths !== undefined) {
setIconPaths(loadedIconPaths);
}
else if (autoLoad) {
Icons.load(icon, size)
.then(() => {
// if this effect expired by the time icon loaded, then don't set state
if (!shouldCancelIconLoading) {
setIconPaths(Icons.getPaths(icon, size));
}
})
.catch(reason => {
console.error(`[Blueprint] Icon '${icon}' (${size}px) could not be loaded.`, reason);
});
}
else {
console.error(`[Blueprint] Icon '${icon}' (${size}px) is not loaded yet and autoLoad={false}, did you call Icons.load('${icon}', ${size})?`);
}
}
return () => {
shouldCancelIconLoading = true;
};
}, [autoLoad, icon, size]);
if (icon == null || typeof icon === "boolean") {
return null;
}
else if (typeof icon !== "string") {
return icon;
}
if (iconPaths == null) {
// fall back to icon font if unloaded or unable to load SVG implementation
const sizeClass = size === IconSize.STANDARD
? Classes.ICON_STANDARD
: size === IconSize.LARGE
? Classes.ICON_LARGE
: undefined;
return React.createElement(tagName || "span", {
"aria-hidden": title ? undefined : true,
...removeNonHTMLProps(htmlProps),
className: classNames(Classes.ICON, sizeClass, Classes.iconClass(icon), Classes.intentClass(intent), className),
"data-icon": icon,
ref,
title: htmlTitle,
});
}
else {
const pathElements = iconPaths.map((d, i) => React.createElement("path", { d: d, key: i, fillRule: "evenodd" }));
// HACKHACK: there is no good way to narrow the type of SVGIconContainerProps here because of the use
// of a conditional type within the type union that defines that interface. So we cast to <any>.
// see https://github.com/microsoft/TypeScript/issues/24929, https://github.com/microsoft/TypeScript/issues/33014
return (React.createElement(SVGIconContainer, { children: pathElements,
// don't forward `Classes.ICON` or `Classes.iconClass(icon)` here, since the container will render those classes
className: classNames(Classes.intentClass(intent), className), color: color, htmlTitle: htmlTitle, iconName: icon, ref: ref, size: size, svgProps: svgProps, tagName: tagName, title: title, ...removeNonHTMLProps(htmlProps) }));
}
});
Icon.displayName = `${DISPLAYNAME_PREFIX}.Icon`;
//# sourceMappingURL=icon.js.map