Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[icons] Support getting Icon Components as Arrays, by styles and tags #42450

Closed
TheOneTheOnlyJJ opened this issue May 30, 2024 · 2 comments
Closed
Assignees
Labels
new feature New feature or request package: icons Specific to @mui/icons

Comments

@TheOneTheOnlyJJ
Copy link

TheOneTheOnlyJJ commented May 30, 2024

Summary

In the context of an issue I opened for the MUI X package mui/mui-x#13206 I have mentioned the necessity to add a new utility function getIcons to the mui/icons-material package. This is because I need to create an icon selection component from which a user could select any of the Material Icons available. There is no way to import all of them at once, and writing out thousands of imports by hand is not feasible.

Examples

In order to also cover filtering icons by their styles and tags, here is the API I propose (extracted from my MUI X issue mentioned above):

import { getIcons } from '@mui/icons-material';
import SvgIcon from '@mui/material/SvgIcon';

// Get all icons in all styles
let allIcons: Array<SvgIcon> = getIcons();

// Get all outlined icons
let allOutlinedIcons: Array<SvgIcon> = getIcons({ styles: [ 'outlined' ] });

// Get only filled and outlined icons
let filledAndOutlinedIcons: Array<SvgIcon> = getIcons({ styles: [ 'filled', 'outlined' ] });

// Get only filled icons with the "home" tag
// Should only return these icons: https://mui.com/material-ui/material-icons/?query=home
let filledHomeIcons: Array<SvgIcon> = getIcons({ styles: [ 'filled' ], tags: { anyOf: [ 'home' ] } });

// Get all icons with the "home" tag, in all styles
let allHomeIcons: Array<SvgIcon> = getIcons({ tags: { anyOf: [ 'home' ] } });

// Get all icons that have either the "home" or the "building" tags, in all styles
let allHomeOrBuildingIcons: Array<SvgIcon> = getIcons({ tags: { anyOf: [ 'home', 'building' ] } });

// Get all icons that have both the "home" and "building" tags, in the sharp style only
let allSharpHomeAndBuildingIcons: Array<SvgIcon> = getIcons({ styles: [ 'sharp' ], tags: { allOf: [ 'home', 'building' ] } });

// Do not support allOf and anyOf at the same time
let willThrowException = getIcons({ tags: { anyOf: [ 'home' ], allOf: [ 'building' ] } });

The styles argument is optional and, if missing, every style will be included in the output. It is a string array that can have any of the following options filled, outlined, rounded, two tone and sharp. These could additionally also be exported as enums to be used in code conveniently.

The tags argument is also optional, and its filtering will apply together with the style filter. It is an object that must have either the anyOf or the allOf keys that map to string arrays. They should not be both supported at the same time, resulting in an exception being thrown. Using the argument with anyOf option will return all the icons that have at least one of the tags in the list. Using it with the allOf option will return only the icons that have all the tags from the given tag list.

Additionally, a function that allows getting all tags for a specific icon (maybe call it getIconTags) should also be available for flexibility (to show the user the keywords/tags a specific icon can be found by), but this would require an internal ID for every icon to be passed as an argument to that function. I am not that accustomed to the internals of the icons package, so I do not know how difficult such an addition would be.

If this API addition would require profound internal modifications of the mui/icons-material package, I may suggest batching it with the addition of support for Material Symbols (see #32846 for details) in MUI v7, as that will also impact the package substantially.

Motivation

There's no way to easily get Material Icons as components en masse (My use case requires this for user selection).

Search keywords: material icon symbol array style tag

@TheOneTheOnlyJJ TheOneTheOnlyJJ added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label May 30, 2024
@aarongarciah aarongarciah added package: icons Specific to @mui/icons new feature New feature or request labels May 30, 2024
@aarongarciah aarongarciah self-assigned this May 30, 2024
@aarongarciah aarongarciah removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label May 30, 2024
@aarongarciah
Copy link
Member

Hey @TheOneTheOnlyJJ, thanks for the proposal. As you pointed out, this is a big change that we'll need to consider.

In the meantime, you should be able to build the icon selection functionality in userland. This is how it currently works in the Material Icons docs page:

  1. Import all icons:
    import * as mui from '@mui/icons-material';
  2. Filter/group icons as needed:
    const allIconsMap = {};
    const allIcons = Object.keys(mui)
    .sort()
    .map((importName) => {
    let theme;
    if (importName.indexOf('Outlined') !== -1) {
    theme = 'Outlined';
    } else if (importName.indexOf('TwoTone') !== -1) {
    theme = 'Two tone';
    } else if (importName.indexOf('Rounded') !== -1) {
    theme = 'Rounded';
    } else if (importName.indexOf('Sharp') !== -1) {
    theme = 'Sharp';
    } else {
    theme = 'Filled';
    }
    const name = importName.replace(/(Outlined|TwoTone|Rounded|Sharp)$/, '');
    let searchable = name;
    if (synonyms[searchable]) {
    searchable += ` ${synonyms[searchable]}`;
    }
    searchIndex.addAsync(importName, searchable);
    const icon = {
    importName,
    name,
    theme,
    Component: mui[importName],
    };
    allIconsMap[importName] = icon;
    return icon;
    });
  3. Render the icons:
    {icons.map((icon) => {
    /* eslint-disable jsx-a11y/click-events-have-key-events */
    return (
    <StyledIcon key={icon.importName} onClick={handleIconClick(icon)}>
    <StyledSvgIcon
    component={icon.Component}
    fontSize="large"
    tabIndex={-1}
    onClick={handleOpenClick}
    title={icon.importName}
    />
    <div>
    {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions -- TODO: a11y */}
    <div onClick={handleLabelClick}>{icon.importName}</div>
    </div>
    {/* eslint-enable jsx-a11y/click-events-have-key-events */}
    </StyledIcon>
    );
    })}
    </div>

@aarongarciah aarongarciah changed the title Support getting Icon Components as Arrays, by styles and tags [icons] Support getting Icon Components as Arrays, by styles and tags May 30, 2024
@aarongarciah
Copy link
Member

@TheOneTheOnlyJJ I'm closing this issue since there's a solution that can be implemented in userland and for now, we don't think this is a necessary addition to the @mui/icons-material package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request package: icons Specific to @mui/icons
Projects
None yet
Development

No branches or pull requests

2 participants