import React, { createContext, FC, ReactNode, useContext, useMemo, } from "react"; import FontIcon from "./FontIcon"; export interface ConfigurableIcons { /** * The general icon for navigating backwards or closing an item to the left. */ back?: ReactNode; /** * The general icon to use for checkboxes. */ checkbox?: ReactNode; /** * The general icon to use for dropdown menus or content that expands * vertically in a new material instead of inline like the `expander` icon. */ dropdown?: ReactNode; /** * The general icon to use for downloading content. */ download?: ReactNode; /** * The general icon to use for expanding content vertically. */ expander?: ReactNode; /** * The general icon for navigating forwards or closing an item to the right. * This is also used internally for nested dropdown menus. */ forward?: ReactNode; /** * The general icon to use for displaying a main navigation menu. */ menu?: ReactNode; /** * The general icon for displaying notifications. This is used internally in * the `BadgedButton` in the `@react-md/badge` package. */ notification?: ReactNode; /** * The general icon for temporarily displaying a password's field value as * plain text. */ password?: ReactNode; /** * The general icon to use for radio buttons. */ radio?: ReactNode; /** * The general icon to use for showing that something has been selected that * is not a radio or checkbox. This is used internally for the `Chip` in the * `@react-md/chip` package. */ selected?: ReactNode; /** * The general icon for sorting content. This defaults to the sort ascending * behavior. */ sort?: ReactNode; } export type ConfiguredIcons = Required; const DEFAULT_ICONS: ConfiguredIcons = { back: keyboard_arrow_left, checkbox: check_box, download: file_download, dropdown: arrow_drop_down, expander: keyboard_arrow_down, forward: keyboard_arrow_right, menu: menu, notification: notifications, password: remove_red_eye, radio: radio_button_checked, selected: check, sort: arrow_upward, }; const context = createContext(DEFAULT_ICONS); const { Provider } = context; /** * Gets one of the configured icons from the `IconProvider`. This is probably * just for use within `react-md`, but might be helpful outside if you want to * reuse the existing icon configuration for other custom components. * * If te second argument is provided and it is not `undefined`, that value will * be used instead of the inherited icon type. * * @param name The name of the icon you want to use. * @param override An optional override to use instead of the inherited icon. * @return The overridden icon value or the inherited icon. */ export function useIcon( name: keyof ConfigurableIcons, override?: ReactNode | undefined ): ReactNode { const icons = useContext(context); if (typeof override !== "undefined") { return override; } return icons[name]; } export interface IconProviderProps extends ConfigurableIcons { /** * The children that should inherit the icon provider context. This is * required since this component is pretty much worthless to use if you don't * inherit the overridden icons. */ children: ReactNode; } /** * The `IconProvider` component is used to override all the default icons within * `react-md` with a newly defined set of icons. This is super nice since you * won't need to create new component wrappers for all the components within * `react-md` if you want to switch to SVG icons instead of the default font * icons. */ const IconProvider: FC = ({ children, back = DEFAULT_ICONS.back, checkbox = DEFAULT_ICONS.checkbox, download = DEFAULT_ICONS.download, dropdown = DEFAULT_ICONS.dropdown, expander = DEFAULT_ICONS.expander, forward = DEFAULT_ICONS.forward, menu = DEFAULT_ICONS.menu, notification = DEFAULT_ICONS.notification, password = DEFAULT_ICONS.password, radio = DEFAULT_ICONS.radio, selected = DEFAULT_ICONS.selected, sort = DEFAULT_ICONS.sort, }) => { const value = useMemo( () => ({ back, checkbox, download, dropdown, expander, forward, menu, notification, password, radio, selected, sort, }), [ back, checkbox, download, dropdown, expander, forward, menu, notification, password, radio, selected, sort, ] ); return {children}; }; if (process.env.NODE_ENV !== "production") { try { const PropTypes = require("prop-types"); IconProvider.propTypes = { children: PropTypes.node, back: PropTypes.node, checkbox: PropTypes.node, download: PropTypes.node, dropdown: PropTypes.node, expander: PropTypes.node, forward: PropTypes.node, menu: PropTypes.node, notification: PropTypes.node, password: PropTypes.node, radio: PropTypes.node, selected: PropTypes.node, sort: PropTypes.node, }; } catch (e) {} } export default IconProvider;