weixin_39747807
weixin_39747807
2020-11-28 20:32

Custom icons

Based on a custom SVG icon file I have, can styled icons be used as a mechanism to embed custom icons? How could I implement this feature in my project?

该提问来源于开源项目:styled-icons/styled-icons

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

16条回答

  • weixin_39590472 weixin_39590472 5月前

    Hey this isn't possible currently, but I've started work on the next version of this package which will have the ability to create custom icons alongside the built-in ones. So stay tuned... 🙂

    点赞 评论 复制链接分享
  • weixin_39590472 weixin_39590472 5月前

    Hey just wanted to let you know I haven't forgotten about this issue - custom icons aren't quite ready yet, but the latest release (v7.1.0) starts to lay the groundwork for supporting custom icons.

    If you'd like to provide some API feedback, you can try importing from an internal StyledIconBase component. I'd be curious to know how custom icons would be used in the wild.

    DISCLAIMER: this is an internal API and will likely break in a future release - you probably don't want to use this in production. This is not the final API.

    For instance, if this is your SVG:

    html
    <svg viewbox="0 0 24 24" fill="currentColor">
      <path fill="currentColor" d="M13 4c-3.859 0-7 3.141-7 7 0 .763.127 1.495.354 2.183l-.749.75-.511.512-1.008 1.045a3.076 3.076 0 0 0-.891 2.185 3.134 3.134 0 0 0 3.13 3.131c.757 0 1.504-.278 2.104-.784l.064-.055.061-.061 1.512-1.51.75-.749A6.983 6.983 0 0 0 13 18c3.859 0 7-3.141 7-7s-3.141-7-7-7zm0 12c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5zm0-9c-2.205 0-4 1.794-4 4s1.795 4 4 4 4-1.794 4-4-1.795-4-4-4zm0 7a3.001 3.001 0 0 1 0-6 3.001 3.001 0 0 1 0 6z"></path>
    </svg>
    

    You could create a custom icon like so:

    typescript
    import * as React from 'react'
    import {StyledIconBase} from 'styled-icons/StyledIconBase'
    
    const CustomIcon = React.forwardRef((props, ref) => {
      // Additional attributes to add to the <svg> tag
      const attrs = {
        fill: 'currentColor',
      }
    
      return (
        <stylediconbase iconattrs="{attrs}" iconverticalalign="middle" iconviewbox="0 0 24 24" ref="{ref}">
          <path fill="currentColor" d="M13 4c-3.859 0-7 3.141-7 7 0 .763.127 1.495.354 2.183l-.749.75-.511.512-1.008 1.045a3.076 3.076 0 0 0-.891 2.185 3.134 3.134 0 0 0 3.13 3.131c.757 0 1.504-.278 2.104-.784l.064-.055.061-.061 1.512-1.51.75-.749A6.983 6.983 0 0 0 13 18c3.859 0 7-3.141 7-7s-3.141-7-7-7zm0 12c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5zm0-9c-2.205 0-4 1.794-4 4s1.795 4 4 4 4-1.794 4-4-1.795-4-4-4zm0 7a3.001 3.001 0 0 1 0-6 3.001 3.001 0 0 1 0 6z"></path>
        </stylediconbase>
      )
    })
    
    CustomIcon.displayName = 'CustomIcon'
    </svg>

    And if you use TypeScript and want the types to match:

    typescript
    import * as React from 'react'
    import {StyledIconBase} from 'styled-icons/StyledIconBase'
    
    const CustomIcon = React.forwardRef<svgsvgelement stylediconprops>((props, ref) => {
      const attrs: React.SVGProps<svgsvgelement> = {
        fill: 'currentColor',
      }
    
      return (
        <stylediconbase iconattrs="{attrs}" iconverticalalign="middle" iconviewbox="0 0 24 24" ref="{ref}">
          <path fill="currentColor" d="M13 4c-3.859 0-7 3.141-7 7 0 .763.127 1.495.354 2.183l-.749.75-.511.512-1.008 1.045a3.076 3.076 0 0 0-.891 2.185 3.134 3.134 0 0 0 3.13 3.131c.757 0 1.504-.278 2.104-.784l.064-.055.061-.061 1.512-1.51.75-.749A6.983 6.983 0 0 0 13 18c3.859 0 7-3.141 7-7s-3.141-7-7-7zm0 12c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5zm0-9c-2.205 0-4 1.794-4 4s1.795 4 4 4 4-1.794 4-4-1.795-4-4-4zm0 7a3.001 3.001 0 0 1 0-6 3.001 3.001 0 0 1 0 6z"></path>
        </stylediconbase>
      )
    })
    
    CustomIcon.displayName = 'CustomIcon'
    </svgsvgelement></svgsvgelement>

    That CustomIcon would have all the behaviors and properties of any other Styled Icon and would also match the StyledIcon TypeScript type, in case you have any components that accept an icon as a prop.

    Again, that's an internal API, and the final custom icon API will likely be considerably simpler, like createStyleIcon(<svg>...</svg>) or even something like a Webpack loader, but I would appreciate any feedback on potential use-cases or desired features.

    点赞 评论 复制链接分享
  • weixin_39747807 weixin_39747807 5月前

    I was using a similar approach/pattern for custom icons. I created a base component and then the icon was the SVG passed as props. Will look into it deeper to see how it could integrate well with the pattern you're proposing. Thanks.

    点赞 评论 复制链接分享
  • weixin_39913422 weixin_39913422 5月前

    Would it be possible to extract the component generation code into a cli so custom icons could be made as a step in the build process?

    点赞 评论 复制链接分享
  • weixin_39590472 weixin_39590472 5月前

    Would it be possible to extract the component generation code into a cli so custom icons could be made as a step in the build process?

    Most likely yes - I've been slowly working on this feature, and after complete, Styled Icons will read the icon SVG data as a JSON file, so it should be fairly straightforward to have a CLI that converts existing SVG files into that JSON format.

    点赞 评论 复制链接分享
  • weixin_39520869 weixin_39520869 5月前

    Hey there any chance this feature is nearing production ready?

    点赞 评论 复制链接分享
  • weixin_39808953 weixin_39808953 5月前

    Any more updates on this feature?

    点赞 评论 复制链接分享
  • weixin_39720865 weixin_39720865 5月前

    I guess not ready for me yet. Going for my old style ico-moon, Really interested in this once ready.

    点赞 评论 复制链接分享
  • weixin_39881575 weixin_39881575 5月前

    I was looking at taking a stab at this. Was just curious if you had any other guidance you might want the API to look like?

    Would createIcon take a JSX.Element or a string? Would you want to cover SVG optimizing or leave that to the users?

    点赞 评论 复制链接分享
  • weixin_39590472 weixin_39590472 5月前

    I was looking at taking a stab at this

    Awesome, very appreciated! 🎉

    Would createIcon take a JSX.Element or a string? Would you want to cover SVG optimizing or leave that to the users?

    I don't have any strong preferences here, though we'd potentially want to avoid shipping an SVG optimizer into the client bundle. Right now the optimized SVG data is passed to StyledIconBase here: https://github.com/jacobwgillespie/styled-icons/blob/master/packages/styled-icons/generate/templates/StyledIconBase.tsx. We could formalize that API.

    But overall I'm open to any ideas and don't have any prescriptions!

    点赞 评论 复制链接分享
  • weixin_39881575 weixin_39881575 5月前

    I don't have any strong preferences here, though we'd potentially want to avoid shipping an SVG optimizer into the client bundle. Right now the optimized SVG data is passed to StyledIconBase here: /packages/styled-icons/generate/templates/StyledIconBase.tsx . We could formalize that API.

    I agree that shipping an optimizer is less than desirable. I would opt to leave that up to the user.

    I'm not sure what the common use-case is here for JSX.Element vs string. Does anyone have any examples? JSX.Element would definitely be easier to accept. A string would require something like dangerouslySetInnerHTML to insert the string.

    点赞 评论 复制链接分享
  • weixin_39957805 weixin_39957805 5月前
    jsx
    import React from 'react'
    import { StyledIconBase } from 'styled-icons/StyledIconBase'
    import TeamSvg from 'static/gfx/svg/team.csvg'
    
    // Generic handling
    export const Custom = ({ svg, size = 24, className, ...props }) => {
        const { props: svgProps } = svg()
        const { children, ...attrs } = svgProps
    
        return (
            <stylediconbase width="{size}" height="{size}" iconverticalalign="middle" classname :>
                {children}
            </stylediconbase>
        )
    }
    
    // Specific icons
    export const Team = props => (
        <custom svg="{TeamSvg}"></custom>
    )
    

    Just got this working quite nicely with the /webpack plugin. Calling the SVG component as a function feels kind of dirty, but it works.

    Is it as dirty as it feels, or is it alright? Also, was any progress made on this issue since last year, removing the need for this hack?

    点赞 评论 复制链接分享
  • weixin_39831991 weixin_39831991 5月前

    Any movement on this? would love to have this feature

    点赞 评论 复制链接分享
  • weixin_39640762 weixin_39640762 5月前

    any updates on this?

    点赞 评论 复制链接分享
  • weixin_39590472 weixin_39590472 5月前

    Hey all, no updates yet, but if you had to describe how you'd like this feature to work, I'd appreciate any feedback here! I haven't personally had the need to add custom icons to Styled Icons, so any insights into what you'd expect would be extra helpful!

    点赞 评论 复制链接分享
  • weixin_39957805 weixin_39957805 5月前

    For me personally it’s about replicating

    1. the visual appearance and behavior
    2. all the accessibility stuff you provide under the hood

    The visual stuff is mostly about making sure sizes are consistent; a custom icon should use the same amount of its bounding box as the bundled icons, and of course be centered.

    The accessibility stuff is mostly about having sane defaults applied; basically to make it possible to use the same API as with the bundled icons.

    点赞 评论 复制链接分享

相关推荐