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

[RFC] Restructure icons exports #42704

Open
o-alexandrov opened this issue Jun 21, 2024 · 2 comments
Open

[RFC] Restructure icons exports #42704

o-alexandrov opened this issue Jun 21, 2024 · 2 comments
Assignees
Labels
RFC Request For Comments status: waiting for maintainer These issues haven't been looked at yet by a maintainer

Comments

@o-alexandrov
Copy link

o-alexandrov commented Jun 21, 2024

What's the problem?

This RFC looks at 2 problems with icons:

  1. for MUI's users, there's no out-of-the-box option to enforce icons' variant: Sharp, Rounded, Outlined, TwoTone, Filled
  2. too many icons; it affects performance (see related issues)

What are the requirements?

MUI's user should be able to enforce icons' variants and the number of icons shouldn't affect DX.

Proposed solution

We can tackle both problems by allowing MUI's users to have more consistent interfaces by enforcing icons' variants using ESLint's no-restricted-imports.

File structure for Material Icons:

  • the barrel file has 5x less icons 2,127 instead of 10,635
|-- index.ts // exports everything as it is now to support the current usage
|-- /variants
   |-- /sharp // exports only Sharp variant, available as "@mui/icons-material/sharp"
   |-- /rounded // exports only Rounded variant, available as "@mui/icons-material/rounded"
   |-- /outlined // exports only Outlined variant, available as "@mui/icons-material/outlined"
   |-- /two-tone // exports only TwoTone variant, available as "@mui/icons-material/two-tone"
   |-- /filled // exports only Filled variant, available as "@mui/icons-material/filled"

File structure for Material Symbols:

  • the barrel file has 63x less icons 2,500 instead of 157,500
|-- index.ts // exports everything as it is now to support the current usage
|-- /variants
   |-- /sharp // exports only Sharp variant, available as "@mui/icons-material/sharp"
      |-- /100 // exports only 100 weight, available as "@mui/icons-material/sharp/100"
         |-- /neg25 // exports only -25 grade, available as "@mui/icons-material/sharp/100/neg25"
         |-- /0 // exports only 0 grade, available as "@mui/icons-material/sharp/100/0"
         |-- /200 // exports only 200 grade, available as "@mui/icons-material/sharp/100/200"
      |-- ...other weights in separate directories 200, 300, 400, 500, 600, 700
   |-- /rounded // exports only Rounded variant, available as "@mui/icons-material/rounded"
      |-- /100 // exports only 100 weight, available as "@mui/icons-material/rounded/100"
         |-- /neg25 // exports only -25 grade, available as "@mui/icons-material/rounded/100/neg25"
         |-- /0 // exports only 0 grade, available as "@mui/icons-material/rounded/100/0"
         |-- /200 // exports only 200 grade, available as "@mui/icons-material/rounded/100/200"
      |-- ...other weights in separate directories 200, 300, 400, 500, 600, 700
   |-- /outlined // exports only Outlined variant, available as "@mui/icons-material/outlined"
      |-- /100 // exports only 100 weight, available as "@mui/icons-material/outlined/100"
         |-- /neg25 // exports only -25 grade, available as "@mui/icons-material/outlined/100/neg25"
         |-- /0 // exports only 0 grade, available as "@mui/icons-material/outlined/100/0"
         |-- /200 // exports only 200 grade, available as "@mui/icons-material/outlined/100/200"
      |-- ...other weights in separate directories 200, 300, 400, 500, 600, 700

Related issues

Search keywords: material icons, symbols, icons v2

@o-alexandrov o-alexandrov added RFC Request For Comments status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jun 21, 2024
@TheOneTheOnlyJJ
Copy link

Not long ago I made a suggestion that would exapnd the icons' package features and improve DX when requiring specific icons at runtime (eg. based on user input).

See the issue at #42450.

Now, thinking of it in the context of performance, splitting the icons into separate packages based on style could allow tree shakers to reduce the bundled size significantly if icons of one particular style are used. A separate import could be used for when all the icons of all styles are required.

My issue was requesting the ability to get the icons at runtime based on their style(s) and tag(s)/synonym(s) (see why I need that feature in mui/mui-x#13206). It's a shame it got closed just because there's already a hacky way to import icons at runtime in userland. The current way of doing it is also not optimised for a particular style. I'm glad this RFC has been opened, so we can have a proper discussion on the topic.

Given the very likely adoption of Material Symbols (#32846) in MUI v7, I believe an expansion of the icons' package API (like my suggestion or similar) should be considered by the team. A well thought-out API expansion in this area could bring both extended functionality and improved performance, thus covering extra use-cases (like mine from mui/mui-x#13206) and improving performance, as mentioned here.

@TheOneTheOnlyJJ
Copy link

I'll copy & paste the proposed API changes I made in the issues mentioned in the above reply so that they can be discussed further right here.

I would like to add an explicit example of how the utility function from the icons package I was talking about could look like:

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.

With this kind of API, the Icon Picker component can pass its state as arguments to the getIcons function and fulfil my requirement. When the user would change the style option(s) or change the search word, the state would update and call the function again, and the Icon Picker would rerender to only display the new icons returned by getIcons. Having both the anyOf and the allOf tag selectors will enable this component to potentially use Chip-based sorting as well as the already discussed Radio Button/Tree View variants.

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 icons-related reply is out of topic here, feel free to move (or copy) this issue to the corresponding repository (material-ui).

Of course, this proposed API should be expanded taking into account the separation of the icons' packages based on style, to reduce the final build size through tree shaking when not all styles are required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC Request For Comments status: waiting for maintainer These issues haven't been looked at yet by a maintainer
Projects
None yet
Development

No branches or pull requests

3 participants