natemoo-re / astro-icon

Inline and sprite-based SVGs in Astro made easy!
https://astroicon.dev
Other
992 stars 57 forks source link

Make `astro-icon` usable from UI framework components #151

Open PeterDraex opened 7 months ago

PeterDraex commented 7 months ago

Currently, it is not possible to call Astro components from UI frameworks, so it is currently not possible to use astro-icon on interactive websites. The issue is that astro-icon only exports Astro components, which cannot be used from within UI frameworks.

I see two approaches to fix this:

  1. Let developers create their own <Sprite> component in their app.

This is currently not possible, because the package exports are limited to:

  "exports": {
    ".": "./index.ts",
    "./pack": "./lib/createIconPack.ts"
  },

Which would need to be changed to:

  "exports": {
    ".": "./index.ts",
    "./pack": "./lib/createIconPack.ts"
    "./context": "./lib/context.ts",
    "./constants": "./lib/constants.ts"
  },
  1. Export framework-agnostic JSX component <Sprite> To do this, we would:
    • move the JSX code from Sprite.astro to Sprite.jsx (Sprite.astro would just receive props and pass it to Sprite.jsx)
    • export both JSX and Astro component However, I guess this would not work for non-JSX UI frameworks (e.g. Svelte).

What do you think? Would a PR for either of these solutions be accepted?

iivvaannxx commented 7 months ago

Correct me if I'm mistaken, but I believe you can actually do that already, Astro allows the usage of Astro components in UI framework components through named slots.

The example in the docs uses a <MyReactComponent> as an example and a <MyAstroComponent slot='name'>. In your case would be exactly the same, just using <Icon> instead of <MyAstroComponent>. Example:

<MyReactComponentOrWhateverFramework>
  <Icon name='mdi:home' slot='icon' />
</MyReactComponentOrWhateverFramework>

Just ensure you have a slot inside your component named icon. In React you don't do this through slots though, you need to have a prop named the same you are giving to the slot attribute. See this for an example. For other frameworks like Svelte or Vue I think this works seamlessly.

PeterDraex commented 7 months ago

@iivvaannxx I think that would work, but turn out to be very impractical for an interactive website. Since Astro components can't be included from framework components, all re-usable components tend to be framework components. Only the root level pages are Astro components. That means that all <Icon />s must be loaded on the root page level and passed down the component hierarchy through slots, sometimes going 5 levels deep to reach the place where the icon should be displayed. It hurts readability too much.

iivvaannxx commented 7 months ago

@PeterDraex Yeah, in that situation it's true that is a bit of a pain to do so. Then I guess that this library may not be your best option for your use case. You could take a look at unplugin-icons. It's very easy to use and it's framework agnostic out of the box. It uses the same sets of icons that astro-icon uses (from Iconify).

You lose indeed many of the features that this library offers for Astro icons but if you're using it only for icons then unplugin-icons is your best next option. If you pretend to use the icons on many different frameworks I recommend checking this issue.

Also, it seems this library is receiving less and less updates so if you have any ideas, I would recommend going to this proposal which talks about Astro native Icon support.