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

refactor(select): replace menu with native html select #2462

Merged
merged 29 commits into from
Apr 2, 2018

Conversation

moog16
Copy link
Contributor

@moog16 moog16 commented Mar 26, 2018

fixes #2399

}

nameditem(key) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

may want to reimplement namedItem

Matt Goo added 2 commits March 26, 2018 17:08
…al-components/material-components-web into refactor/select/use-native-select
</div>
```

Use the `<option disabled selected/>` element as a way to display the select having no value.
Copy link
Contributor

Choose a reason for hiding this comment

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

Say what?


| Method Signature | Description |
| --- | --- |
| `item(index: number) => HTMLElement?` | Analogous to `HTMLSelectElement.prototype.item`. Returns the option at the specified index, or `null` if the index is out of bounds. }
| `nameditem(key: string) => HTMLElement?` | Analogous to `HTMLSelectElement.prototype.nameditem`. Returns the options either whose `id` equals the given `key`, or whose `name` attribute equals the given `key`. Returns `null` if no item with an `id` or `name` attribute of the specified key is found. |
| `initialSyncWithDOM() => void` | Syncs the component with the current state of the HTML markup. |
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a method on all components, you don't need to document it

| `mdc-list-divider` | A divider. |

It is advised that dividers also set `role="presentation"` to disable selection and not cloud accessibility.
| `mdc-select__option` | A select option. |
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a necessary class?

@codecov-io
Copy link

codecov-io commented Mar 27, 2018

Codecov Report

Merging #2462 into master will decrease coverage by 0.03%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2462      +/-   ##
==========================================
- Coverage    98.9%   98.87%   -0.04%     
==========================================
  Files         102      102              
  Lines        4218     4073     -145     
  Branches      528      510      -18     
==========================================
- Hits         4172     4027     -145     
  Misses         46       46
Impacted Files Coverage Δ
packages/mdc-select/foundation.js 100% <100%> (ø) ⬆️
packages/mdc-select/index.js 100% <100%> (ø) ⬆️
packages/mdc-ripple/util.js 100% <100%> (ø) ⬆️
packages/mdc-select/constants.js 100% <100%> (ø) ⬆️

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 a70aa88...c816555. Read the comment docs.


border-bottom-width: 1px;
border-bottom-style: dotted;
opacity: .38;
cursor: default;
pointer-events: none;
// Imitate native disabled functionality
user-select: none;

.mdc-select__bottom-line {
display: none;
}
}

// postcss-bem-linter: end
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we still need this?

return this.root_.querySelectorAll('[aria-selected]');
// In an array because HTML spec also returns an array.
// Cannot access HTMLSelectElement.selectedIndex since it is not supported by IE11.
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedIndex
Copy link
Contributor

Choose a reason for hiding this comment

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

selectedIndex -> selectedOptions
https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedIndex -> https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedOptions

@moog16 moog16 assigned kfranqueiro and unassigned williamernest Mar 28, 2018
@kfranqueiro
Copy link
Contributor

I'll get to this review in a bit, but FYI I'm immediately noticing that the arrow doesn't look like it's vertically aligned correctly for the base MDC Select...

image

Copy link
Contributor

@kfranqueiro kfranqueiro left a comment

Choose a reason for hiding this comment

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

First round of review. Didn't bother reviewing tests because I have some adapter API suggestions first.

</div>
</section>
</section>
<section class="example">
<h2 class="mdc-typography--title">OptGroup JS Component</h2>
Copy link
Contributor

Choose a reason for hiding this comment

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

Re-word to "MDC Select with optgroups"

option with `aria-selected`. This will ensure that the label moves out of the way of the select's value
and prevents a Flash Of Un-styled Content (**FOUC**).
option with the `selected` attribute. This will ensure that the label moves out
of the way of the select's value and prevents a Flash Of Un-styled Content (**FOUC**).
Copy link
Contributor

Choose a reason for hiding this comment

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

While we're here, remove the - from unstyled

</div>
```

#### Select with floating label as the placeholder

Use the `<option disabled selected hidden/>` element as a way to display the select having no value.
Copy link
Contributor

Choose a reason for hiding this comment

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

hidden seems to have issues even in some browsers that support it, e.g. Edge and Safari where it leaves an empty space in the menu because of the hidden option. Between that and it not being supported by IE at all, I'd be inclined to leave it out...

Also, I'm not sure why you're saying to add the float-above class here? If the select initially has "no value", you would not want the float-above modifier (and our demo seems to match that).

