Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
feat(select): Add style updates to MDC Select, update tests and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
amsheehan committed Oct 31, 2017
1 parent 1f0ae99 commit 28a8c11
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 31 deletions.
7 changes: 7 additions & 0 deletions packages/mdc-menu/simple/adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ class MDCSimpleMenuAdapter {
*/
getAttributeForEventTarget(target, attributeName) {}

/**
* @param {EventTarget} target
* @param {string} className
* @return {boolean}
*/
eventTargetHasClass(target, className) {}

/** @return {{ width: number, height: number }} */
getInnerDimensions() {}

Expand Down
2 changes: 1 addition & 1 deletion packages/mdc-menu/simple/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ class MDCSimpleMenuFoundation extends MDCFoundation {

while (el && el !== document.body) {
if (this.adapter_.eventTargetHasClass(el, cssClasses.LIST_ITEM)) {
return true;
return;
}
el = el.parentNode;
}
Expand Down
21 changes: 12 additions & 9 deletions packages/mdc-select/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,14 +352,14 @@ within `componentDidUpdate`.
| `setBottomLineAttr(attr: string, value: string) => void` | Adds an attribute to the bottom line |
| `setAttr(attr: string, value: string) => void` | Sets attribute `attr` to value `value` on the root element. |
| `rmAttr(attr: string) => void` | Removes attribute `attr` from the root element. |
| `computeBoundingRect() => {left: number, top: number}` | Returns an object with a shape similar to a `ClientRect` object, with a `left` and `top` property specifying the element's position on the page relative to the viewport. The easiest way to achieve this is by calling `getBoundingClientRect()` on the root element. |
| `computeBoundingRect() => {left: number, top: number}` | Returns an object with a shape similar to a `ClientRect` object, with a `left` and `top` property specifying the element's position on the page relative to the viewport. The easiest way to achieve this is by calling `getBoundingClientRect()` on the surface element. |
| `registerInteractionHandler(type: string, handler: EventListener) => void` | Adds an event listener `handler` for event type `type` on the root element. |
| `deregisterInteractionHandler(type: string, handler: EventListener) => void` | Removes an event listener `handler` for event type `type` on the root element. |
| `focus() => void` | Focuses the root element |
| `makeTabbable() => void` | Allows the root element to be tab-focused via keyboard. We achieve this by setting the root element's `tabIndex` property to `0`. |
| `makeUntabbable() => void` | Disallows the root element to be tab-focused via keyboard. We achieve this by setting the root element's `tabIndex` property to `-1`. |
| `getComputedStyleValue(propertyName: string) => string` | Get the root element's computed style value of the given dasherized css property `propertyName`. We achieve this via `getComputedStyle(...).getPropertyValue(propertyName). `|
| `setStyle(propertyName: string, value: string) => void` | Sets a dasherized css property `propertyName` to the value `value` on the root element. We achieve this via `root.style.setProperty(propertyName, value)`. |
| `getComputedStyleValue(propertyName: string) => string` | Get the surface element's computed style value of the given dasherized css property `propertyName`. We achieve this via `getComputedStyle(...).getPropertyValue(propertyName). `|
| `setStyle(propertyName: string, value: string) => void` | Sets a dasherized css property `propertyName` to the value `value` on the surface element. We achieve this via `root.style.setProperty(propertyName, value)`. |
| `create2dRenderingContext() => {font: string, measureText: (string) => {width: number}}` | Returns an object which has the shape of a CanvasRenderingContext2d instance. Namely, it has a string property `font` which is writable, and a method `measureText` which given a string of text returns an object containing a `width` property specifying how wide that text should be rendered in the `font` specified by the font property. An easy way to achieve this is simply `document.createElement('canvas').getContext('2d');`. |
| `setMenuElStyle(propertyName: string) => void` | Sets a dasherized css property `propertyName` to the value `value` on the menu element. |
| `setMenuElAttr(attr: string, value: string) => void` | Sets attribute `attr` to value `value` on the menu element. |
Expand Down Expand Up @@ -436,12 +436,15 @@ First, wrap both a custom select and a native select within a wrapper element, l
</div>
</div>
<!-- Native element, shown on mobile devices -->
<select class="mdc-select">
<option value="" selected disabled>Pick one</option>
<option value="a">A</option>
<option value="b">B</option>
<option value="c">C</option>
</select>
<div class="mdc-select">
<select class="mdc-select__surface">
<option value="" selected disabled>Pick one</option>
<option value="a">A</option>
<option value="b">B</option>
<option value="c">C</option>
</select>
<div class="mdc-select__bottom-line"></div>
<div>
</div>
```

Expand Down
3 changes: 2 additions & 1 deletion packages/mdc-select/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ export const strings = {
};

export const numbers = {
SURFACE_HORIZONTAL_PADDING: 26,
SURFACE_RIGHT_PADDING: 26,
SURFACE_LEFT_PADDING: 16,
};
16 changes: 6 additions & 10 deletions packages/mdc-select/foundation.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ export default class MDCSelectFoundation extends MDCFoundation {
setAttr: (/* attr: string, value: string */) => {},
rmAttr: (/* attr: string */) => {},
computeBoundingRect: () => /* {left: number, top: number} */ ({left: 0, top: 0}),
registerPointerDownHandler: (/* evtType: string, handler: EventListener */) => {},
deregisterPointerDownHandler: (/* evtType: string, handler: EventListener */) => {},
registerInteractionHandler: (/* type: string, handler: EventListener */) => {},
deregisterInteractionHandler: (/* type: string, handler: EventListener */) => {},
focus: () => {},
Expand Down Expand Up @@ -94,17 +92,15 @@ export default class MDCSelectFoundation extends MDCFoundation {
this.displayViaKeyboardHandler_ = (evt) => this.handleDisplayViaKeyboard_(evt);
this.selectionHandler_ = ({detail}) => {
const {index} = detail;
const shouldRemoveFloatingLabelClass = false;

if (index !== this.selectedIndex_) {
this.setSelectedIndex(index);
this.adapter_.notifyChange();
}
this.close_(shouldRemoveFloatingLabelClass);
this.close_();
};
this.cancelHandler_ = () => {
const shouldRemoveFloatingLabelClass = true;
this.close_(shouldRemoveFloatingLabelClass);
this.close_();
};
}

Expand Down Expand Up @@ -196,9 +192,9 @@ export default class MDCSelectFoundation extends MDCFoundation {

let maxTextLength = 0;
for (let i = 0, l = this.adapter_.getNumberOfOptions(); i < l; i++) {
// SURFACE_HORIZONTAL_PADDING corresponds to a variable set in ./mdc-select.scss
// SURFACE_RIGHT_PADDING and SURFACE_LEFT_PADDING correspond to variables set in ./mdc-select.scss
// If the UI of MDC Select changes, also change it in the style
const selectBoxAddedPadding = numbers.SURFACE_HORIZONTAL_PADDING;
const selectBoxAddedPadding = numbers.SURFACE_RIGHT_PADDING + numbers.SURFACE_LEFT_PADDING;
const txt = this.adapter_.getTextForOptionAtIndex(i).trim();
const {width} = this.ctx_.measureText(txt);
const addedSpace = letterSpacing * txt.length;
Expand Down Expand Up @@ -255,11 +251,11 @@ export default class MDCSelectFoundation extends MDCFoundation {
this.adapter_.setMenuElStyle('transform-origin', `center ${itemOffsetTop}px`);
}

close_(shouldRemoveFloatingLabelClass) {
close_() {
const {OPEN} = MDCSelectFoundation.cssClasses;
this.adapter_.removeClass(OPEN);

if (shouldRemoveFloatingLabelClass && this.getSelectedIndex() === -1) {
if (this.getSelectedIndex() === -1) {
this.adapter_.removeClassFromLabel(cssClasses.LABEL_FLOAT_ABOVE);
}
this.adapter_.removeClassFromBottomLine(cssClasses.BOTTOM_LINE_ACTIVE);
Expand Down
6 changes: 6 additions & 0 deletions packages/mdc-select/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ export class MDCSelect extends MDCComponent {
this.foundation_.setDisabled(disabled);
}

constructor(...args) {
super(...args);

this.ripple_ = MDCRipple.attachTo(this.surface_);
}

item(index) {
return this.options[index] || null;
}
Expand Down
25 changes: 21 additions & 4 deletions packages/mdc-select/mdc-select.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
@return #{$property} 180ms $mdc-animation-standard-curve-timing-function;
}

$mdc-select-arrow-padding: 24px;
$mdc-select-arrow-padding: 26px;
$mdc-select-label-padding: 16px;

// postcss-bem-linter: define select
.mdc-select {
Expand Down Expand Up @@ -72,7 +73,9 @@ $mdc-select-arrow-padding: 24px;
}
}

@include mdc-theme-dark(".mdc-textfield", true) {
@include mdc-theme-dark(".mdc-select") {
@include mdc-select-dd-arrow-svg-bg_("ffffff", .54);

background-color: rgba(white, .1);
}

Expand All @@ -89,6 +92,14 @@ $mdc-select-arrow-padding: 24px;
@include mdc-typography(subheading2);
@include mdc-theme-prop(color, text-primary-on-light);
@include mdc-rtl-reflexive-box(padding, right, $mdc-select-arrow-padding);
@include mdc-ripple-base;
@include mdc-ripple-fg((pseudo: "::after"));
@include mdc-ripple-bg((pseudo: "::before"));

@include mdc-theme-dark(".mdc-icon-toggle", true) {
@include mdc-ripple-bg((pseudo: "::before", base-color: white, opacity: .16));
@include mdc-ripple-fg((pseudo: "::after", base-color: white, opacity: .16));
}

&::-ms-expand {
display: none;
Expand All @@ -99,7 +110,7 @@ $mdc-select-arrow-padding: 24px;
flex: 1;
width: 100%;
height: 56px;
padding-left: 16px;
padding-left: $mdc-select-label-padding;
border: none;
border-radius: 4px 4px 0 0;
outline: none;
Expand Down Expand Up @@ -144,7 +155,7 @@ $mdc-select-arrow-padding: 24px;
transition: mdc-select-transition(transform);
color: rgba(black, .6);
pointer-events: none;
// Force the label into its own layer to prevent to prevent visible layer promotion adjustments
// Force the label into its own layer to prevent visible layer promotion adjustments
// when the ripple is activated behind it.
will-change: transform;

Expand Down Expand Up @@ -224,11 +235,17 @@ $mdc-select-arrow-padding: 24px;
@include mdc-theme-prop(color, text-disabled-on-light);
@include mdc-select-dd-arrow-svg-bg_(000000, .38);

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;
}
}

@each $sel in ("mdc-select--disabled", "mdc-select[disabled]") {
Expand Down
7 changes: 4 additions & 3 deletions test/unit/mdc-select/foundation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ test('default adapter returns a complete adapter implementation', () => {
verifyDefaultAdapter(MDCSelectFoundation, [
'addClass', 'removeClass', 'addClassToLabel', 'removeClassFromLabel', 'addClassToBottomLine',
'removeClassFromBottomLine', 'setBottomLineAttr', 'setAttr', 'rmAttr', 'computeBoundingRect',
'registerPointerDownHandler', 'deregisterPointerDownHandler',
'registerInteractionHandler', 'deregisterInteractionHandler', 'focus', 'makeTabbable',
'makeUntabbable', 'getComputedStyleValue', 'setStyle', 'create2dRenderingContext',
'setMenuElStyle', 'setMenuElAttr', 'rmMenuElAttr', 'getMenuElOffsetHeight', 'openMenu',
Expand Down Expand Up @@ -189,7 +188,8 @@ test('#resize resizes the element to the longest-length option', () => {
foundation.resize();
assert.equal(ctx.font, '16px Roboto');
// ceil(letter-spacing * 'longest'.length + longest measured width + extra padding)
const expectedWidth = Math.ceil((2.5 * 7) + Math.max(...widths) + numbers.SURFACE_HORIZONTAL_PADDING);
const expectedWidth = Math.ceil((2.5 * 7) + Math.max(...widths) +
numbers.SURFACE_RIGHT_PADDING + numbers.SURFACE_LEFT_PADDING);
td.verify(mockAdapter.setStyle('width', `${expectedWidth}px`));
});

Expand Down Expand Up @@ -218,7 +218,8 @@ test('#resize falls back to font-{family,size} if shorthand is not supported', (
foundation.resize();
assert.equal(ctx.font, '16px Roboto');
// ceil(letter-spacing * 'longest'.length + longest measured width)
const expectedWidth = Math.ceil((2.5 * 7) + Math.max(...widths) + numbers.SURFACE_HORIZONTAL_PADDING);
const expectedWidth = Math.ceil((2.5 * 7) + Math.max(...widths) +
numbers.SURFACE_RIGHT_PADDING + numbers.SURFACE_LEFT_PADDING);
td.verify(mockAdapter.setStyle('width', `${expectedWidth}px`));
});

Expand Down
6 changes: 3 additions & 3 deletions test/unit/mdc-select/mdc-select.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,21 +260,21 @@ test('adapter#focus focuses on the root element', () => {
document.body.removeChild(fixture);
});

test('adapter#makeTabbable sets the root element\'s tabindex to 0', () => {
test('adapter#makeTabbable sets the menu element\'s tabindex to 0', () => {
const {component, menuEl} = setupTest();
menuEl.tabIndex = -1;
component.getDefaultFoundation().adapter_.makeTabbable();
assert.equal(menuEl.tabIndex, 0);
});

test('adapter#makeUntabbable sets the root element\'s tabindex to -1', () => {
test('adapter#makeUntabbable sets the menu element\'s tabindex to -1', () => {
const {component, menuEl} = setupTest();
menuEl.tabIndex = 0;
component.getDefaultFoundation().adapter_.makeUntabbable();
assert.equal(menuEl.tabIndex, -1);
});

test('adapter#getComputedStyleValue gets the computed style value of the prop from the root element', () => {
test('adapter#getComputedStyleValue gets the computed style value of the prop from the surface element', () => {
const {component, fixture, surface} = setupTest();
document.body.appendChild(fixture);
surface.style.width = '500px';
Expand Down

0 comments on commit 28a8c11

Please sign in to comment.