Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

RFC: New icon api#62904

Closed
fkling wants to merge 1 commit into
mainfrom
fkling/srch-71-svelte-import-lucide-icons
Closed

RFC: New icon api#62904
fkling wants to merge 1 commit into
mainfrom
fkling/srch-71-svelte-import-lucide-icons

Conversation

@fkling

@fkling fkling commented May 24, 2024

Copy link
Copy Markdown
Contributor

This PR adds the ability to use Lucide icons. Because those icons work differently (you import an SVG element/component, not a text string), we also have to decide how we want to use these icons. Here are three proposals:

1) Import and use icon directly as component

import TheIcon from '~icons/lucide/icon'
// or import TheIcon from 'lucide-icons/icons/icon
// or import {TheIcon} from 'lucide-icons'


<TheIcon aria-hidden class="icon-inline" />

Pro:

  • Only loads the icons that are used

Cons:

  • cannot provide "nice" api for icons and needs global CSS for additional styling
  • no autocompletion for the first way to import icons

2) Import icon and pass to icon component

import TheIcon from '~icons/lucide/icon'
// or import {TheIcon} from 'lucide-icons'
// or import TheIcon from 'lucide-icons/icons/icon

<Icon icon={TheIcon} aria-hidden inline />

Pro:

  • only loads the icons that are used
  • we can have a nicer API for displaying icons (no global CSS needed)

Cons:

  • no autocompletion for the first way to import icons

3) Specify icon via string

<Icon icon="theicon" aria-hidden inline />

where Icon defines a map like

import TheIcon from '~icons/lucide/icon'

const icons = {
    theicon: TheIcon
}

Pros:

  • we abstract from the concrete icon library/set that is used
  • we can have a nicer API for displaying icons (no global CSS needed)
  • get autocompleteion for icons if the icon property is defined accordingly

Cons:

  • we possibly import lots of icons that are not currently used for the page

Approach (2) and (3) can also be combined and maybe we only provide string names for icons that are used in multiple places in the app. Then we have all the pros and lessen the cons.

Test plan

Manual testing.

@cla-bot cla-bot Bot added the cla-signed label May 24, 2024
@fkling fkling closed this May 24, 2024
@camdencheek

camdencheek commented May 24, 2024

Copy link
Copy Markdown
Member

Gut reaction: option 2 feels right.

Option 1:

  • You mentioned the global CSS, which doesn't feel ideal. I really liked the "scoped-ness" of components for applying styles, and would be sad to lose that.
  • For custom icons (which we will likely have at least a few of), we would need to be careful to provide the same interface as the unplugin icons so icons can be used in a uniform manner across the app.

Option 2:

  • I like that this gives us a way to provide a fully uniform interface for icons (custom and unplugin)
  • I like that the Icon component can be well-documented and gives a clear entrypoint for adding an icon
  • I like that the Icon component can own both its styling and its interface

Option 3:

  • I don't love that the Icon component needs to be the owner of every icon in the web app. e.g., for custom icons, it can make sense to organize the icon SVG in with the component that uses/owns it. It just feels less composable.

@fkling

fkling commented May 24, 2024

Copy link
Copy Markdown
Contributor Author

@camdencheek FWIW, unplugin-icons allows you to define custom icon sets that you can import in exactly the same way (i.e. import SomeIcon from '~icons/ourset/someicon').

My biggest concern with (1) and (2) (and unplugin-icons) is that it's not possible to get nice autocomplete from the editor when using an icon. But maybe that's not as big of an issue than I think it is. I have to go to the icon overview anyway to get the exact name of the icon.
The alternative is that we use lucide-icons but then we still need unplugin-icons to import other icon sets for file icons. I guess this wouldn't be too bad either but I like uniformity.

We can also always create a custom wrapper around an icon to make it more ergonomic, e.g. create a CloseIcon component that can be used directly.

You mentioned the global CSS, which doesn't feel ideal. I really liked the "scoped-ness" of components for applying styles, and would be sad to lose that.

