Skip to content

feat: Adding custom renderer for select with demos #21064

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

Merged
merged 17 commits into from
Feb 11, 2020
Merged

feat: Adding custom renderer for select with demos #21064

merged 17 commits into from
Feb 11, 2020

Conversation

fguitton
Copy link
Contributor

@fguitton fguitton commented Jan 21, 2020

🤔 This is a ...

  • New feature
  • Bug fix
  • Site / document update
  • Component style update
  • TypeScript definition update
  • Refactoring
  • Code style optimization
  • Test Case
  • Branch merge
  • Other (about what?)

🔗 Related issue link

close #12910

💡 Background and solution

We want to be able to customise the rendering of elements in the Select component. For example to indicate invalid emails

This is the effective result :
image

Currently the work is in progress, as it necessitates react-component/select#445 to be merged first

📝 Changelog

This simply adds an example for using underlying rc-select change.

Language Changelog
🇺🇸 English Adding customized tag rendering in select
🇨🇳 Chinese 在select中支持自定义tag内容render

☑️ Self Check before Merge

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • TypeScript definition is updated/provided or not needed
  • Changelog is provided or not needed

View rendered components/select/demo/custom-tag-render.md
View rendered components/select/index.en-US.md
View rendered components/select/index.zh-CN.md


IssueHunt Summary

Referenced issues

This pull request has been submitted to:


IssueHunt has been backed by the following sponsors. Become a sponsor

@pr-triage pr-triage bot added the PR: draft label Jan 21, 2020
@ant-design-bot
Copy link
Contributor

ant-design-bot commented Jan 21, 2020

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jan 21, 2020

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 6d4140e:

Sandbox Source
antd reproduction template Configuration

@fguitton fguitton changed the title [WIP] Adding a custom renderer for tags feat: [WIP] Adding a custom renderer for tags Jan 22, 2020
@afc163 afc163 removed the enhancement label Feb 3, 2020
@codecov
Copy link

codecov bot commented Feb 3, 2020

Codecov Report

Merging #21064 into feature will decrease coverage by <.01%.
The diff coverage is 97.77%.

Impacted file tree graph

@@             Coverage Diff             @@
##           feature   #21064      +/-   ##
===========================================
- Coverage    97.56%   97.55%   -0.01%     
===========================================
  Files          299      300       +1     
  Lines         6969     6994      +25     
  Branches      1882     1882              
===========================================
+ Hits          6799     6823      +24     
- Misses         170      171       +1
Impacted Files Coverage Δ
components/notification/index.tsx 96.42% <100%> (+0.08%) ⬆️
components/notification/hooks/useNotification.tsx 95.65% <95.65%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4462885...6d4140e. Read the comment docs.

@fguitton fguitton changed the title feat: [WIP] Adding a custom renderer for tags feat: Adding a custom renderer for tags Feb 3, 2020
@fguitton
Copy link
Contributor Author

fguitton commented Feb 3, 2020

There is an an issue with snapshots in /components/config-provider/__tests__/__snapshots__/components.test.js.snap and /components/locale-provider/__tests__/__snapshots__/index.test.js.snap which seem to be unrelated to the changes regarding this PR

@fguitton fguitton marked this pull request as ready for review February 3, 2020 14:46
@fguitton fguitton changed the title feat: Adding a custom renderer for tags feat: Adding custom renderer for select with demos Feb 5, 2020
@fguitton fguitton requested a review from afc163 February 5, 2020 23:00
@zombieJ
Copy link
Member

zombieJ commented Feb 6, 2020

Seems multiple un-related files were prettieried. Could you help revert them?

@fguitton
Copy link
Contributor Author

fguitton commented Feb 6, 2020

Seems multiple un-related files were prettieried. Could you help revert them?

@zombieJ, apologies for that, the automated husky hooks triggered on the commit. This should now been clear.

@zombieJ
Copy link
Member

zombieJ commented Feb 10, 2020

One demo is good enough. Tag Editing is also same meaning of customize tag.

@fguitton fguitton requested a review from zombieJ February 10, 2020 14:33
```jsx
import { Select, Tag } from 'antd';

const OPTIONS = ['Hello', 'World', '42'];
Copy link
Member

Choose a reason for hiding this comment

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

OPTIONS = ['gold', 'cyan']

Copy link
Member

Choose a reason for hiding this comment

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

and follow tagRender just reuse the value.

Copy link
Contributor Author

@fguitton fguitton Feb 11, 2020

Choose a reason for hiding this comment

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

and follow tagRender just reuse the value.

If I do that without extra checks any other tags that's not a color understood by will essentially be transparent. As long as you're OK with that.

Copy link
Member

Choose a reason for hiding this comment

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

We can just simplify demo for multiple instead:

<Select
    mode="multiple"
    tagRender={tagRender}
    defaultValue={OPTIONS}
    style={{ width: '100%' }}
    options={...}
/>

PS: Not Options in children. options is a prop.

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 now switched over to "multiple" and aligned the demo to the "big-data" one for options.

@fguitton fguitton requested a review from zombieJ February 11, 2020 09:07
@zombieJ
Copy link
Member

zombieJ commented Feb 11, 2020

LGTM

@fguitton fguitton removed the request for review from afc163 February 11, 2020 11:57
@zombieJ zombieJ merged commit 0e34ca6 into ant-design:feature Feb 11, 2020
@ycjcl868 ycjcl868 mentioned this pull request Feb 24, 2020
@lawrencety
Copy link

I am trying to use this ability to render custom colors for each tag, but it looks like the colors are entirely dependent on either the value or label props that are passed through tagRender. The only other props are closable and onClose. This isn't really helpful since typically speaking, values and labels don't necessarily hold the color. Rather, they hold a select option and the value of that select option.

It would be helpful to have the entire option passed through where we can access both label and value but along with other props we may want i.e. color or even icon to be used by the Tag component

@fguitton
Copy link
Contributor Author

fguitton commented Jun 1, 2020

@lawrencety, @dotexe0, The custom rendering is in no way limited to colors. You can bring-in rendering logic from your upper level component. While you cannot have more than value and label passed as props since those are the only concepts supported by Select and effectively by the HTML select, the example in the documentation only uses color names supported by Tag as labels for the sake a brevity. You need not use Tag either.

@lawrencety
Copy link

lawrencety commented Jun 2, 2020

@fguitton Thanks for the quick response. The issue there is then we are not able to directly control each individual tag's colors. It looks like all tags must share the same color if we are using a higher level component. If we want to render different properties for each select option. A straightforward and controlled way to do so is by passing in custom props for the custom tags. Those props would be passed through from a higher level component. Something like this:

<Select 
  tagRender: (record, closable, onClose) => tagRender(record, closable, onClose) // record: { label, value, ...props }
  options: [{ label, value, ...props }, ...]
/>

Furthermore, if we are allowed to bring in any rendering logic, why limit the props that are passed down per record? It would make more sense to just pass the whole record.

If there's a way to effectively set up custom properties for each tag that are controlled by the select options/properties please let us know.

@fguitton
Copy link
Contributor Author

fguitton commented Jun 2, 2020

@lawrencety, You don't strictly need to pass in the all the elements you want to the tagRender. If you are only interested in customising your labels you can do so directly in the Option component. This can be done at any level and allows you to have all the control you need over the rendering. tagRender is mainly here to help you customize the label container (and its events) rather than the label itself.

See this codepen.io

const { Select } = antd;
const { Option } = Select;

const contacts = {
  "2jde": {
    firstname: "John",
    lastname: "Doe",
    image: "https://picsum.photos/id/237/50/50"
  },
  "t24d": {
    firstname: "Jane",
    lastname: "Doe",
    image: "https://picsum.photos/id/238/50/50"
  },
  "28sj": {
    firstname: "Boogie",
    lastname: "Monster",
    image: "https://picsum.photos/id/239/50/50"
  }
}

const PersonTag = ({person}) => {
  return (
      <span className="peopleTag">
        <img src={person.image}/>
        {person.firstname} {person.lastname.toUpperCase()}
      </span>
    );
}

const PeopleSelect = ({options, ...props}) => {
  
  return (
    <Select
      mode="multiple"
      className="peopleBar"
      tagRender={({label})=>label}
      {...props}
    >
      {Object.entries(options).map(([id, person]) => (
        <Option key={id} value={id}>
          <PersonTag person={person} />
        </Option>
      ))}
    </Select>
  );
}

ReactDOM.render(
  <PeopleSelect options={contacts} defaultValue={['28sj']}/>,
  root,
);

@lawrencety
Copy link

@fguitton Thank you, this was really helpful!

@Harukisatoh
Copy link
Contributor

But what if I want to dinamically set the colors of the labels itself not the options? I can't see a way to do that

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.

7 participants