Aside from that, I think this paragraph could use some re-wording anyway:

By default, `<select>` elements will select their first enabled option. In order to initially display a placeholder
instead, add an initial `<option>` element with the `disabled` *and* `selected` attributes set, and with `value` set to `""`.

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 was saying to add float-above if you want a placeholder instead of using the label, but the way I worded it is confusing and this might not be the place so I'll remove. Should I also remove hidden from the demos as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I think I commented on the line in the demo page too.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, not sure what you mean regarding wanting a placeholder instead of using the label... the placeholder attribute is not a thing for native select (since select normally always has an option selected)

if you do use this option as a placeholder to add the `mdc-select__label--float-above` class. Refer to [pre-selected option](#select-with-pre-selected-option). Also note that not all browsers respect the `hidden` attribute (ie. IE11).

```html
<option value="" disabled selected hidden></option>
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove hidden as per above comment

#### Disabled select

Add the `mdc-select--disabled` class to the `mdc-select` element. The disabled
Copy link
Contributor

Choose a reason for hiding this comment

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

I would re-word this to always recommend also setting the disabled attribute on the select element, again to prevent FOUC (and more importantly to prevent users from interacting with the select if JS loads slowly). The initialSyncWithDOM stuff should be more of a coincidental implementation detail that isn't needed here.

Also, throughout the readme, don't refer to <select> and <option> with slashes... they always have matching closing tags, so this just seems unnatural.

display: flex;
position: relative;
flex-grow: 1;
&::-ms-expand {
Copy link
Contributor

Choose a reason for hiding this comment

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

Above this, also add @include mdc-typography-base; to force consistent font (browsers like to reset font on inputs, and the box variant already resolves this by way of including a specific typography scale which itself includes base)

Copy link
Contributor

Choose a reason for hiding this comment

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

This still needs to be resolved; non-box selects are still using the browser's default input font


this.ripple = new MDCRipple(this.surface_);
this.ripple = new MDCRipple(this.root_);
Copy link
Contributor

Choose a reason for hiding this comment

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

Two issues here:

  • We probably want to do something like what we do with checkbox/radio/text-field to forward the ripple component's event handlers to the select element. This should make activation work when pressing space, and should make focus styles work via ripple JS.
  • We should only instantiate ripple if we're using the box variant (text field should have similar logic to check for a modifier class).

@@ -114,14 +109,15 @@
background-position: left 10px center;
}

.mdc-select__surface {
.mdc-select__surface,
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this element is no longer the ripple surface, we might want to consider renaming it... e.g. checkbox has __native-control for this.

(We'd want to change variable names in JS too)

@@ -27,12 +28,15 @@
// postcss-bem-linter: define select
.mdc-select {
@include mdc-typography-base;
@include mdc-states;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be in --box styles where the other ripple mixins are used. It doesn't make sense for this to apply to anything without those styles.

When you move it, change it to: @include mdc-states(text-primary-on-light, $has-nested-focusable-element: true);

This will make the ripple match the ink color, and make focus shade work properly given the nested select element, even when ripple JS isn't used (I know, right now we require JS, but this seems like the more technically correct thing to do esp. if there is ever hope of CSS-only down the road)

@@ -27,12 +28,15 @@
// postcss-bem-linter: define select
.mdc-select {
@include mdc-typography-base;
@include mdc-states;

Copy link
Contributor

Choose a reason for hiding this comment

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

We might want to go ahead and remove the following @each which is applying letter-spacing typography styles, since IIUC we're probably removing that property from typography anyway, and this might be hard to catch when we do a sweep later... @lynnjepsen what do you think?

Copy link
Contributor

@kfranqueiro kfranqueiro left a comment

Choose a reason for hiding this comment

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

Looking good RE APIs; reviewed tests this time too. I think the arrow location hasn't been fixed for non-box yet?

<div id="box-js-select" class="mdc-select mdc-select--box">
<select class="mdc-select__native-control">
<option value="" disabled selected></option>
<option value="fruit-roll-ups1">
Copy link
Contributor

Choose a reason for hiding this comment

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

These don't need "1"s on the values anymore, thanks to us no longer awkwardly using IDs as values. (Don't forget to update the value set in the JS below too)

</div>
<div id="js-pre-selected" class="mdc-select">
<select class="mdc-select__native-control">
<option value="fruit-roll-ups2" selected>
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove the numbers on these values too now.

<div id="optgroup-js-select" class="mdc-select">
<select class="mdc-select__native-control">
<optgroup label="Meats">
<option value="hot-dog">Steak</option>
Copy link
Contributor

Choose a reason for hiding this comment

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

hot-dog -> steak?

<option value="hamburger">Hamburger</option>
</optgroup>
<optgroup label="Vegetables">
<option value="beets">Beets</option>
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: make this singular to match other entries

white-space: nowrap;
cursor: pointer;
appearance: none;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the overflow: hidden below this needed? It was needed for __surface before because that's what contained the ripple, but that's been moved.

| `getSelectedIndex() => number` | Returns the selected index of the `<select>` element. |
| `setSelectedIndex(index: number) => void` | Sets the select's selectedValue to the option found at the provided index. If the index is out of the select's range, it will default to -1. |
| `getValue() => string` | Returns the value selected on the `<select>` element. |
| `setValue(value: string) => void` | Sets the select's value. If no option has the provided value, it sets `value` to empty string. |
Copy link
Contributor

Choose a reason for hiding this comment

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

Reduce this to: Sets the value of the <select> element.

(The rest is re-documenting native behavior.)


| Method Signature | Description |
| --- | --- |
| `setValue(value: string) => void` | Sets the select's value. If value is not found within list of options, it will set it to empty string. |
Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to above, reduce description: Sets the value of the component.

</div>
```

#### Select with floating label as the placeholder

Copy link
Contributor

Choose a reason for hiding this comment

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

Extra newlines here and before the next heading? Just need one empty line

display: flex;
position: relative;
flex-grow: 1;
&::-ms-expand {
Copy link
Contributor

Choose a reason for hiding this comment

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

This still needs to be resolved; non-box selects are still using the browser's default input font


this.ripple = new MDCRipple(this.surface_);
if (this.root_.classList.contains(cssClasses.BOX)) {
this.ripple = new MDCRipple(this.root_);
Copy link
Contributor

Choose a reason for hiding this comment

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

Only one of my two previous comments was resolved. Here's the other one:

We probably want to do something like what we do with checkbox/radio/text-field to forward the ripple component's event handlers to the select element. This should make activation work when pressing space, and should make focus styles work via ripple JS.

Specifically, I'm talking about e.g. this:

registerInteractionHandler: (type, handler) => this.nativeCb_.addEventListener(type, handler),
deregisterInteractionHandler: (type, handler) => this.nativeCb_.removeEventListener(type, handler),

Matt Goo and others added 5 commits March 30, 2018 13:56
…ial-components/material-components-web into refactor/select/use-native-select
* Simplify ripple tests
* Don't worry about wrapping ripple activation
* README fixes
Copy link
Contributor

@kfranqueiro kfranqueiro left a comment

Choose a reason for hiding this comment

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

I applied one last round of edits this morning; I think this is good, but you might want to look at my changes.

This should probably be feat(select) since it does affect APIs and functionality, and we need something like BREAKING CHANGE: The template and adapter APIs have changed to take advantage of the native select element; see the MDC Select README for more information.

@kfranqueiro kfranqueiro dismissed lynnmercier’s stale review April 2, 2018 14:32

These review points have been resolved

white-space: nowrap;
overflow: hidden;
cursor: pointer;
appearance: none;
Copy link

Choose a reason for hiding this comment

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

FYI, across the code base the prefixed version of appearance is used

-moz-appearance: none;
-webkit-appearance: none;

According to https://caniuse.com/#search=appearance the unprefixed version has very little support currently

Copy link
Contributor

Choose a reason for hiding this comment

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

The vendor prefixes are added automatically by autoprefixer when we build releases (and you are encouraged to do the same if you have your own Sass workflow). I have noticed that we have a few components using the vendor prefixes directly, which we should probably fix to use the non-prefixed version that will be picked up by autoprefixer.

Copy link

Choose a reason for hiding this comment

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

I see, thanks for clarifying @kfranqueiro

Is there a documentation for how one is supposed to use @material/* scss as and then apply postcss? Since postcss supports plugins/etc I am not sure which setup is the one mcw rely on.

In my case we compile a css with @material/* mixins to build a custom theme + some overrides.

trimox added a commit to trimox/angular-mdc-web that referenced this pull request Apr 8, 2018
Change as per material-components-web v0.34.1.
reference: material-components/material-components-web#2462

BREAKING CHANGE: 
- The template and adapter APIs have changed to take advantage of the native select element; see the MDC Select README for more information.
- Removed mdc-select-item component. Replace with HTML5's native option element.
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.

Revert mdc-select to use the <select> element
6 participants