Skip to content

refactor: make ListItem accepts a custom description#996

Merged
brunohkbx merged 2 commits intocallstack:masterfrom
brunohkbx:refactor/List.Item
May 23, 2019
Merged

refactor: make ListItem accepts a custom description#996
brunohkbx merged 2 commits intocallstack:masterfrom
brunohkbx:refactor/List.Item

Conversation

@brunohkbx
Copy link
Copy Markdown
Collaborator

@brunohkbx brunohkbx commented Apr 16, 2019

Motivation

Currently, there's no way to customize the description of List.Item. In order to make it able to be customized, List.Item now accepts a custom node as description.

With these changes we can implement a list item like Gmail app:
customized-list-description

<List.Item
  left={() => (
    <Image
      source={require('../../assets/images/email-icon.png')}
      style={styles.image}
    />
  )}
  right={props => <List.Icon {...props} icon="star-border" />}
  title="List Item 1"
  description={({
    ellipsizeMode,
    color: descriptionColor,
    fontSize,
  }) => (
    <View style={[styles.container, styles.column]}>
      <Text
        numberOfLines={2}
        ellipsizeMode={ellipsizeMode}
        style={{ color: descriptionColor, fontSize }}
      >
        React Native Paper is a high-quality, standard-compliant
        Material Design library that has you covered in all major
        use-cases.
      </Text>
      <View style={[styles.container, styles.row, { paddingTop: 8 }]}>
        <Chip icon="picture-as-pdf" onPress={() => {}}>
          DOCS.pdf
        </Chip>
      </View>
    </View>
  )}
/>

Test plan

  1. Download this branch
  2. Run the example app
  3. Open List.Section to see the new example.

@callstack-bot
Copy link
Copy Markdown

callstack-bot commented Apr 16, 2019

Hey @brunohkbx, thank you for your pull request 🤗. The documentation from this branch can be viewed here. Please remember to update Typescript types if you changed API.

@brunohkbx brunohkbx changed the title Split ListItem and make it accepts a children refactor: Split ListItem and make it accepts a children Apr 16, 2019
@thymikee thymikee requested review from Trancever and satya164 April 25, 2019 12:32
@brunohkbx brunohkbx force-pushed the refactor/List.Item branch 2 times, most recently from a930312 to 96e31af Compare May 2, 2019 17:59
@brunohkbx brunohkbx changed the title refactor: Split ListItem and make it accepts a children refactor: make ListItem accepts a custom description May 2, 2019
Copy link
Copy Markdown
Contributor

@Trancever Trancever left a comment

Choose a reason for hiding this comment

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

I am generally ok with render prop approach and I like it, but I don't like exposing List.Description component. Can we remove it?

Also, could you pass ellipsizeMode, color, fontSize to render function instead of ellipsizeMode and whole style obj?

@brunohkbx brunohkbx force-pushed the refactor/List.Item branch 2 times, most recently from e6d74b4 to 5ae1695 Compare May 6, 2019 14:14
@brunohkbx brunohkbx force-pushed the refactor/List.Item branch from 5ae1695 to 95f3cab Compare May 6, 2019 14:16
@brunohkbx
Copy link
Copy Markdown
Collaborator Author

Thanks @Trancever. Done 5ae1695

@Trancever
Copy link
Copy Markdown
Contributor

@brunohkbx Awesome, one more thing, can we improve description prop description? We should add info that it can be string or render prop and what arguments will be passed to that render prop. Please check other components that follow this pattern for reference.

@brunohkbx brunohkbx force-pushed the refactor/List.Item branch from 1cbae2c to cc56e4f Compare May 7, 2019 10:33
@brunohkbx
Copy link
Copy Markdown
Collaborator Author

brunohkbx commented May 7, 2019

Good catch, thanks. Added in f00d906

title="List Item 1"
description={({
ellipsizeMode,
color: descriptionColor,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

imo the color and fontSize should be in style, not as separate props.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@satya164 hmm, other components expose them as separate props, I wanted it to be consistent

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

hmm I think in most places where it's this way, it's usually for icons etc., but here looks like the render callback is passing a bunch of props (do we need to pass ellipsizeMode and fontSize for example?)

Copy link
Copy Markdown
Collaborator Author

@brunohkbx brunohkbx May 15, 2019

Choose a reason for hiding this comment

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

@satya164 I found these components doing the same: ListItem, ListAccordion, Banner
I think we should pass ellipsizeMode and fontSize because could have cases when the user only wants to add more content to the description and keep the Text as the original. e.g. #686

@brunohkbx brunohkbx merged commit 1dccc81 into callstack:master May 23, 2019
@brunohkbx brunohkbx deleted the refactor/List.Item branch May 23, 2019 17:32
Trancever pushed a commit that referenced this pull request Jun 27, 2019
* refactor: make ListItem accepts a custom description

* fix: update prop description type
@BenWildeman
Copy link
Copy Markdown
Contributor

BenWildeman commented Jul 26, 2019

This should have never been merged as it's a breaking change but aside from that. the implementation here isn't really the "react way". What do I mean by that? Well you shouldn't have to pass in a callback in order to use a react component.

Because of this breaking change, it's no longer possible to pass in a text component to it which was perfectly valid beforehand. Here it checks that the description is explicitly a string, in order to put it into the text component, but then this PR #1199 has reversed it and is now explicitly checking for a function.

This PR did not remove the React.Node type which meant that this didn't throw any errors within TS

The ideal way to fix this is to do the following which would have satisfied all needs, without creating a breaking change:

// renderDescription function

const isDescReactElement = React.isValidElement(description); // would be false for anything that's not a react element, such as a string;

if (isDescReactElement) {
    const desc = React.cloneElement(description, {
        ellipsizeMode: descriptionEllipsizeMode,
        color: descriptionColor,
        fontSize: styles.description.fontSize,
    });

    return desc;
}

return (
    <Text	
         ellipsizeMode={descriptionEllipsizeMode}	
         numberOfLines={2}	
         style={[	
             styles.description,	
             {	
                 color: descriptionColor,	
              },	
              descriptionStyle,	
         ]}	
    >	
        {description}	
    </Text>
);

@brunohkbx
Copy link
Copy Markdown
Collaborator Author

@BenWildeman I didn't realize that it would break the current implementation 😞. I apologize for the inconvenience.
Thanks for showing your implementation, it's good to know but I'm not sure if it would be ok to pass a component as a prop because this entire project is using render props to return elements.
Maybe @satya164, @Trancever or @wojteg1337 can check your fix.

@BenWildeman
Copy link
Copy Markdown
Contributor

it's fine with this, it's just that the original types are incorrect really. there shouldn't have been React.Node if it was only supposed to accept a string. you fixed it to be inline with the rest of the codebase. it's just annoying that a minor bump included a breaking change that broke our app in places that we didn't know about. luckily we do regression testing so it was caught

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.

5 participants