You can see the changes in styles.css here. However due to the nature of Svelte, the CSS in the Icon component will also have to use :global(...). But at least it's colocated with where it's actually used (and we could use more complicated class names to prevent accidental application).

@camdencheek

Copy link
Copy Markdown
Member

unplugin-icons allows you to define custom icon sets

Oh, neat! Definitely on board with unplugin. Seems convenient.

it's not possible to get nice autocomplete from the editor when using an icon

Am I understanding right that this is because the unplugin icon components are generated at compile time rather than pre-packaged as a list of components? TBH, I'm not terribly concerned about this. I always end up looking up the icons in the set anyways.

Icon component will also have to use :global(...). But at least it's colocated with where it's actually used

Another benefit is that we can limit it to only apply to children of the Icon component without needing to name the Icon component/class from global CSS

@fkling

fkling commented May 24, 2024

Copy link
Copy Markdown
Contributor Author

Another benefit is that we can limit it to only apply to children of the Icon component without needing to name the Icon component/class from global CSS

Only if we wrap it in another element. Which is probably fine to do.

@fkling

fkling commented May 24, 2024

Copy link
Copy Markdown
Contributor Author

@camdencheek How do you feel about auto importing icons? I.e. with the right setup we can do

import Icon from '$lib/Icon.svelte'

<Icon icon={ILucideHome} inline />

It even seems to work with Typescript (it generates a .d.ts file, although I still get a warning, maybe from the Svelte LSP?)

@camdencheek

Copy link
Copy Markdown
Member

Cool! How does it know what ILucideHome to use?

(Also, I do not feel strongly about this, so feel free to go whatever direction makes most sense)

@fkling

fkling commented May 24, 2024

Copy link
Copy Markdown
Contributor Author

It seems to look for variables that match {prefix}{iconset}{iconname} and generate the appropriate import. I'll create a new PR to give it a try. We can always switch if it feels too magical.

@fkling fkling deleted the fkling/srch-71-svelte-import-lucide-icons branch May 24, 2024 15:43
@vovakulikov

Copy link
Copy Markdown
Contributor

My biggest concern with (1) and (2) (and unplugin-icons) is that it's not possible to get nice autocomplete from the editor when using an icon

+1 to this concern, it is always a case for me when I just can't find the icon that we have in Figma in the real world, there is a demo for MDI icons (kind of vitrine, but I'm not sure it's an actual world in English though) where you can find an icon set, but it doesn't make it any easier because we use different names in Figma for icons.

So, I would like to solve this problem with autocomplete in another way, where we have our own demo in the storybook for all icons we have with search by name input; it would be easier for me to find an icon and see what it actually looks like. This being said, not having an autocomplete wouldn't be a problem for me if we had a searchable demo with icons.

Case №3

we possibly import lots of icons that are not currently used for the page

This is probably the biggest stopper for me personally; we probably don't want to keep track manually of which icon is used and which isn't. But maybe this fact would force us to treat icons a bit more carefully (I doubt that would be the case though, too many things to worry about already besides icons, and people won't be tracking it really)

In conclusion, I would go with approach №2 with or without autogenerated imports for icons. Would also add that we probably should have external or internal demo/overview for all icons we have,

fkling added a commit that referenced this pull request May 29, 2024
See also #62904.

This PR adds a new icon component (`Icon2`), which takes an svg component imported by `unplugin-icons`. To make things easier the icons can be auto-imported via `unplugin-auto-import`.

Usage example:

```js
import Icon2 from '$lib/Icon2.svelte'

<Icon2 icon={ILucideX} inline />
```

`unplugin-icons` allows us to:

- use other icon sets besides lucide, while using the same API. Other icon sets are necessary for file icons. `react-icons`, which we use in the React app, also pulls from multiple icon sets.
- define our own icon sets

See https://github.com/unplugin/unplugin-icons for more information.

If it turns out that auto-importing (which involves generating TypeScrip types) doesn't work with our Bazel pipeline we can fall back to manual importing.

This PR converts some icons as example.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants