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

react-card - Phase 1 #19646

Merged
merged 25 commits into from Sep 14, 2021
Merged

react-card - Phase 1 #19646

merged 25 commits into from Sep 14, 2021

Conversation

andrefcdias
Copy link
Contributor

Pull request checklist

- Addresses an existing issue: Fixes #0000
- Include a change request file using $ yarn change

Description of changes

To avoid delays with the implementation of partner needed functionalities of Card, a phase 1 was established where we tackle only the necessary functionalities needed.
This means that, in new phases after we approve the component spec, there will probably be breaking changes to the component.

Focus areas to test

image
image

@andrefcdias andrefcdias requested review from a team September 3, 2021 17:05
@andrefcdias andrefcdias added this to In progress in CXE Prague - @microsoft/cxe-prg via automation Sep 3, 2021
@andrefcdias andrefcdias mentioned this pull request Sep 3, 2021
37 tasks
@fabricteam
Copy link
Collaborator

fabricteam commented Sep 3, 2021

📊 Bundle size report

Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
163.832 kB
46.719 kB
react-components
react-components: FluentProvider & webLightTheme
35.75 kB
11.392 kB
🤖 This report was generated against 9cee1b15de24665a3f4f70f8cc450fd7d06d36e8

@codesandbox-ci
Copy link

codesandbox-ci bot commented Sep 3, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 326b919:

Sandbox Source
Fluent UI React Starter Configuration

@size-auditor
Copy link

size-auditor bot commented Sep 3, 2021

Asset size changes

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

Baseline commit: 9cee1b15de24665a3f4f70f8cc450fd7d06d36e8 (build)

},
},
});
const LogoBackground = (props: React.HTMLAttributes<HTMLElement>) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sample component too look like the design specs


// Size: medium
// TODO: Validate if we should use a token instead + the unit of said token
// TODO: Explore alternate way of applying padding
Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the moment, we're applying padding on the Card component instead of each child component for ease of implementation reasons. However, this means the users will need to revert this padding if they so have such a specific need, so perhaps having a spacing token and reusing this across all Card* components is a better way to go.

Comment on lines +43 to +49
(state.onClick ||
state.onMouseUp ||
state.onMouseDown ||
state.onPointerUp ||
state.onPointerDown ||
state.onTouchStart ||
state.onTouchEnd) &&
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To be extracted into a separate utility once we define our standard of interactivity.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would avoid making styling assumptions based on event listeners used as it might lead to higher amount of custom overrides. Having explicit prop like interactive?: boolean is more robust. You can consider changing the default value of it based on the listeners (like if onClick is used and interactive is not, it would still be interactive, unless consumer specifies interactive={false})

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 don't see what the point of an interactive prop would be if the styling is still applied based on events. To me this is a visual accessibility feature that we want to be there.
If the user wants actions with no visual feedback or vice-versa, this seems like behavior we wouldn't want to encourage.

Copy link
Contributor

Choose a reason for hiding this comment

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

@jurokapsiar That's a valid point and even more of a reason to have this logic abstracted into a separate utility which can reason about it internally based on state.

I am, however, a bit afraid of a prop like interactive?: boolean as it exposes styling internals. This will also mean we run into a situation where we decouple styling interactivity and functional interactivity.

  • What should happen if the prop is true but there are no handlers?
    • Should it look interactive but when users try to manipulate it, it does nothing?
  • What should happen if the prop is false and there are handlers?
    • Should it disable those handlers?
    • Should it look non-interactive? But how are we then handling cases like keyboard focus?

If we believe that current component spec will lead to high amount of custom overrides then in my opinion the component design is not done properly and interactivity should be better defined within the spec. Otherwise, this would just be a premature optimisation for a problem that might not be a problem at all, especially when taking into consideration there already is a mechanism for users to override the styling if they want to opt-into less common scenarios.

Copy link
Member

@ling1726 ling1726 Sep 6, 2021

Choose a reason for hiding this comment

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

Looking at the figma design specs, there is no requirement that these interactive styles are linked to any kind of event listeners.

Why does interactive necessarily mean a mouse click ? why can a mouseenter not define interactive behaviour ? If a user wants to have hover styles, they would currently need to add an empty click listener to do that.

The event listeners also miss out on contextmenu event, should that also define interactivity ?

Adding an interactive prop means that we allow maximum flexibility for users since the designers who will work with these components can be from different product groups and might not associate things like hover styles with a click. On the reverse, some designs might not want hover styles or pressed styles to be applied on the card even on click, the simple prop lets us quite easily handle both situations without being too hacky

Copy link
Contributor

Choose a reason for hiding this comment

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

@andrefcdias @jurokapsiar @ling1726 I opened an issue which covers this. I feel this discussion targets more than just the card and feel that extra visibility of a separate issue might be useful. If you could raise your points there it would be greatly welcome. 🙏

#19664

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is why we need to define interactivity. My personal opinion is that if something has an action, it's interactive and needs visual feedback of being actionable. A mouseenter event is not an event that, to me, would define interactivity.
End of the day, this is something that should be opt out. If the user doesn't define anything, we provide them with a good baseline.

My suggestion is that we go with the current solution, keeping in mind that this is definitely not set in stone. There's already the pretext that breaking changes will happen in the next phases, so let's not dwell on this right now and migrate this discussion into the spec PR to define the definite solution for it, unless this is of high importance to have defined right now.
What do you think?

@fabricteam
Copy link
Collaborator

fabricteam commented Sep 3, 2021

Perf Analysis (@fluentui/react)

No significant results to display.

All results

Scenario Render type Master Ticks PR Ticks Iterations Status
Avatar mount 936 900 5000
BaseButton mount 892 953 5000
Breadcrumb mount 2587 2632 1000
ButtonNext mount 487 443 5000
Checkbox mount 1497 1511 5000
CheckboxBase mount 1334 1317 5000
ChoiceGroup mount 4730 4772 5000
ComboBox mount 965 973 1000
CommandBar mount 10276 10318 1000
ContextualMenu mount 6639 6533 1000
DefaultButton mount 1085 1128 5000
DetailsRow mount 3778 3721 5000
DetailsRowFast mount 3616 3767 5000
DetailsRowNoStyles mount 3512 3494 5000
Dialog mount 2446 2386 1000
DocumentCardTitle mount 125 138 1000
Dropdown mount 3313 3259 5000
FluentProviderNext mount 7470 7529 5000
FluentProviderWithTheme mount 344 352 10
FluentProviderWithTheme virtual-rerender 90 94 10
FluentProviderWithTheme virtual-rerender-with-unmount 491 496 10
FocusTrapZone mount 1767 1742 5000
FocusZone mount 1847 1835 5000
IconButton mount 1805 1897 5000
Label mount 332 340 5000
Layer mount 2933 2907 5000
Link mount 474 455 5000
MakeStyles mount 1867 1826 50000
MenuButton mount 1438 1497 5000
MessageBar mount 2058 1977 5000
Nav mount 3345 3263 1000
OverflowSet mount 1090 1080 5000
Panel mount 2396 2305 1000
Persona mount 840 828 1000
Pivot mount 1405 1426 1000
PrimaryButton mount 1301 1249 5000
Rating mount 7601 7459 5000
SearchBox mount 1311 1317 5000
Shimmer mount 2502 2506 5000
Slider mount 1960 2001 5000
SpinButton mount 4950 5277 5000
Spinner mount 441 415 5000
SplitButton mount 3249 3137 5000
Stack mount 512 537 5000
StackWithIntrinsicChildren mount 1549 1551 5000
StackWithTextChildren mount 4492 4472 5000
SwatchColorPicker mount 10234 10296 5000
Tabs mount 1380 1397 1000
TagPicker mount 2571 2529 5000
TeachingBubble mount 13301 13323 5000
Text mount 424 426 5000
TextField mount 1401 1368 5000
ThemeProvider mount 1196 1200 5000
ThemeProvider virtual-rerender 601 595 5000
ThemeProvider virtual-rerender-with-unmount 1866 1878 5000
Toggle mount 837 851 5000
buttonNative mount 114 111 5000

Perf Analysis (@fluentui/react-northstar)

Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
AccordionMinimalPerf.default 161 149 1.08:1
AttachmentMinimalPerf.default 162 150 1.08:1
LoaderMinimalPerf.default 732 679 1.08:1
ButtonMinimalPerf.default 173 161 1.07:1
DropdownManyItemsPerf.default 687 640 1.07:1
FormMinimalPerf.default 403 376 1.07:1
ReactionMinimalPerf.default 376 352 1.07:1
ChatWithPopoverPerf.default 381 358 1.06:1
GridMinimalPerf.default 342 324 1.06:1
RadioGroupMinimalPerf.default 451 426 1.06:1
HeaderSlotsPerf.default 794 754 1.05:1
DialogMinimalPerf.default 762 734 1.04:1
ListCommonPerf.default 615 592 1.04:1
TreeWith60ListItems.default 176 169 1.04:1
AvatarMinimalPerf.default 198 192 1.03:1
TextMinimalPerf.default 353 343 1.03:1
AttachmentSlotsPerf.default 1121 1102 1.02:1
DividerMinimalPerf.default 350 344 1.02:1
InputMinimalPerf.default 1264 1245 1.02:1
ProviderMinimalPerf.default 1060 1040 1.02:1
SegmentMinimalPerf.default 337 330 1.02:1
BoxMinimalPerf.default 345 340 1.01:1
EmbedMinimalPerf.default 4197 4139 1.01:1
HeaderMinimalPerf.default 359 356 1.01:1
ItemLayoutMinimalPerf.default 1190 1180 1.01:1
LayoutMinimalPerf.default 362 358 1.01:1
MenuButtonMinimalPerf.default 1615 1597 1.01:1
RefMinimalPerf.default 231 229 1.01:1
TableManyItemsPerf.default 1921 1904 1.01:1
TooltipMinimalPerf.default 1012 1006 1.01:1
CarouselMinimalPerf.default 451 450 1:1
ChatMinimalPerf.default 642 642 1:1
CheckboxMinimalPerf.default 2772 2767 1:1
ListWith60ListItems.default 645 643 1:1
SliderMinimalPerf.default 1550 1556 1:1
TextAreaMinimalPerf.default 483 485 1:1
CustomToolbarPrototype.default 3844 3857 1:1
TreeMinimalPerf.default 793 796 1:1
AlertMinimalPerf.default 259 261 0.99:1
ButtonOverridesMissPerf.default 1669 1682 0.99:1
CardMinimalPerf.default 543 547 0.99:1
DatepickerMinimalPerf.default 5521 5563 0.99:1
DropdownMinimalPerf.default 3081 3114 0.99:1
FlexMinimalPerf.default 285 287 0.99:1
RosterPerf.default 1113 1128 0.99:1
SplitButtonMinimalPerf.default 4089 4131 0.99:1
StatusMinimalPerf.default 647 653 0.99:1
ToolbarMinimalPerf.default 899 909 0.99:1
AnimationMinimalPerf.default 409 416 0.98:1
MenuMinimalPerf.default 835 854 0.98:1
PopupMinimalPerf.default 591 602 0.98:1
TableMinimalPerf.default 410 418 0.98:1
ButtonSlotsPerf.default 516 532 0.97:1
ListNestedPerf.default 528 544 0.97:1
PortalMinimalPerf.default 180 186 0.97:1
SkeletonMinimalPerf.default 349 359 0.97:1
IconMinimalPerf.default 582 608 0.96:1
ChatDuplicateMessagesPerf.default 285 301 0.95:1
ImageMinimalPerf.default 355 375 0.95:1
ProviderMergeThemesPerf.default 1686 1775 0.95:1
LabelMinimalPerf.default 363 385 0.94:1
ListMinimalPerf.default 495 526 0.94:1
VideoMinimalPerf.default 597 634 0.94:1

@@ -0,0 +1,9 @@
<svg width="22" height="23" viewBox="0 0 22 23" fill="none" xmlns="http://www.w3.org/2000/svg">
Copy link
Member

Choose a reason for hiding this comment

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

you'll need to make sure these aren't released along with our published packages. I would suggest you update the migration generator to update the generated npmignore for either:

  • assets folder -> could be a bit too opinionated and specific to one package
  • all svgs -> I don't think we should be shipping any svgs, but I'm not 100% sure on this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I just use @fluentui/example-data instead or is this a v8 thing only?

Copy link
Member

@ling1726 ling1726 Sep 7, 2021

Choose a reason for hiding this comment

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

I think it's a v8 thing, but I don't think including it as a dev dep should have too many consequences just like other shared dev deps between v8/9. @ecraig12345 any reason we can't use that package as a dev dep for stories ?

import type { CardState } from './Card.types';

/**
* Render the final JSX of Card
*/
export const renderCard = (state: CardState) => {
const { slots, slotProps } = getSlotsCompat(state, cardShorthandProps);
const { slots, slotProps } = getSlotsCompat(state);
Copy link
Member

Choose a reason for hiding this comment

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

since this is the first phase of a new component, please follow the new slot guidelines from #19483 It's a beta high priority task to migrate components to the new API

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Compat was used on purpose as the PR was still pending approval back then. If this is not breaking, I would rather leave it for when the implementation of the rest of the functionality starts to avoid delaying it (given that it's not one of the Beta components and we're not closing Card with this).
Could this be postponed to the next PR?

Copy link
Member

Choose a reason for hiding this comment

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

I would say that when there's less functionality this change is easier to make (having had to do this for the full Menu package). But you are driving the work on card, so I'll leave it to your timeline 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Plan would be to pick that up right after the PR gets merged and before we start with additional functionality, so impact should be the same.


return (
<slots.root {...slotProps.root}>
<div>{state.children}</div>
Copy link
Member

@ling1726 ling1726 Sep 6, 2021

Choose a reason for hiding this comment

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

I also don't like this, but every DOM slot should be customizable. In MenuItem I had the same issue and just settled for a content slot

Suggested change
<div>{state.children}</div>
<slots.content>{state.children}</slots.content>

Copy link
Member

Choose a reason for hiding this comment

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

I see now that you do have a content slot, did you forget to use it in the render function ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

so the same should for done for renderCardFooter ?

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 see the confusion now. I thought this was referring to CardHeader and not CardFooter. 😅
I think I would prefer to have slightly more complex styling to achieve the same result instead of having a content prop for this case. It's only there so we have content to the left and actions to the right.
Opinion?

Copy link
Member

@ling1726 ling1726 Sep 10, 2021

Choose a reason for hiding this comment

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

why not just use flex display and set margin-left: 'auto' on the actions slot ? I checked out your PR to test it out, it seems to work

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 went ahead with creating a content slot instead. margin-left would not work for RTL scenarios and there doesn't seem to be any viable solution for it. There's the :dir psudo-selector but that's not fully supported yet.

Copy link
Member

Choose a reason for hiding this comment

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

I'm pretty sure sure make-styles does RTL styles flipping automatically

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've reverted the API changes back to leverage that functionality. Let us discuss going forward over the best approach given that this depends on knowledge about the FluentProvider

@@ -1,7 +1,7 @@
{
"name": "@fluentui/react-card",
"version": "9.0.0-alpha.0",
"private": true,
"private": false,
Copy link
Member

Choose a reason for hiding this comment

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

are we sure that we want to release immediately ? are we in a rush to deliver this to partners ?

Copy link
Member

Choose a reason for hiding this comment

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

as you said it's not targeted for the beta release

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Partner's needs are basically ASAP, hence the need for this first phase iteration.

Copy link
Member

Choose a reason for hiding this comment

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

Another note: if partners consume this as a separate package along with react-components there would be compatibility issues since the removal of mergeProps and other breaking changes to slots. It would be hard for them to figure out why things are breaking because we use prerelease tags that don't communicate breaking changes

Copy link
Member

@khmakoto khmakoto left a comment

Choose a reason for hiding this comment

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

Left 2 comments but most of the other things that I could point out are already addressed by @ling1726's comments.

packages/react-card/src/index.ts Outdated Show resolved Hide resolved
/**
* Image slot
*/
image: ShorthandPropsCompat<React.ImgHTMLAttributes<HTMLImageElement>>;
Copy link
Member

Choose a reason for hiding this comment

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

Should the image be required?

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, at least for now. We don't really have any designs at the moment for scenarios with missing pieces and making it optional in the future wouldn't bring breaking changes.

Co-authored-by: Peter Varholak <peter.varholak@gmail.com>
Copy link
Contributor

@varholak-peter varholak-peter left a comment

Choose a reason for hiding this comment

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

LGTM 🇿🇲

CXE Prague - @microsoft/cxe-prg automation moved this from In progress to Reviewer approved Sep 10, 2021
@andrefcdias andrefcdias requested a review from a team as a code owner September 14, 2021 12:39
@andrefcdias andrefcdias merged commit e870763 into microsoft:master Sep 14, 2021
CXE Prague - @microsoft/cxe-prg automation moved this from Reviewer approved to Done Sep 14, 2021
@andrefcdias andrefcdias deleted the card-phase1 branch September 16, 2021 15:19
@Hotell Hotell moved this from Done to Archive in CXE Prague - @microsoft/cxe-prg Oct 21, 2021
mlp73 pushed a commit to mlp73/fluentui that referenced this pull request Jan 17, 2022
Co-authored-by: Peter Varholak <peter.varholak@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants