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

feat(icons): add @fluentui/react-icons package #12608

Merged
merged 22 commits into from Apr 13, 2020

Conversation

mnajdova
Copy link
Contributor

@mnajdova mnajdova commented Apr 8, 2020

This PR is adding new @fluentui/react-icons package that will contain utilities for creating icons, as well as set of svg icons.

There are currently two proposals on the svg factory function:

  1. createSvgIcon that can be used in the following manner:
// Users may provide additional props
const OneDriveIcon = createSvgIcon<{/* addition custom props if any */}>({
  // full signiture ({ classes, props }) - we may add rtl here too
  svg: ({ classes }) => ( // classes are processed classes for the different slots inside the icon (for example svg)
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0,0,2048,2048" className={classes.svg}>
      <g fill="#1B559B">
        <path d="M 1860 ...." />
      </g>
    </svg>
  ),
  displayName: 'OneDriveIcon', // the name for the icon that will appear in the React tree
});

The root span element with all processed props is created automatically here inside the createSvgIcon factory.

One we decide on the factory used, I will migrate all svg icons.

NEEDS SOME HELP/SUGGESTIONS

Things that we need to decide on:

  • witch factory we want to use or do we want to keep both? - keep createSvgIcon
  • do we want to use rtl from the theme, or provide separate context for it? - will be added as next step
  • do we want to align on a same API for the SvgIconProps on v0 and v7, or should we keep the API simple for the v7? - This will help when we want to merge the icons set - will be aligned as next step


export type SvgIconFuncArg<TProps = ISvgIconProps> = {
classNames: { [iconSlot: string]: string }; // renamed from classes
// rtl: boolean; // how do we support this?
Copy link
Member

@dzearing dzearing Apr 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useRTL hook possibly with an RTL specific context would be ideal. Both v0 and v7 have the rtl flag on the theme object and I don't really see a great way other than React context to get an accurate value unless we just don't support scoped theming.

const YammerIcon = createSvgIcon({
svg: ({ classNames }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0,0,2048,2048">
<g className="thing">
Copy link
Member

@dzearing dzearing Apr 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

className="thing", also classNames doesn't seem to be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this className is being used in an example, but this doesn't seem like a good pattern to demonstrate in general. Maybe find another way to re-style the element for the example?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I just copied this examples from the Icon.Svg.Example.tsx. Will create new example with showcase of how the things inside the svgs can be styled

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored and improved examples. Please take a look.


const OneDriveIcon = createSvgIcon({
svg: ({ classNames }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0,0,2048,2048">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should classNames get injected on the root?

Copy link
Contributor Author

@mnajdova mnajdova Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createSvgIcon is doing that. I have two alternatives of the factory once that is for injecting only the svg and another one that allows user to have custom props and define the root element too. Let's see if we will need the both or choose one

Copy link
Member

@ecraig12345 ecraig12345 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments but it's mostly smaller things. It would also be good if you could update the PR description with a higher-level overview of what you're doing.

packages/react-icons/README.md Outdated Show resolved Hide resolved
const YammerIcon = createSvgIcon({
svg: ({ classNames }) => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0,0,2048,2048">
<g className="thing">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this className is being used in an example, but this doesn't seem like a good pattern to demonstrate in general. Maybe find another way to re-style the element for the example?

displayName: 'BorderBlindsIcon',
});

export default BorderBlindsIcon;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we discussed whether we want to use default or named exports in new code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, I just used whatever I was used to :S Let me know what makes more sense and will update it..

Copy link
Member

@dzearing dzearing Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original thinking with not exporting default was:

A downstream index.ts file might do something like:

export * from './BorderBlindsIcon';

Which would not include the default export, but only named ones. That said, we have seen concerns multiple times about export *. And there is NO friction in exporting { default as Foo } explicitly; explicit exports are better anyway in that we don't accidentally leak something unintentionally.

So my 2c is "it's fine".

packages/react-icons/src/utils/createSvgIcon.ts Outdated Show resolved Hide resolved
packages/react-icons/src/utils/createSvgIcon.ts Outdated Show resolved Hide resolved
{
...containerProps,
...nativeProps,
className: css(MS_ICON, classNames.root, className),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning for using MS_ICON on the new icons?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it's nice to have some common classname for all icons. Not sure if this is the right name for it, but we can change it..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, I'd let the author bring them for the new icons and keep them as vanilla as possible. We made the mistake of using ms-Icon for the existing Icon component and have seen a number of issues where developers do things like:

.ms-Icon { font-size: 22px !important; }

We can certainly add them later, but let's try without for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove it!

mnajdova and others added 7 commits April 9, 2020 11:29
Co-Authored-By: David Zearing <dzearing@microsoft.com>
Co-Authored-By: David Zearing <dzearing@microsoft.com>
Co-Authored-By: Elizabeth Craig <ecraig12345@gmail.com>
Co-Authored-By: Elizabeth Craig <ecraig12345@gmail.com>
-removed circular dependencies
@mnajdova
Copy link
Contributor Author

mnajdova commented Apr 9, 2020

@ecraig12345 & @dzearing thanks for the early review. Please take another look on the example/usages and the PR description and let's decide on the unknowns so we can faster move the svgs inside the package.

@mnajdova
Copy link
Contributor Author

See also PR: #12641 which is adding all svg icons

@mnajdova mnajdova changed the title [WIP] feat(icons): add @fluentui/react-icons package feat(icons): add @fluentui/react-icons package Apr 10, 2020
@dzearing
Copy link
Member

Which factory we want to use or do we want to keep both?

I would prefer to avoid "withRoot" variant. Is there any reason that the svg can't be considered the root? Is there a benefit of wrapping it in a span?

Do we want to use rtl from the theme, or provide separate context for it?

I don't think you need to resolve that yet but I think it belongs in a separate context that's easy to reuse without betting on the entire theme. I keep wanting to gravitate to a useRtl hook, so that I can make decisions in code. I think this would belong in the standardized theming context package once we make one :)

Do we want to align on a same API for the SvgIconProps on v0 and v7, or should we keep the API simple for the v7? - This will help when we want to merge the icons set

Alignment would be awesome, but what specifically? (I don't think this blocks this checkin, but curious specifically which props you want to converge.)

Copy link
Member

@dzearing dzearing left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this is a v0 and subject to change, it doesn't have to be perfect. I'd like to get this checked in so that we can try out the icons and adjust as needed!

const { color1 = 'red', color2 = 'green', color3 = 'blue' } = props;

// custom styles for the border blinds
const borderBlindsPart1 = mergeStyles({
Copy link
Member

@dzearing dzearing Apr 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid class names to represent styles which could mutate frequently. Could we use inline styles or css variables?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(don't let this block checkin, but I think it's important to get the right pattern to replicate.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added inline styles for now. Anyway in the next PR this icon will be remomved, so wouldn't like to spend much time on it..

import createSvgIcon from '../utils/createSvgIcon';

const OneDriveIcon = createSvgIcon({
svg: ({ classes }) => (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor suggestion/thought:

will there ever be more than 1 class name here? Maybe it should just be className.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In our experience with react-icons-northstar there are cases like this, so would rather leave it as is at this moment as it is easier for extending this way and won't introduce necessity for changes in all icons in the future..

const Component: React.FC<React.HTMLAttributes<HTMLSpanElement> & TProps & ISvgIconProps> = props => {
const { className, style = {} } = props;

const nativeProps = getNativeProps<React.HTMLAttributes<HTMLElement>>(props, htmlElementProperties);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Icons are a hot spot in perf of an app, as they can be rendered tons of times. I wonder if it makes sense to just avoid any unnecessaries altogether:

// get all the things and have ...rest
const { color1, color2, color3, className, ...rest } = props;

return (
  <span 
    role="presentation"
    aria-hidden="true" 
    {...rest} 
    className={cx(classes, className)} 
  />);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but that would mean that we may end up with wrong props on the root, which is not the case with any other component in both libraries... Would rather merge it as is now and we can measure perf and decide in the next phase...

@mnajdova
Copy link
Contributor Author

@ecraig12345 can you double check the dependencies version. I used yarn create-package, but it seems like meanwhile there were some updates on the dependencies.. I check those manually, but would be nice to have ea second par of eyes on them. Thank you!

@size-auditor
Copy link

size-auditor bot commented Apr 13, 2020

Asset size changes

Size Auditor did not detect a change in bundle size for any component!

Baseline commit: d4e4953524017e8e8238cc245eaa83e91dec66c9 (build)

@msft-github-bot
Copy link
Contributor

msft-github-bot commented Apr 13, 2020

Perf Analysis

No significant results to display.

All results

Scenario Master Ticks PR Ticks Iterations Status
BaseButton 709 721 5000
Checkbox 1618 1615 5000
CheckboxBase 1276 1246 5000
ChoiceGroup 4744 4747 5000
ComboBox 870 872 1000
CommandBar 6511 6654 1000
DefaultButton 853 879 5000
DetailsRow 2585 2887 5000
DetailsRow (fast icons) 2805 2654 5000
DetailsRow without styles 2427 2449 5000
Dialog 1078 1088 1000
DocumentCardTitle with truncation 1321 1369 1000
Dropdown 2272 2229 5000
FocusZone 1213 1242 5000
IconButton 1292 1252 5000
Label 373 357 5000
Link 365 341 5000
MenuButton 1064 1064 5000
Nav 2827 2444 1000
Panel 1353 1355 1000
Persona 633 618 1000
Pivot 995 1020 1000
PrimaryButton 910 890 5000
SearchBox 1169 1121 5000
Slider 1391 1410 5000
Spinner 294 288 5000
SplitButton 2319 2369 5000
Stack 368 323 5000
Stack with Intrinsic children 861 861 5000
Stack with Text children 3071 3012 5000
TagPicker 2097 2073 5000
Text 264 280 5000
TextField 1317 1291 5000
Toggle 660 636 5000
button 42 44 5000

Perf Analysis (Fluent)

Perf comparison
Status Scenario Fluent TPI Fabric TPI Ratio Iterations Ticks
🔧 Avatar.Fluent 0.52 0.45 1.16:1 2000 1037
🦄 Button.Fluent 0.09 0.16 0.56:1 5000 440
🔧 Checkbox.Fluent 0.68 0.35 1.94:1 1000 684
🔧 Dialog.Fluent 0.37 0.18 2.06:1 5000 1846
🔧 Dropdown.Fluent 3.7 0.42 8.81:1 1000 3703
🔧 Icon.Fluent 0.13 0.04 3.25:1 5000 641
🦄 Image.Fluent 0.06 0.09 0.67:1 5000 324
🔧 Slider.Fluent 1.51 0.38 3.97:1 1000 1512
🔧 Text.Fluent 0.06 0.02 3:1 5000 316
🦄 Tooltip.Fluent 0.11 14.85 0.01:1 5000 556

🔧 Needs work     🎯 On target     🦄 Amazing

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
ButtonMinimalPerf.default 142 126 1.13:1
FormMinimalPerf.default 927 860 1.08:1
RadioGroupMinimalPerf.default 517 479 1.08:1
Icon.Fluent 641 601 1.07:1
AttachmentSlotsPerf.default 2528 2411 1.05:1
BoxMinimalPerf.default 296 282 1.05:1
DialogMinimalPerf.default 1727 1637 1.05:1
HierarchicalTreeMinimalPerf.default 965 924 1.04:1
Tooltip.Fluent 556 534 1.04:1
CheckboxMinimalPerf.default 3071 2973 1.03:1
MenuMinimalPerf.default 1973 1921 1.03:1
ProviderMinimalPerf.default 614 596 1.03:1
SliderMinimalPerf.default 1527 1486 1.03:1
TableMinimalPerf.default 650 632 1.03:1
ToolbarMinimalPerf.default 1078 1046 1.03:1
TreeMinimalPerf.default 1148 1119 1.03:1
Dialog.Fluent 1846 1791 1.03:1
CardMinimalPerf.default 346 338 1.02:1
DropdownManyItemsPerf.default 1366 1335 1.02:1
ItemLayoutMinimalPerf.default 1980 1947 1.02:1
LayoutMinimalPerf.default 610 600 1.02:1
PortalMinimalPerf.default 264 258 1.02:1
RefMinimalPerf.default 185 181 1.02:1
SplitButtonMinimalPerf.default 3486 3406 1.02:1
TextMinimalPerf.default 330 323 1.02:1
Dropdown.Fluent 3703 3616 1.02:1
GridMinimalPerf.default 795 789 1.01:1
ImageMinimalPerf.default 325 323 1.01:1
LabelMinimalPerf.default 366 363 1.01:1
SegmentMinimalPerf.default 1032 1022 1.01:1
TooltipMinimalPerf.default 830 819 1.01:1
Avatar.Fluent 1037 1028 1.01:1
Slider.Fluent 1512 1496 1.01:1
HeaderMinimalPerf.default 509 507 1:1
LoaderMinimalPerf.default 1072 1073 1:1
ProviderMergeThemesPerf.default 1443 1439 1:1
VideoMinimalPerf.default 823 824 1:1
Checkbox.Fluent 684 682 1:1
CarouselMinimalPerf.default 562 570 0.99:1
ChatMinimalPerf.default 537 545 0.99:1
DropdownMinimalPerf.default 3670 3692 0.99:1
HeaderSlotsPerf.default 1601 1621 0.99:1
ListWith60ListItems.default 1232 1250 0.99:1
ReactionMinimalPerf.default 2356 2375 0.99:1
StatusMinimalPerf.default 612 620 0.99:1
CustomToolbarPrototype.default 3699 3728 0.99:1
Button.Fluent 440 443 0.99:1
Image.Fluent 324 327 0.99:1
Text.Fluent 316 320 0.99:1
ListMinimalPerf.default 426 435 0.98:1
PopupMinimalPerf.default 228 233 0.98:1
AlertMinimalPerf.default 525 539 0.97:1
AttachmentMinimalPerf.default 125 129 0.97:1
EmbedMinimalPerf.default 5366 5538 0.97:1
FlexMinimalPerf.default 268 276 0.97:1
ListNestedPerf.default 908 939 0.97:1
MenuButtonMinimalPerf.default 1483 1524 0.97:1
TextAreaMinimalPerf.default 3104 3188 0.97:1
AccordionMinimalPerf.default 197 206 0.96:1
AvatarMinimalPerf.default 504 525 0.96:1
ButtonSlotsPerf.default 577 604 0.96:1
ChatWithPopoverPerf.default 578 603 0.96:1
ChatDuplicateMessagesPerf.default 371 389 0.95:1
DividerMinimalPerf.default 856 905 0.95:1
InputMinimalPerf.default 1025 1076 0.95:1
IconMinimalPerf.default 570 597 0.95:1
TreeWith60ListItems.default 204 217 0.94:1
ListCommonPerf.default 978 1051 0.93:1
AnimationMinimalPerf.default 594 663 0.9:1

@msft-github-bot
Copy link
Contributor

🎉office-ui-fabric-react@v7.106.1 has been released which incorporates this pull request.:tada:

Handy links:

DuanShaolong pushed a commit to DuanShaolong/fluentui that referenced this pull request Apr 27, 2020
* wip

* -added example svg icons

* -added props support by diff factory

* Update packages/react-icons/src/components/BorderBlindsIcon.tsx

Co-Authored-By: David Zearing <dzearing@microsoft.com>

* Update packages/react-icons/src/components/BorderBlindsIcon.tsx

Co-Authored-By: David Zearing <dzearing@microsoft.com>

* Update packages/react-icons/src/utils/createSvgIcon.ts

Co-Authored-By: Elizabeth Craig <ecraig12345@gmail.com>

* Update packages/react-icons/README.md

Co-Authored-By: Elizabeth Craig <ecraig12345@gmail.com>

* -cleanups
-removed circular dependencies

* -removed comments

* -improvements

* -exported utilities

* -updated readme

* -addressed comments

* -added tests

* -added dependencies

* -removed merge conflicts changes

* -picked changes from master

* -reverted changes

* -updated package json

* Change files

* Adding snapshot.

Co-authored-by: David Zearing <dzearing@microsoft.com>
Co-authored-by: Elizabeth Craig <ecraig12345@gmail.com>
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 this pull request may close these issues.

None yet

5 participants