UNPKG

@blueprintjs/core

Version:

Core styles & components

98 lines 5.06 kB
/* * 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