react-fontawesome icon indicating copy to clipboard operation
react-fontawesome copied to clipboard

Add support for DuoTone

Open dancrumb opened this issue 5 years ago • 22 comments

Is your feature request related to a problem? Please describe. Add support for DuoTone, as announced by https://blog.fontawesome.com/introducing-duotone/

Describe the solution you'd like Updating the component to support the various features listed in the blog post

Describe alternatives you've considered The alternative is to glom classes onto the component

Additional context Add any other context or screenshots about the feature request here.

dancrumb avatar Jul 30 '19 18:07 dancrumb

I believe this cheatsheet covers the specific duotone functionality that needs to be accounted for in React Font Awesome. There are 4 new custom properties and 1 new class.

--fa-primary-opacity
--fa-secondary-opacity
--fa-primary-color
--fa-secondary-color	
fa-swap-opacity

kevinwhoffman avatar Jul 30 '19 19:07 kevinwhoffman

I am paying for PRO and can't use it because it was not simultaneously released in all FontAwesome packages. 🤦‍♂

ivosabev avatar Aug 14 '19 15:08 ivosabev

@ivosabev

You can use it right now. However, if you want to change colours and opacity to something other than the defaults applied by duotone styling, you have to use class selectors rather than attributes.

Install

npm i --save @fortawesome/pro-duotone-svg-icons

Import

import { faTimes } from '@fortawesome/pro-duotone-svg-icons';

Style

In css

.my-icon .fa-primary {
   fill: #1a237e;
   opacity: 0.5;
}
.my-icon .fa-secondary {
   fill: #c62828;
   opacity: 0.8;
}
<FontAwesomeIcon className="my-icon" icon={faTimes} />

knightjdr avatar Aug 14 '19 17:08 knightjdr

This should be somewhere in the docs, also props support was what I was originally looking for. Thanks!

ivosabev avatar Aug 18 '19 15:08 ivosabev

Is there a timeline for release on this? We're at the three week mark or so now from the release of Duotones but it's awfully quiet in here.

joshsmith avatar Aug 19 '19 09:08 joshsmith

My concern is how can I use "far" as well as "fad" together? If I import it as

import { faTimes } from '@fortawesome/pro-duotone-svg-icons'; and now I also want faTimes from regular, so I'll import it again, correct?

import { faTimes } from '@fortawesome/pro-regular-svg-icons'; This creates a conflict. I can surely import this one using 'as' like following

import { faTimes as faRegularTimes} from '@fortawesome/pro-regular-svg-icons'; But then the problem is with library.add(). If I add them both, like library.add(faTimes, faRegularTimes); will the library be able to understand what name to lookup?

For example if I call something like this <FontAwesomeIcon icon="['far', 'times']"/>

will it be able to know that I'm calling the regular one, not the doutone one?

I'm sorry I'm not an expert in ReactJs. I tried this method through guess work and it doesn't seem to work.

prabhat1992 avatar Aug 23 '19 13:08 prabhat1992

@prabhat1992 Yes, if you import { faTimes as faTimesSolid } from ... and import { faTimes as faTimesDuo } from ..., you can add both to the library and it'll work.

The reason you can't get it to work is that you're supplying the array as a string <FontAwesomeIcon icon="['far', 'times']"/> when you should supply it as an object:

<FontAwesomeIcon icon={['far', 'times']}/>

designbyadrian avatar Aug 30 '19 07:08 designbyadrian

For the colors you can do for example:

<FontAwesomeIcon
      icon={['fad', 'stroopwafel']}
      size="4x"
      style={{ '--fa-primary-color': 'red' }}
/>

raRaRa avatar Sep 25 '19 14:09 raRaRa

This has been released in 0.1.5

robmadole avatar Sep 29 '19 13:09 robmadole

@robmadole this shouldn't be closed IMHO; since it's only partly addressed. swapOpacity was implemented, but nothing about colors

cyrilchapon avatar Dec 06 '19 06:12 cyrilchapon

@cyrilchapon color works using CSS as documented here. Were you expecting something else?

robmadole avatar Dec 06 '19 13:12 robmadole

@robmadole,

Were you expecting something else? Yes actually ! this behavior is pretty different from how color works... doesn't it ?

IMHO, keeping color (mapped to css color or --primary-color) depending on the case, somehow), and adding secondaryColor, primaryOpacity, secondaryOpacity would be preferable.

Opacities can be more discussed, I have to say; but definately --primary-color and --secondary-color sound strange for React users.

The use-case and the friction is real. I'm using "react-fontawesome" for a while now, and my designer just asked us to display a duotone one. I faced this friction

cyrilchapon avatar Dec 06 '19 14:12 cyrilchapon

@cyrilchapon those are CSS Custom Properties so while that syntax (--fa-primary-color) may feel strange is part of the spec.

I'm resisting quite strongly adding a component prop like primaryColor or secondaryOpacity because it would simply mask the underlying technology. What I've seen so far is there is an objection from a lot of devs and designers to use the inline style to set these custom properties on the icon:

<FontAwesomeIcon icon={['fad', 'stroopwafel']} style={{ '--fa-primary-color': 'eggplant' }} />

This resistance is healthy and usually leads to organizing the custom properties in an external CSS file, using Styled-Components, or Webpack-assisted CSS Modules. This is better than inline styling.

What are your thoughts on this? What did you end up doing to implement the color?

robmadole avatar Dec 06 '19 14:12 robmadole

is part of the spec

The core font-awesome spec, actualy. What I'm challenging is the React wrapper spec.

it would simply mask the underlying technology So as for raw color (no duotone icons) which has been done for months now, isn't it ?

And actually; "masking the underlying tech" is... the point of a wrapper, in a certain way. I got your point, but IMHO it would just be a helper (just like color); overridable via css with the core spec.

This resistance is healthy and usually leads to organizing the custom properties in an external CSS file, using Styled-Components, or Webpack-assisted CSS Modules. This is better than inline styling.

"Better" is a point of view. I challenge this one, even if your point is a great one. It's "better" in term of performance and asset-sizing only. But still; your point is applicable to color. And still, it wouldn't disallow someone to use such a technology to compress the styles. It's not "better" at all in terms of consistency. When you have transform, size and color defined as props; and you want to change the color; you would go through css-in-js in your mind ? Well, the context you describe is exactly mine, I'm using emotion.js for now, which is a powerful css-in-js technology. I compress every style through classes in my project (with some styled() component, and css templates that leads to classes); but I tell you : I made the choice to explicitly use style just for the line of code of the FontAwesome Icon, for the sake of simplicity, and consistency. Just because putting some css-in-js here would lead to some crazy syntax / props passing / hoisting need that one just to want to tweak an icon color. This is only a point of view, but this is another one.

cyrilchapon avatar Dec 06 '19 15:12 cyrilchapon

When I say "spec" I'm actually referring to this.

And actually; "masking the underlying tech" is... the point of a wrapper, in a certain way. I got your point, but IMHO it would just be a helper (just like color); overridable via css with the core spec.

Not if masking the underlying tech is harmful to overall development. And this is where the difference comes for me and why I push back against adding it like transform or size. I would consider it an anti-pattern to use a primaryColor component property when better solutions should be encouraged.

"Better" is a point of view

Absolutely. And I appreciated you taking the time to explain your use case.

When you have transform, size and color defined as props; and you want to change the color; you would go through css-in-js in your mind ?

The vital part of this is that Duotone introduces the use of something completely new to Font Awesome: CSS Custom Properties. So this is less to do with how a developer deals with Font Awesome and its use of custom properties but custom properties for their entire project. What would be inconsistent is to be required to learn every custom component API that exposes component props for setting CSS Custom Properties. Using custom properties should be consistent across the project (however that decision is made; inline styles, helpers, CSS Modules, emotion.js, etc.)

I made the choice to explicitly use style just for the line of code of the FontAwesome Icon, for the sake of simplicity, and consistency. Just because putting some css-in-js here would lead to some crazy syntax / props passing / hoisting need that one just to want to tweak an icon color.

I would love to see an example of this craziness. In my mind it shouldn't be any different than setting any other CSS property like "color" or "margin" or "font-size". Maybe I'm missing something?

(re-opening this issue since you have made some great points)

robmadole avatar Dec 06 '19 15:12 robmadole

What would be inconsistent is to be required to learn every custom component API that exposes component props for setting CSS Custom Properties.

I'm sorry if I'm missing something here, but why is that any different than being required to learn every CSS Customer property directly? Component props do autocomplete in editors like Code, inline CSS Custom Properties don't (for me, I'm not sure that's for everyone the case).

In my personal experience: if these were a prop, I'd have been able to guess them. Now I had to look around for an efficient way to do this which I only found in this issue.

Studio384 avatar Dec 20 '19 10:12 Studio384

I share the same sentiment as @Studio384 so I made a workaround component in TypeScript:

import React from 'react';
import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome';


interface IDuotoneFontAwesomeIconProps extends FontAwesomeIconProps {

    primaryColor?: string,
    secondaryColor?: string

}


type TFontAwesomeProperties = {

 '--fa-primary-color'?: string,
 '--fa-secondary-color'?: string,

}

export function DuotoneFontAwesomeIcon(props: IDuotoneFontAwesomeIconProps) {

    const primaryColor: string | undefined = props.primaryColor;
    const secondaryColor: string | undefined = props.secondaryColor;

    const style: (React.CSSProperties & TFontAwesomeProperties) = props.style ? {...props.style} : {};
    style['--fa-primary-color'] = primaryColor;
    style['--fa-secondary-color'] = secondaryColor;

    return (

        <FontAwesomeIcon
            { ...props }
            style={ style }
        />

    )
}

With this workaround, you can use the following:

<DuotoneFontAwesomeIcon
    icon={faSomeCoolIcon}
    primaryColor={'#F0F'}
    secondaryColor={'#0FF'}
/>

While it's not an ideal solution by any means, it prevents me from accidentally mistyping a CSS property name and offers code completion in WebStorm. I agree that not every variant of an icon should have its own set of properties to learn; however, if the icon adds significant functionality (which I believe duotone icons do), then I would prefer that significant functionality to be explicitly defined.

I don't agree that separating primary and secondary colors into a prop is an anti-pattern; I don't see the difference between this and the existing color prop. If there is an anti-pattern here, its passing custom/faux CSS style attributes as pseudo-props. A quick alternative is to allow a string prop or an object prop with primary and secondary defined, however that results in primary/secondary being ambiguous for non-duotone icons.

Additionally, TypeScript users will see errors about non-standard prop style keys as they are not part of the standard CSSProperties type object. This can be mitigated by FontAwesome adding custom attributes to the style?: CSSProperties definition on the FontAwesomeIconProps itself which may offer an interim solution to the issue as a whole although I maintain that custom/faux CSS styles are not the 'React' way to do this.

All a matter of taste in the end, but thank you and your team for duotone icons as whole, they're a refreshing take on icons!

JohnPersano avatar Aug 15 '20 16:08 JohnPersano

Is it possible to just add the functionality that already exist in react-native-fontawesome?

Duotone

<FontAwesomeIcon icon="coffee" color="blue" secondaryColor="red" secondaryOpacity={ 0.4 } />

You can specify the color and opacity for Duotone's secondary layer using the secondaryColor and secondaryOpacity props. Note that these are optional, and will simply default to using your primary color at 40% opacity.

https://github.com/FortAwesome/react-native-fontawesome#duotone

bolarson avatar Aug 18 '20 18:08 bolarson

so seems like it's still not resolved? Any updates on this?

pasevin avatar Nov 30 '21 12:11 pasevin

@pasevin what kind of update are you looking for?

robmadole avatar Nov 30 '21 20:11 robmadole

@pasevin what kind of update are you looking for?

What @bolarson said gets my vote

jacobbroughton avatar Dec 07 '21 16:12 jacobbroughton

Seems not to be a priority :(

pinonpierre avatar Sep 22 '22 15:09 pinonpierre

We are not going to add props to control CSS custom properties. I'm closing this since this component supports Duotone icons already.

If users want to use properties to control this they will have to write their own wrappers around the component.

robmadole avatar Oct 03 '22 14:10 robmadole

I share the same sentiment as @Studio384 so I made a workaround component in TypeScript:

import React from 'react';
import { FontAwesomeIcon, FontAwesomeIconProps } from '@fortawesome/react-fontawesome';


interface IDuotoneFontAwesomeIconProps extends FontAwesomeIconProps {

    primaryColor?: string,
    secondaryColor?: string

}


type TFontAwesomeProperties = {

 '--fa-primary-color'?: string,
 '--fa-secondary-color'?: string,

}

export function DuotoneFontAwesomeIcon(props: IDuotoneFontAwesomeIconProps) {

    const primaryColor: string | undefined = props.primaryColor;
    const secondaryColor: string | undefined = props.secondaryColor;

    const style: (React.CSSProperties & TFontAwesomeProperties) = props.style ? {...props.style} : {};
    style['--fa-primary-color'] = primaryColor;
    style['--fa-secondary-color'] = secondaryColor;

    return (

        <FontAwesomeIcon
            { ...props }
            style={ style }
        />

    )
}

With this workaround, you can use the following:

<DuotoneFontAwesomeIcon
    icon={faSomeCoolIcon}
    primaryColor={'#F0F'}
    secondaryColor={'#0FF'}
/>

Thank you @JohnPersano ! This works beautifully!! I was even able to follow your example to add in primary and secondary opacitys!! (not sure if I spelled that right) But in my app, I was able to swap the looks of the icon on click like so: image image

dmikester1 avatar Mar 29 '23 20:03 dmikester1