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

fix(material-experimental/mdc-form-field): notched-outline should include prefixes and suffixes #18381

Merged

Conversation

devversion
Copy link
Member

@devversion devversion commented Feb 4, 2020

When we landed the initial MDC form-field implementation, we
intentionally left the outline appearance with prefixes and suffixes in
a visually bad state. We did this because it was unclear how to proceed
due to a limitation with the MDC notched-outline.

After chatting more with the MDC team about this, and experimenting with
more alternatives, the form-field will now follow MDC as close as
possible. Instead of requiring changes upstream to MDC which aren't
necessarily reasonable (due to us supporting arbitrary prefix/suffix
content), we just use the notched-outline as intended.

To summarize what happened before: Our form-field supports abitrary
prefixes and suffixes. This is different in MDC, which always assumes a
fixed width/size for prefixes and suffixes. Ultimately, this causes
problems for us since in the outline appearance, the label should
be relative to the infix container (not overlap prefixes), but still
be aligned vertically over the prefix container. MDC achieves this by
simply shifting the label by a fixed amount of pixels (since they only
allow a specific width for prefixes and suffixes). This won't work for
us since our prefix container can scale as much as possible.

To reasonably fix this issue in a way that leverages/follows MDC as much
as possible, we determine the prefix container width programmatically
and shift the floating label horizontally based on the measured width.
This is basically the same approach MDC takes.. just that we have a
dynamic label offset measured at runtime.

For more context on the issue, refer to the original feature request in
MDC: material-components/material-components-web#5326.

…lude prefixes and suffixes

When we landed the initial MDC form-field implementation, we
intentionally left the outline appearance with prefixes and suffixes in
a visually bad state. We did this because it was unclear how to proceed
due to a limitation with the MDC notched-outline.

After chatting more with the MDC team about this, and experimenting with
more alternatives, the form-field will now follow MDC as close as
possible. Instead of requiring changes upstream to MDC which aren't
necessarily reasonable (due to us supporting arbitrary prefix/suffix
content), we just use the notched-outline as intended.

To summarize what happened before: Our form-field supports abitrary
prefixes and suffixes. This is different in MDC, which always assumes a
fixed width/size for prefixes and suffixes. Ultimately, this causes
problems for us since in the outline appearance, the label should
be relative to the infix container (not overlap prefixes), but still
be aligned vertically over the prefix container. MDC achieves this by
simply shifting the label by a fixed amount of pixels (since they only
allow a specific width for prefixes and suffixes). This won't work for
us since our prefix container can scale as much as possible.

To reasonably fix this issue in a way that leverages/follows MDC as much
as possible, we determine the prefix container width programmatically
and shift the floating label horizontally based on the measured width.
This is basically the same approach MDC takes.. just that we have a
dynamic label offset measured at runtime.

For more context on the issue, refer to the original feature request in
MDC: material-components-web#5326.
@devversion devversion added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent target: patch This PR is targeted for the next patch release labels Feb 4, 2020
@devversion devversion requested a review from mmalerba as a code owner February 4, 2020 15:06
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Feb 4, 2020
// If the directionality is RTL, the x-axis transform needs to be inverted. This
// is because `transformX` does not change based on the page directionality.
const labelHorizontalOffset =
(this._dir.value === 'rtl' ? -1 : 1) * prefixContainer.getBoundingClientRect().width;
Copy link
Member Author

Choose a reason for hiding this comment

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

We could also account for cases where the prefix containers start of invisible here, but I think that this is out-of-scope and very unlikely (it will also affect performance).

I saw that something like this has been done in the non-MDC based form-field for the outline gap. Though IMO we should not complicate these things, and rather provide/expose methods, so that people can refresh if needed.

Copy link
Member

Choose a reason for hiding this comment

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

Am I reading this incorrectly, or is this calling getBoundingClientRect on every zone stable?

Copy link
Member Author

@devversion devversion Feb 4, 2020

Choose a reason for hiding this comment

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

getBoundingClientRect will be called only if the projected prefixes change, or if the appearance is set to outline from fill. The goal is to call this as less as possible.

The update is just scheduled on the next zone stable when the prefixes change, or if the appearance has been changed. The client rect won't be retrieved on every zone stable.

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, you're guarding it on the boolean. It seems like it would be more idiomatic rxjs to combine the _prefixChildren.changes stream with the zone stable stream somehow (though I don't actually know the right operators off the top of my head)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm unsure if it's achievable with RxJS in a less complicated way. Combining both observables would complicate things since we also want to update if the appearance input changes.

We need logic like: Whenever prefix changes, or the appearance input changes, and the Zone becomes stable, update the offset. And important would be to only update once if both prefix and input change. FWIW: The same pattern is used in the non MDC-based form-field.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

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

Are these weird vertical alignments expected?
image

// If the directionality is RTL, the x-axis transform needs to be inverted. This
// is because `transformX` does not change based on the page directionality.
const labelHorizontalOffset =
(this._dir.value === 'rtl' ? -1 : 1) * prefixContainer.getBoundingClientRect().width;
Copy link
Member

Choose a reason for hiding this comment

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

Am I reading this incorrectly, or is this calling getBoundingClientRect on every zone stable?

@devversion
Copy link
Member Author

@jelbourn Thanks for trying the change in the dev-app. The vertical alignments are expected, since the prefix and suffixes align with the input baseline. This can be observed if you type into the form-fields with simple text prefixes/suffixes.

For the icons we currently do not provide any specific styles to adjust the baseline (like it has been done in the non MDC-based one). The baseline is incorrect for the icons right now.

The prefix and suffix containers currently are plain containers, and projected content must have a correct baseline to correctly align with the input element. I want to work on better alignment for mat-icon and icon buttons as part of a separate PR. Mostly because we want to update how these things align in the non MDC-based form-field too (as we discussed in the meeting). Tracked in COMP-271

…uld include prefixes and suffixes

Address feedback; and handle SSR better
@devversion
Copy link
Member Author

@jelbourn I addressed the feedback, and also found a way to make arbitrary prefixes render properly on the server. I think the overall arbitrary prefix/suffix API we need to support for backwards compatibility is not ideal.

Personally, for me It makes sense to support it now for backwards compatibility (given that it's not too much additional bloat), but long-term we should limit the prefix/suffix to either:

  1. Text prefix/suffix. We can let MDC handle this once they have support for it (in progress)
  2. Leading icon / trailing icon. MDC already supports this.

This would simplify the MDC-based form-field, and would allow us to rely on MDC as much as possible. Also it would allow us better align with the Material Design specification since text prefixes/suffixes actually should behave differently.

Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

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

LGTM

I agree, we should add e.g. mat-text-prefix and mat-icon-prefix and leave the existing mat-prefix as a legacy thing. Migration would be a pain.

@jelbourn jelbourn added pr: lgtm action: merge The PR is ready for merge by the caretaker labels Feb 6, 2020
@mmalerba mmalerba merged commit fc91061 into angular:master Feb 7, 2020
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 9, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants