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

Better support for custom icons #172

Closed
devoto13 opened this issue Aug 23, 2019 · 10 comments · Fixed by #438
Closed

Better support for custom icons #172

devoto13 opened this issue Aug 23, 2019 · 10 comments · Fixed by #438

Comments

@devoto13
Copy link
Collaborator

  1. Document how to render custom icon using angular-fontawesome.
  2. Investigate what can be done to improve support for custom icons without sacrificing auto complete for stock Font Awesome icons. E.g.
<fa-icon icon="my-custom-icon"></fa-icon>

will fail to compile, because my-custom-icon is not a known icon name. However if we change type to allow arbitrary string as an icon name we'll loose the auto complete for stock icons because of microsoft/TypeScript#29729.

@devoto13 devoto13 added this to the 0.6.0 milestone Aug 23, 2019
@devoto13 devoto13 removed this from the 0.6.0 milestone Feb 29, 2020
@thepercival
Copy link

It would be very useful for me to add custom-icon support. My custom icons are now in a flaticon-collectio which is completely loaded when needed. Not the ideal way. Your library works very nice by the way. I am very pleased. If I can help in anyway to implement this issue, i am at your service.

@devoto13
Copy link
Collaborator Author

devoto13 commented Apr 28, 2020

Thanks for kind words @thepercival!

In runtime world this just works. To support this feature in types world it is necessary to update type definitions for all FA packages ecosystem. I've been experimenting with it in https://github.com/devoto13/fa-icons-merge (last commit), but the current approach is pretty cumbersome.

I think the key to support this feature is some way of declaration merging, which will allow to add custom icons' names to the IconName and IconPrefix types. The key requirements are to not loose auto-completion for icon names and to not break FA users.

Unfortunately neither type unions, nor enums support declaration merging. So if you have any ideas how to make syntax for adding custom icons less cumbersome this should allow to move this feature forward.

@thepercival
Copy link

Hello,

I am not a tech expert and I hope I don't waste your time.

I took a look at the type-definitions. With custom icons the library does not know the names of the icons. That is obvious.
I wrote some lines of code which seems fine from the users-perspective(mine):

export type IconNameCustom = 'faMyCustomIcon1' | 'faMyCustomIcon2';

export class MyFaIconLibrary extends FaIconLibrary {
  getIconDefinition(prefix: IconPrefix, name: IconName | IconNameCustom): IconDefinition | null {
    if (prefix === 'fac') { /* 'fac' where c stands for custom */
      if (name === 'faMyCustomIcon2') {
        // createDefinition of faMyCustomIcon and return
      }
    }
    return super.getIconDefinition(prefix, <IconName>name);
  }
}

The custom icons will not show up in the autocompletion, but that should not be a problem for custom icons. Otherwise I do not see a solution.

Hopefully this gives you an idea of the users-perspective.

@devoto13
Copy link
Collaborator Author

devoto13 commented Apr 28, 2020

This issue is really about the type safety and auto-completion for custom icon names on the usage site, i.e. <fa-icon icon="<IN HERE>"></fa-icon>.

If you're okey with some casts you can use custom icons already today without any code modifications: https://stackblitz.com/edit/angular-z8v4ux-i7gazy?file=src%2Fapp%2Fapp.module.ts.

You'll probably need to wrap it into $any() in the template as well, but StackBlitz does not trigger the error for some reason.

The custom icons will not show up in the autocompletion, but that should not be a problem for custom icons. Otherwise I do not see a solution.

The problem is that it will not just be missing from the compilation, but will also result in a type error during production build, because custom icon name is not assignable to the icon input property typed as IconName.

@jtinsley85
Copy link

I know we’re dealing with Angular here but, I was just reading through this and it made me think about how Material UI allows you to “Augment” types in custom theme implementations for React.js projects. Their documentation isn’t exhaustive when it comes to ALL the different use cases for this but would encourage you to check it out in case it could be a route to explore.

Scroll down till you see the “ declare module“ part.

https://material-ui.com/customization/palette/

@devoto13
Copy link
Collaborator Author

Thanks for the info @jtinsley85. This is exactly what I've been thinking about. Unfortunately such declarations are rather cumbersome. We only need icon name, but because declaration merging does not work with string literal unions we have to define such names as properties of the object.

@lightman76
Copy link

Just ran into this issue while upgrading my angular app. Has there been any progress/updates on this?

Wondering if instead of using the [icon] binding for the custom icons, instead add a [customIcon] binding for those with a more open typing. This would allow the [icon] binding to continue to use more strict types to enable autocomplete.

Based on what Devoto13 said above about it working today with some casts, it seems that both bindings could map to the same underlying property so hopefully wouldn't be too difficult to implement. I'm not very familiar with this codebase at this point, but if this sounds like an approach the maintainers would be ok with, I could take a stab at a pull request.

@devoto13
Copy link
Collaborator Author

devoto13 commented Jan 24, 2022

@lightman76 I think a customIcon binding is an interesting approach, but then we'll also need to add a customMask as mask binding takes icon as well. I'm somewhat hesitant about broadening the API in this way as it essentially is just a "native" way to opt-out of the type checking. IMO when you're opting out of type checking it is better to do it explicitly in your own code using [icon]="$any('icon')" or in the custom icon definition if you use explicit reference approach.

I've been returning to this issue couple of times, but there are just two approaches: remove type safety and completion for the native icons or very cumbersome type definitions as I've pointed out in this comment. I'm leaning towards the latter approach, but hope that something will happen in TypeScript to make it less cumbersome 😄 Your proposal looks like a better alternative to completely removing the type safety at the cost of the API complexity and I'm not sure if we should accept this trade-off 🤔

It's worth noting that the main blocker for this to move forward is the icon library approach (where one would pass icon name as a string). It is pretty straightforward to define a more relaxed version of the IconDefinition type and allow to pass it to the icon and mask bindings. I was holding that off to avoid making custom icons work only in some cases, but maybe we should ship it, so at least some users can make fewer casts.

@lightman76
Copy link

@devoto13 Thanks for the consideration. I agree that having to have a separate binding just for type checking reasons isn't ideal, especially if it looks like there is a possible solution from typescript in the future to handle this.

I had some time to play around with this more and I was able to use the casting method successfully (at least so far - haven't released to production yet - still working on migrating the rest of the project.) We have a centralized definition for our custom icons, so that's the only place it seems I needed to worry with the casting. We import all our icons as constants instead of referring to them by name, so didn't need to do any casting in the actual usages of fa-icon (yay!)

In case it helps anyone else, here's how I've defined our icons with the casting.

export const myIcon:IconDefinition = { prefix: 'myCustomPrefix' as IconPrefix, iconName: 'myIcon ' as IconName, icon: [65,65,[],"f908","M28.643 ... svg data....z"] };

@fplusf
Copy link

fplusf commented Jan 18, 2023

Also allowing to add SVG attributes like "fill-rule" and "clip-rule" for the element would greatly enhance creating & using custom icons. Probably it makes sense to include such a field in the IconDeifnion interface.

devoto13 added a commit to devoto13/angular-fontawesome that referenced this issue Apr 17, 2024
With this change `angular-fontawesome` exposes more permissive variants of some types (`IconPrefix`, `IconName`, `IconLookup`, `IconDefinition` and `IconPack`) from the `fontawesome-svg-core`. These new types allow arbitrary string values as icon name and icon prefix while maintaining auto-completion for the core Font Awesome icons.

Firstly, this makes it possible to define and use custom icons without any casts, thus implementing part of the FortAwesome#172 and addressing part of the FortAwesome#423 (Kit packages with custom icons). The documentation for custom icons is coming later in a separate PR.

Secondly, this makes `angular-fontawesome` resilient to multiple instance of `fontawesome-common-types` packages, thus helps with issues like FortAwesome#125.

The drawback of this change is that if a user makes a typo in a core icon name or an icon prefix it will no longer produce a compile-time error, but will throw a runtime error instead. However, this trade-off seems to be overall the best option. Considerations:

1. To keep type safety while supporting custom icons, we'll need to somehow extend the mentioned icon types. It was investigated in the FortAwesome#172 (comment). The conclusion is that it requires very convoluted code to be added to the project and therefore is undesired.
2. For the explicit reference approach, the type safety/completion is not really needed as icon definitions are imported as runtime symbols and importing a symbol which does not exist will always result in complication error.
3. For the icon library approach, the type safety isn't perfect either. While it will catch cases where one specifies a completely incorrect icon name, it does not catch all problems. Icons are added to the library at runtime and if an icon name is correct, but the icon was not added to the library it will still result in a runtime error.
devoto13 added a commit to devoto13/angular-fontawesome that referenced this issue Apr 17, 2024
With this change `angular-fontawesome` exposes more permissive variants of some types (`IconPrefix`, `IconName`, `IconLookup`, `IconDefinition` and `IconPack`) from the `fontawesome-svg-core`. These new types allow arbitrary string values as icon name and icon prefix while maintaining auto-completion for the core Font Awesome icons.

Firstly, this makes it possible to define and use custom icons without any casts, thus implementing part of the FortAwesome#172 and addressing part of the FortAwesome#423 (Kit packages with custom icons). The documentation for custom icons is coming later in a separate PR.

Secondly, this makes `angular-fontawesome` resilient to multiple instance of `fontawesome-common-types` packages, thus helps with issues like FortAwesome#125.

The drawback of this change is that if a user makes a typo in a core icon name or an icon prefix it will no longer produce a compile-time error, but will throw a runtime error instead. However, this trade-off seems to be overall the best option. Considerations:

1. To keep type safety while supporting custom icons, we'll need to somehow extend the mentioned icon types. It was investigated in the FortAwesome#172 (comment). The conclusion is that it requires very convoluted code to be added to the project and therefore is undesired.
2. For the explicit reference approach, the type safety/completion is not really needed as icon definitions are imported as runtime symbols and importing a symbol which does not exist will always result in complication error.
3. For the icon library approach, the type safety isn't perfect either. While it will catch cases where one specifies a completely incorrect icon name, it does not catch all problems. Icons are added to the library at runtime and if an icon name is correct, but the icon was not added to the library it will still result in a runtime error.
devoto13 added a commit that referenced this issue Apr 18, 2024
With this change `angular-fontawesome` exposes more permissive variants of some types (`IconPrefix`, `IconName`, `IconLookup`, `IconDefinition` and `IconPack`) from the `fontawesome-svg-core`. These new types allow arbitrary string values as icon name and icon prefix while maintaining auto-completion for the core Font Awesome icons.

Firstly, this makes it possible to define and use custom icons without any casts, thus implementing part of the #172 and addressing part of the #423 (Kit packages with custom icons). The documentation for custom icons is coming later in a separate PR.

Secondly, this makes `angular-fontawesome` resilient to multiple instance of `fontawesome-common-types` packages, thus helps with issues like #125.

The drawback of this change is that if a user makes a typo in a core icon name or an icon prefix it will no longer produce a compile-time error, but will throw a runtime error instead. However, this trade-off seems to be overall the best option. Considerations:

1. To keep type safety while supporting custom icons, we'll need to somehow extend the mentioned icon types. It was investigated in the #172 (comment). The conclusion is that it requires very convoluted code to be added to the project and therefore is undesired.
2. For the explicit reference approach, the type safety/completion is not really needed as icon definitions are imported as runtime symbols and importing a symbol which does not exist will always result in complication error.
3. For the icon library approach, the type safety isn't perfect either. While it will catch cases where one specifies a completely incorrect icon name, it does not catch all problems. Icons are added to the library at runtime and if an icon name is correct, but the icon was not added to the library it will still result in a runtime error.
devoto13 added a commit to devoto13/angular-fontawesome that referenced this issue Apr 20, 2024
devoto13 added a commit that referenced this issue Apr 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants