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(chip): trailing remove icon can now be customized #5263

Merged

Conversation

vdegenne
Copy link
Contributor

@vdegenne vdegenne commented Dec 6, 2023

I made a preliminary commit just to show the course it's taking.

A slot was inserted directly into the renderRemoveButton method so everything works as intended with the keydown events and focus logic.

Another advantage is that md-input-chip will also inherit this change so users can use a different remove trailing icon if they want.

@vdegenne vdegenne changed the title Md filter chip icons chore(md-chip): filter chip trailing icon can now be customized Dec 6, 2023
@asyncLiz asyncLiz changed the title chore(md-chip): filter chip trailing icon can now be customized feat(chip): filter chip trailing icon can now be customized Dec 6, 2023
@asyncLiz
Copy link
Collaborator

asyncLiz commented Dec 6, 2023

Also let's check in on the motivation for this change. Do we want to replace the remove button's icon with something else, like a trash can? Or do we want to replace remove functionality with something new, such as a dropdown icon?

@vdegenne
Copy link
Contributor Author

vdegenne commented Dec 7, 2023

@asyncLiz It seems that the more general the better in this case, I see some cases where one developer would want to do something more than just removing or showing a dropdown icon (for instance showing an "info" icon that opens a small dialog to give more info about a special type of filter)

@asyncLiz
Copy link
Collaborator

asyncLiz commented Dec 7, 2023

I agree! Let's tackle that separately then, and scope this to just customizing the remove button's icon :)

I'll update the pr title to reflect

@asyncLiz asyncLiz changed the title feat(chip): filter chip trailing icon can now be customized feat(chip): trailing remove icon can now be customized Dec 7, 2023
Copy link
Collaborator

@asyncLiz asyncLiz left a comment

Choose a reason for hiding this comment

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

omg I forgot to publish my comments... so sorry!

chips/internal/filter-chip.ts Outdated Show resolved Hide resolved
chips/internal/multi-action-chip.ts Outdated Show resolved Hide resolved
chips/internal/trailing-icons.ts Outdated Show resolved Hide resolved
@vdegenne
Copy link
Contributor Author

vdegenne commented Dec 8, 2023

@asyncLiz Ok so if I understand you want to give the ability to change remove icon and later add another slot so users can insert anything at the end?
That means this code

<md-filter-chip
  removable
>
  <md-icon-button slot="trailing-icon">...</md-icon-button>
</md-filter-chip>

will end up showing two different trailing elements, is that ok?

Just to make sure we are on the same page, the modifications I provide allow this writing:

<!-- show "remove" trailing icon button by default -->
<md-filter-chip
  has-trailing
  @remove=${/* executed when remove icon button clicked */}
></md-filter-chip>

<!-- user can change the default -->
<md-filter-chip
  has-trailing
  @remove=${/* won't get executed */}
>
  <md-icon slot="trailing-icon">arrow_drop_down</md-icon>
</md-filter-chip>

We can then allow users to insert what they want in the chip by providing a general slot later on (for instance if they want to include md-menu when arrow down is clicked.)

@vdegenne vdegenne requested a review from asyncLiz December 8, 2023 13:41
@asyncLiz
Copy link
Collaborator

asyncLiz commented Dec 8, 2023

will end up showing two different trailing elements

I'm thinking that removable will not have an effect if a user provides a new trailing action.

<!-- Only the new icon button shows, not a second one. `removable` has no effect -->
<md-filter-chip removable>
  <md-icon-button slot="trailing-icon">...</md-icon-button>
</md-filter-chip>

<!-- Remove button shows with different icon -->
<md-filter-chip removable>
  <md-icon slot="remove-trailing-icon">trash</md-icon>
</md-filter-chip>

<!-- Only the new icon button shows, custom remove trailing icon does not. -->
<md-filter-chip removable>
  <md-icon slot="remove-trailing-icon">trash</md-icon>
  <md-icon-button slot="trailing-icon">...</md-icon-button>
</md-filter-chip>

@asyncLiz
Copy link
Collaborator

asyncLiz commented Dec 8, 2023

Just to make sure we are on the same page, the modifications I provide allow this writing:

<!-- show "remove" trailing icon button by default -->
<md-filter-chip
  has-trailing
  @remove=${/* executed when remove icon button clicked */}
></md-filter-chip>

<!-- user can change the default -->
<md-filter-chip
  has-trailing
  @remove=${/* won't get executed */}
>
  <md-icon slot="trailing-icon">arrow_drop_down</md-icon>
</md-filter-chip>

That is correct, the remove event will not fire with an entirely new custom trailing-icon slot. It would fire with a remove-trailing-icon slot.

@vdegenne
Copy link
Contributor Author

vdegenne commented Dec 8, 2023

@asyncLiz Last attempt. I don't want to bother I just studied the code thoroughly and tried different solutions, just making sure you fully understand this approach.
I renamed removable to has-trailing, has-trailing here basically serve as a switch for "show the trailing icon" which default to the "remove" icon, but users can then use trailing-icon to change the appearance of the icon.
get hasSlottedTrailingIcon() is used to determine if a slot content was provided but only during click event which won't compromise SSR. But ideally why not just dispatching a global event instead so in the end we could end up with a more intuitive syntax, e.g.

<md-filter-chip
  has-trailing
  @trailing-click=${this.#openChipMenu}
>
    <md-icon slot="trailing-icon">arrow_drop_down</md-icon>
    <!-- default slot -->
    <md-menu>...</md-menu>
</md-filter-chip>

Another advantage for this syntax is all the focus-ring navigation logic you wrote still act as intended and do not need additional code.

@asyncLiz
Copy link
Collaborator

asyncLiz commented Dec 8, 2023

We use has-* attributes specifically for SSR workarounds, so it'd be nice to keep that consistent rather than adding functionality with one of them. In general, most users shouldn't need to add has-* attributes unless they start seeing a FOUC. One day we'll remove them entirely once CSS adds :has-slotted().

I'd prefer to keep removable so it's more explicit to users what feature they're adding. It's also a breaking change if we remove it, and we want to stay on and support 1.x for a while.

I think an event like @trailing-click and attribute like trailing-icon-action or a slot="trailing-icon-button" is likely the right approach, but I'd like some more planning before we add it. For now, let's scope this PR to just customizing the existing remove button's icon with a slot="remove-trailing-icon" so we can get it in faster.

@vdegenne
Copy link
Contributor Author

vdegenne commented Dec 9, 2023

@asyncLiz Ok it's clear now, thanks for the heads-up. I'll complete this PR and probably leave the trailing-icon slot part to you because I'm not comfortable with the focus and aria logic yet.

Copy link
Collaborator

@asyncLiz asyncLiz left a comment

Choose a reason for hiding this comment

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

Looking great! Just a couple nits

Comment on lines 38 to 41
[name="trailing-icon"]::slotted(md-icon) {
[name="remove-trailing-icon"]::slotted(md-icon) {
--md-icon-size: var(--_icon-size);
color: inherit;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should be able to remove all of this CSS by creating a wrapper <span class="trailing icon"> around the slot. Then it will re-use shared .icon styles to size the icon:

.icon ::slotted(:first-child) {
  font-size: var(--_icon-size);
  height: var(--_icon-size);
  width: var(--_icon-size);
}

color inherits through slots, and <md-icon> explicitly has color: inherit so I don't think we need that declaration either.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice, I just realize font-size on md-icon will size the icon to match this value, this is so perfect.

@@ -34,7 +34,7 @@ export function renderRemoveButton({
@focus=${focusListener}>
<md-focus-ring part="trailing-focus-ring"></md-focus-ring>
<md-ripple ?disabled=${disabled}></md-ripple>
<slot name="trailing-icon" class="trailing icon">
<slot name="remove-trailing-icon" class="trailing icon">
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we move the .trailing.icon to a wrapping <span> element?

<span class="trailing icon">
  <slot name="remove-trailing-icon">...</slot>
</span>

This will re-use the shared .icon and .icon ::slotted() styles and set things up for the next <slot name="trailing-icon">.

@@ -9,7 +9,7 @@ import '../../ripple/ripple.js';

import {html, nothing} from 'lit';

import {Chip} from './chip.js';
import {MultiActionChip} from './multi-action-chip.js';
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can revert this change

@vdegenne vdegenne requested a review from asyncLiz December 12, 2023 08:46
@vdegenne
Copy link
Contributor Author

Something worth bringing to your attention, when using a custom remove icon using close value to emulate the default appearance, results look different:

image
(top: default, bottom: using close icon)

@asyncLiz
Copy link
Collaborator

Something worth bringing to your attention, when using a custom remove icon using close value to emulate the default appearance, results look different:

image (top: default, bottom: using close icon)

Can you file a separate issue for that?

<path
d="m249 849-42-42 231-231-231-231 42-42 231 231 231-231 42 42-231 231 231 231-42 42-231-231-231 231Z" />
</svg>
<span class="trailing icon">
Copy link
Collaborator

Choose a reason for hiding this comment

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

this change is 🤌

Copy link
Contributor Author

Choose a reason for hiding this comment

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

\ o / I like how it reverted to just that

@copybara-service copybara-service bot merged commit 27d3541 into material-components:main Dec 12, 2023
3 checks passed
@vdegenne vdegenne deleted the md-filter-chip-icons branch December 12, 2023 20:48
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.

2 participants