Skip to content
This repository has been archived by the owner on Mar 4, 2020. It is now read-only.

feat: add on change handlers and renamed others for standardisation #2293

Merged
merged 15 commits into from
Feb 20, 2020

Conversation

silviuaavram
Copy link
Collaborator

@silviuaavram silviuaavram commented Jan 30, 2020

BREAKING CHANGES

Some onChange handlers have been renamed to become standardised with HTML elements and with the name of the prop they are representing. The list of changes:

Component Old Handler Name New Handler Name
Alert onDismiss onVisibleChange
Dropdown onSelectedChange onChange
Embed onActiveChanged onActiveChange
RadioGroup checkedValueChanged onCheckedValueChange
RadioGroupItem checkedChanged onChange

Some additional handlers added:

Component Handler Name
Accordion onActiveIndexChange
Dropdown onActiveSelectedIndexChange
Dropdown onHighlightedIndexChange
Menu onActiveIndexChange
ToolbarMenuItem onMenuOpenChange
Tree onActiveItemIdsChange

isConformat tests have been improved. If a component has a state value as controlled prop, then it should also have a default prop and a onChange handler as handled props.

Fixes #2119

Some components could not be covered by the test as they are not conformant (Dialog, Tooltip, Popup etc.)

@DustyTheBot
Copy link
Collaborator

DustyTheBot commented Jan 30, 2020

Warnings
⚠️ 1 perf regressions detected

Perf comparison

Status Scenario Fluent TPI Fabric TPI Ratio Iterations Ticks
🔧 Avatar.Fluent 0.52 0.44 1.18:1 2000 1033
🦄 Button.Fluent 0.12 0.2 0.6:1 1000 118
🔧 Checkbox.Fluent 1 0.33 3.03:1 1000 1004
🔧 Dialog.Fluent 0.4 0.2 2:1 5000 2023
🔧 Dropdown.Fluent 4.54 0.46 9.87:1 1000 4538
🔧 Icon.Fluent 0.16 0.04 4:1 5000 822
🦄 Image.Fluent 0.06 0.11 0.55:1 5000 276
🔧 Slider.Fluent 1.97 0.4 4.93:1 1000 1966
🔧 Text.Fluent 0.07 0.02 3.5:1 5000 340
🦄 Tooltip.Fluent 0.09 19.34 0:1 5000 448

🔧 Needs work     🎯 On target     🦄 Amazing

Potential regressions comparing to master

Scenario Current PR Ticks Baseline Ticks Ratio
Image.Fluent 276 297 0.93:1
Perf tests with no regressions
Scenario Current PR Ticks Baseline Ticks Ratio
VideoMinimalPerf.default 948 806 1.18:1
DropdownManyItemsPerf.default 459 396 1.16:1
CarouselMinimalPerf.default 2537 2200 1.15:1
LayoutMinimalPerf.default 557 484 1.15:1
ListNestedPerf.default 742 662 1.12:1
TreeWith60ListItems.default 306 274 1.12:1
ChatMinimalPerf.default 508 460 1.1:1
FlexMinimalPerf.default 401 366 1.1:1
TooltipMinimalPerf.default 846 767 1.1:1
HeaderMinimalPerf.default 463 423 1.09:1
PortalMinimalPerf.default 222 204 1.09:1
TextMinimalPerf.default 302 276 1.09:1
AttachmentMinimalPerf.default 1091 1011 1.08:1
AvatarMinimalPerf.default 593 556 1.07:1
AttachmentSlotsPerf.default 4038 3808 1.06:1
ListMinimalPerf.default 317 299 1.06:1
Button.Fluent 118 111 1.06:1
Checkbox.Fluent 1004 943 1.06:1
EmbedMinimalPerf.default 6722 6433 1.04:1
RefMinimalPerf.default 145 139 1.04:1
BoxMinimalPerf.default 296 287 1.03:1
DropdownMinimalPerf.default 3531 3420 1.03:1
HierarchicalTreeMinimalPerf.default 767 742 1.03:1
ProviderMinimalPerf.default 555 543 1.02:1
Dropdown.Fluent 4538 4435 1.02:1
ButtonMinimalPerf.default 134 133 1.01:1
LabelMinimalPerf.default 811 804 1.01:1
ListCommonPerf.default 740 735 1.01:1
ProviderMergeThemesPerf.default 1064 1049 1.01:1
Icon.Fluent 822 810 1.01:1
InputMinimalPerf.default 886 888 1:1
MenuButtonMinimalPerf.default 1429 1425 1:1
PopupMinimalPerf.default 307 307 1:1
ButtonSlotsPerf.default 733 738 0.99:1
DividerMinimalPerf.default 877 885 0.99:1
ItemLayoutMinimalPerf.default 1649 1663 0.99:1
DialogMinimalPerf.default 1636 1662 0.98:1
HeaderSlotsPerf.default 1297 1327 0.98:1
MenuMinimalPerf.default 1909 1939 0.98:1
SegmentMinimalPerf.default 1203 1224 0.98:1
SliderMinimalPerf.default 1363 1394 0.98:1
Text.Fluent 340 347 0.98:1
CheckboxMinimalPerf.default 3768 3882 0.97:1
ImageMinimalPerf.default 223 229 0.97:1
Avatar.Fluent 1033 1061 0.97:1
TextAreaMinimalPerf.default 2885 3006 0.96:1
TreeMinimalPerf.default 1096 1146 0.96:1
ReactionMinimalPerf.default 2328 2452 0.95:1
CustomToolbarPrototype.default 3388 3572 0.95:1
Dialog.Fluent 2023 2120 0.95:1
Tooltip.Fluent 448 470 0.95:1
AnimationMinimalPerf.default 562 595 0.94:1
ListWith60ListItems.default 147 157 0.94:1
LoaderMinimalPerf.default 2318 2465 0.94:1
RadioGroupMinimalPerf.default 387 414 0.93:1
ToolbarMinimalPerf.default 954 1028 0.93:1
Slider.Fluent 1966 2130 0.92:1
IconMinimalPerf.default 264 289 0.91:1
ChatWithPopoverPerf.default 597 662 0.9:1
GridMinimalPerf.default 816 902 0.9:1
StatusMinimalPerf.default 261 289 0.9:1
ChatDuplicateMessagesPerf.default 381 456 0.84:1
FormMinimalPerf.default 681 809 0.84:1
SplitButtonMinimalPerf.default 11257 13376 0.84:1
AlertMinimalPerf.default 575 689 0.83:1
TableMinimalPerf.default 620 785 0.79:1
AccordionMinimalPerf.default 212 276 0.77:1

Generated by 🚫 dangerJS

@@ -70,7 +70,7 @@ const checkOpenTitles = (wrapper: ReactWrapper, expected: string[]): void => {
}

describe('Tree', () => {
isConformant(Tree)
isConformant(Tree, { autocontrolledPropMappings: { activeItemIds: 'onActiveItemIdsChange' } })
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just adding a list of auto controlled props?

@@ -34,6 +34,8 @@ export interface Conformant {
/** This component uses wrapper slot to wrap the 'meaningful' element. */
wrapperComponent?: React.ReactType
handlesAsProp?: boolean
/** In the case when a onChange prop name is custom in relation to the controlled prop. */
Copy link
Contributor

Choose a reason for hiding this comment

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

Comment is confusing; the way I read the implementation it seems like this key is always required, not just when the prop name is customized.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

oups, leftover from previous implementation, will correct that.

@silviuaavram silviuaavram changed the title chore(isConformant): add tests for autocontrolled props feat: add on change handlers and renamed others for standardisation Jan 31, 2020
@@ -432,7 +454,7 @@ class Dropdown extends AutoControlledComponent<WithAsProp<DropdownProps>, Dropdo
const { highlightedIndex, open, searchQuery, value } = this.state

return (
<ElementType className={classes.root} {...unhandledProps}>
<ElementType className={classes.root} onChange={this.handleChange} {...unhandledProps}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't we going to end up here with onChange handler on a div element?

Copy link
Collaborator Author

@silviuaavram silviuaavram Feb 10, 2020

Choose a reason for hiding this comment

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

I did the same thing as in RadioGroupItem. Just to pass the isConformant. I don't know any better way.

    // RadioGroupItem component doesn't present any `input` component in markup, however all of our
    // components should handle events transparently.

@@ -144,21 +152,26 @@ class Menu extends AutoControlledComponent<WithAsProp<MenuProps>, MenuState> {
static Item = MenuItem
static Divider = MenuDivider

setActiveIndex = (e: React.SyntheticEvent, activeIndex: number) => {
_.invoke(this.props, 'onActiveIndexChange', e, this.props)
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's send here the new activeIndex together with the props?

@@ -200,7 +200,7 @@ class RadioGroup extends AutoControlledComponent<WithAsProp<RadioGroupProps>, an
props: RadioGroupItemProps
}) {
this.setState({ checkedValue, shouldFocus })
_.invoke(this.props, 'checkedValueChanged', event, props)
_.invoke(this.props, 'onCheckedValueChange', event, props)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be onChange?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If the prop was value, then yes. Are we changing everything here?

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, I thought it is the native value prop, but I see now that this is the RadioGroup component.


_.invoke(predefinedProps, 'onSiblingsExpand', e, treeItemProps)
},
})

setActiveItemIds = (e: React.SyntheticEvent, activeItemIds: string[]) => {
_.invoke(this.props, 'onActiveItemIds', e, this.props)
Copy link
Contributor

Choose a reason for hiding this comment

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

Send the updated activeItemIds please together with the props.

Copy link
Member

@layershifter layershifter left a comment

Choose a reason for hiding this comment

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

I wonder, to we want to include Dialog, Popup & Tooltip there?

@layershifter layershifter added the ⚙️ enhancement New feature or request label Feb 7, 2020
* @param event - React's original SyntheticEvent.
* @param data - All props and the new selected value(s).
*/
onActiveSelectedIndexChange?: ComponentEventHandler<DropdownProps>
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we suggest in the comment if the event is null for some handler?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

As far as I see, the event might be null, depending from which place the handler was called. And not only for this one, also for onChange as well. What do you suggest?

Copy link
Contributor

Choose a reason for hiding this comment

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

But we already have an issue regarding this: #2318 We should distinguish between the component event handlers that have event and the ones which do not. At least this is my opinion, we can ask other people for input

@@ -124,7 +124,7 @@ class Embed extends AutoControlledComponent<WithAsProp<EmbedProps>, EmbedState>

if (iframeNil || (!iframeNil && !this.state.active)) {
this.setState({ active: !this.state.active })
_.invoke(this.props, 'onActiveChanged', e, { ...this.props, active: !this.state.active })
_.invoke(this.props, 'onActiveChange', e, { ...this.props, active: !this.state.active })
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you save the value that we want to add in the state in a variable and reuse it in both setState and here? This is not save, as setState is async, so we should either move this into the callback in setState, or add here a variable's value, not the state's value

@silviuaavram silviuaavram merged commit d3e6c15 into master Feb 20, 2020
@silviuaavram silviuaavram deleted the chore/controlled-props-tests branch February 20, 2020 14:51
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Components: add onChange-like callback
5 participants