Skip to content

Commit

Permalink
feat(snackbar): Convert JS to TypeScript (#4363)
Browse files Browse the repository at this point in the history
Refs #4225
  • Loading branch information
acdvorak authored Feb 9, 2019
1 parent 08fb283 commit e95ff8a
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 264 deletions.
3 changes: 1 addition & 2 deletions packages/mdc-list/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@
*/

/**
* Adapter for MDC List. Provides an interface for managing focus.
*
* Defines the shape of the adapter expected by the foundation.
* Implement this adapter for your framework of choice to delegate updates to
* the component in your framework of choice. See architecture documentation
* for more details.
Expand Down
16 changes: 8 additions & 8 deletions packages/mdc-snackbar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ Event Name | `event.detail` | Description
--- | --- | ---
`MDCSnackbar:opening` | `{}` | Indicates when the snackbar begins its opening animation.
`MDCSnackbar:opened` | `{}` | Indicates when the snackbar finishes its opening animation.
`MDCSnackbar:closing` | `{reason: ?string}` | Indicates when the snackbar begins its closing animation. `reason` contains the reason why the snackbar closed (`dismiss` or `action`).
`MDCSnackbar:closed` | `{reason: ?string}` | Indicates when the snackbar finishes its closing animation. `reason` contains the reason why the snackbar closed (`dismiss` or `action`).
`MDCSnackbar:closing` | `{reason?: string}` | Indicates when the snackbar begins its closing animation. `reason` contains the reason why the snackbar closed (`'dismiss'`, `'action'`, or `undefined`).
`MDCSnackbar:closed` | `{reason?: string}` | Indicates when the snackbar finishes its closing animation. `reason` contains the reason why the snackbar closed (`'dismiss'`, `'action'`, or `undefined`).

### Usage Within Frameworks

Expand All @@ -202,8 +202,8 @@ Method Signature | Description
`announce() => void` | Announces the snackbar's label text to screen reader users.
`notifyOpening() => void` | Broadcasts an event denoting that the snackbar has just started opening.
`notifyOpened() => void` | Broadcasts an event denoting that the snackbar has finished opening.
`notifyClosing(reason: string) {}` | Broadcasts an event denoting that the snackbar has just started closing. If a non-empty `reason` is passed, the event's `detail` object should include its value in the `reason` property.
`notifyClosed(reason: string) {}` | Broadcasts an event denoting that the snackbar has finished closing. If a non-empty `reason` is passed, the event's `detail` object should include its value in the `reason` property.
`notifyClosing(reason: string) => void` | Broadcasts an event denoting that the snackbar has just started closing. If a non-empty `reason` is passed, the event's `detail` object should include its value in the `reason` property.
`notifyClosed(reason: string) => void` | Broadcasts an event denoting that the snackbar has finished closing. If a non-empty `reason` is passed, the event's `detail` object should include its value in the `reason` property.

#### `MDCSnackbarFoundation` Methods

Expand All @@ -216,9 +216,9 @@ Method Signature | Description
`setTimeoutMs(timeoutMs: number)` | Sets the automatic dismiss timeout in milliseconds. Value must be between `4000` and `10000` or an error will be thrown.
`getCloseOnEscape() => boolean` | Returns whether the snackbar closes when it is focused and the user presses the <kbd>ESC</kbd> key.
`setCloseOnEscape(closeOnEscape: boolean) => void` | Sets whether the snackbar closes when it is focused and the user presses the <kbd>ESC</kbd> key.
`handleKeyDown(event: !KeyEvent)` | Handles `keydown` events on or within the snackbar's root element.
`handleActionButtonClick(event: !MouseEvent)` | Handles `click` events on or within the action button.
`handleActionIconClick(event: !MouseEvent)` | Handles `click` events on or within the dismiss icon.
`handleKeyDown(event: KeyEvent)` | Handles `keydown` events on or within the snackbar's root element.
`handleActionButtonClick(event: MouseEvent)` | Handles `click` events on or within the action button.
`handleActionIconClick(event: MouseEvent)` | Handles `click` events on or within the dismiss icon.

#### Event Handlers

Expand All @@ -236,7 +236,7 @@ External frameworks and libraries can use the following utility methods from the

Method Signature | Description
--- | ---
`announce(ariaEl: !HTMLElement, labelEl: !HTMLElement=) => void` | Announces the label text to screen reader users.
`announce(ariaEl: Element, labelEl?: Element) => void` | Announces the label text to screen reader users.

> Alternatively, frameworks can use [Closure Library's `goog.a11y.aria.Announcer#say()` method](https://github.com/google/closure-library/blob/bee9ced776b4700e8076a3466bd9d3f9ade2fb54/closure/goog/a11y/aria/announcer.js#L80).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,44 +21,21 @@
* THE SOFTWARE.
*/

/* eslint no-unused-vars: [2, {"args": "none"}] */

/**
* Adapter for MDC Snackbar. Provides an interface for managing:
* - CSS classes
* - Event handlers
*
* Additionally, provides type information for the adapter to the Closure
* compiler.
*
* Defines the shape of the adapter expected by the foundation.
* Implement this adapter for your framework of choice to delegate updates to
* the component in your framework of choice. See architecture documentation
* for more details.
* https://github.com/material-components/material-components-web/blob/master/docs/code/architecture.md
*
* @record
*/
class MDCSnackbarAdapter {
/** @param {string} className */
addClass(className) {}

/** @param {string} className */
removeClass(className) {}

announce() {}

notifyOpening() {}
notifyOpened() {}

/**
* @param {string} reason
*/
notifyClosing(reason) {}

/**
* @param {string} reason
*/
notifyClosed(reason) {}
interface MDCSnackbarAdapter {
addClass(className: string): void;
announce(): void;
notifyClosed(reason: string): void;
notifyClosing(reason: string): void;
notifyOpened(): void;
notifyOpening(): void;
removeClass(className: string): void;
}

export default MDCSnackbarAdapter;
export {MDCSnackbarAdapter as default, MDCSnackbarAdapter};
Original file line number Diff line number Diff line change
Expand Up @@ -22,36 +22,33 @@
*/

const cssClasses = {
OPENING: 'mdc-snackbar--opening',
OPEN: 'mdc-snackbar--open',
CLOSING: 'mdc-snackbar--closing',
OPEN: 'mdc-snackbar--open',
OPENING: 'mdc-snackbar--opening',
};

const strings = {
SURFACE_SELECTOR: '.mdc-snackbar__surface',
LABEL_SELECTOR: '.mdc-snackbar__label',
ACTION_SELECTOR: '.mdc-snackbar__action',
ARIA_LIVE_LABEL_TEXT_ATTR: 'data-mdc-snackbar-label-text',
CLOSED_EVENT: 'MDCSnackbar:closed',
CLOSING_EVENT: 'MDCSnackbar:closing',
DISMISS_SELECTOR: '.mdc-snackbar__dismiss',

OPENING_EVENT: 'MDCSnackbar:opening',
LABEL_SELECTOR: '.mdc-snackbar__label',
OPENED_EVENT: 'MDCSnackbar:opened',
CLOSING_EVENT: 'MDCSnackbar:closing',
CLOSED_EVENT: 'MDCSnackbar:closed',

OPENING_EVENT: 'MDCSnackbar:opening',
REASON_ACTION: 'action',
REASON_DISMISS: 'dismiss',

ARIA_LIVE_LABEL_TEXT_ATTR: 'data-mdc-snackbar-label-text',
SURFACE_SELECTOR: '.mdc-snackbar__surface',
};

const numbers = {
MIN_AUTO_DISMISS_TIMEOUT_MS: 4000,
MAX_AUTO_DISMISS_TIMEOUT_MS: 10000,
DEFAULT_AUTO_DISMISS_TIMEOUT_MS: 5000,
MAX_AUTO_DISMISS_TIMEOUT_MS: 10000,
MIN_AUTO_DISMISS_TIMEOUT_MS: 4000,

// These variables need to be kept in sync with the values in _variables.scss.
SNACKBAR_ANIMATION_OPEN_TIME_MS: 150,
SNACKBAR_ANIMATION_CLOSE_TIME_MS: 75,
SNACKBAR_ANIMATION_OPEN_TIME_MS: 150,

/**
* Number of milliseconds to wait between temporarily clearing the label text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@
* THE SOFTWARE.
*/

/* eslint no-unused-vars: ["error", {"argsIgnorePattern": "evt", "varsIgnorePattern": "Adapter$"}] */

import {MDCFoundation} from '@material/base/foundation';
import MDCSnackbarAdapter from './adapter';
import {MDCSnackbarAdapter} from './adapter';
import {cssClasses, numbers, strings} from './constants';

const {OPENING, OPEN, CLOSING} = cssClasses;
const {REASON_ACTION, REASON_DISMISS} = strings;

class MDCSnackbarFoundation extends MDCFoundation {
class MDCSnackbarFoundation extends MDCFoundation<MDCSnackbarAdapter> {
static get cssClasses() {
return cssClasses;
}
Expand All @@ -43,44 +41,27 @@ class MDCSnackbarFoundation extends MDCFoundation {
return numbers;
}

/**
* @return {!MDCSnackbarAdapter}
*/
static get defaultAdapter() {
return /** @type {!MDCSnackbarAdapter} */ ({
addClass: (/* className: string */) => {},
removeClass: (/* className: string */) => {},
announce: () => {},
notifyOpening: () => {},
notifyOpened: () => {},
notifyClosing: (/* reason: string */) => {},
notifyClosed: (/* reason: string */) => {},
});
static get defaultAdapter(): MDCSnackbarAdapter {
return {
addClass: () => undefined,
announce: () => undefined,
notifyClosed: () => undefined,
notifyClosing: () => undefined,
notifyOpened: () => undefined,
notifyOpening: () => undefined,
removeClass: () => undefined,
};
}

/**
* @param {!MDCSnackbarAdapter=} adapter
*/
constructor(adapter) {
super(Object.assign(MDCSnackbarFoundation.defaultAdapter, adapter));

/** @private {boolean} */
this.isOpen_ = false;
private isOpen_ = false;
private animationFrame_ = 0;
private animationTimer_ = 0;
private autoDismissTimer_ = 0;
private autoDismissTimeoutMs_ = numbers.DEFAULT_AUTO_DISMISS_TIMEOUT_MS;
private closeOnEscape_ = true;

/** @private {number} */
this.animationFrame_ = 0;

/** @private {number} */
this.animationTimer_ = 0;

/** @private {number} */
this.autoDismissTimer_ = 0;

/** @private {number} */
this.autoDismissTimeoutMs_ = numbers.DEFAULT_AUTO_DISMISS_TIMEOUT_MS;

/** @private {boolean} */
this.closeOnEscape_ = true;
constructor(adapter?: MDCSnackbarAdapter) {
super(Object.assign(MDCSnackbarFoundation.defaultAdapter, adapter));
}

destroy() {
Expand Down Expand Up @@ -117,7 +98,7 @@ class MDCSnackbarFoundation extends MDCFoundation {
}

/**
* @param {string=} reason Why the snackbar was closed. Value will be passed to CLOSING_EVENT and CLOSED_EVENT via the
* @param reason Why the snackbar was closed. Value will be passed to CLOSING_EVENT and CLOSED_EVENT via the
* `event.detail.reason` property. Standard values are REASON_ACTION and REASON_DISMISS, but custom
* client-specific values may also be used if desired.
*/
Expand All @@ -144,24 +125,15 @@ class MDCSnackbarFoundation extends MDCFoundation {
}, numbers.SNACKBAR_ANIMATION_CLOSE_TIME_MS);
}

/**
* @return {boolean}
*/
isOpen() {
isOpen(): boolean {
return this.isOpen_;
}

/**
* @return {number}
*/
getTimeoutMs() {
getTimeoutMs(): number {
return this.autoDismissTimeoutMs_;
}

/**
* @param {number} timeoutMs
*/
setTimeoutMs(timeoutMs) {
setTimeoutMs(timeoutMs: number) {
// Use shorter variable names to make the code more readable
const minValue = numbers.MIN_AUTO_DISMISS_TIMEOUT_MS;
const maxValue = numbers.MAX_AUTO_DISMISS_TIMEOUT_MS;
Expand All @@ -173,62 +145,44 @@ class MDCSnackbarFoundation extends MDCFoundation {
}
}

/**
* @return {boolean}
*/
getCloseOnEscape() {
getCloseOnEscape(): boolean {
return this.closeOnEscape_;
}

/**
* @param {boolean} closeOnEscape
*/
setCloseOnEscape(closeOnEscape) {
setCloseOnEscape(closeOnEscape: boolean) {
this.closeOnEscape_ = closeOnEscape;
}

/**
* @param {!KeyboardEvent} evt
*/
handleKeyDown(evt) {
if (this.getCloseOnEscape() && (evt.key === 'Escape' || evt.keyCode === 27)) {
handleKeyDown(evt: KeyboardEvent) {
const isEscapeKey = evt.key === 'Escape' || evt.keyCode === 27;
if (isEscapeKey && this.getCloseOnEscape()) {
this.close(REASON_DISMISS);
}
}

/**
* @param {!MouseEvent} evt
*/
handleActionButtonClick(evt) {
handleActionButtonClick(_evt: MouseEvent) {
this.close(REASON_ACTION);
}

/**
* @param {!MouseEvent} evt
*/
handleActionIconClick(evt) {
handleActionIconClick(_evt: MouseEvent) {
this.close(REASON_DISMISS);
}

/** @private */
clearAutoDismissTimer_() {
private clearAutoDismissTimer_() {
clearTimeout(this.autoDismissTimer_);
this.autoDismissTimer_ = 0;
}

/** @private */
handleAnimationTimerEnd_() {
private handleAnimationTimerEnd_() {
this.animationTimer_ = 0;
this.adapter_.removeClass(cssClasses.OPENING);
this.adapter_.removeClass(cssClasses.CLOSING);
}

/**
* Runs the given logic on the next animation frame, using setTimeout to factor in Firefox reflow behavior.
* @param {Function} callback
* @private
*/
runNextAnimationFrame_(callback) {
private runNextAnimationFrame_(callback: () => void) {
cancelAnimationFrame(this.animationFrame_);
this.animationFrame_ = requestAnimationFrame(() => {
this.animationFrame_ = 0;
Expand All @@ -238,4 +192,4 @@ class MDCSnackbarFoundation extends MDCFoundation {
}
}

export default MDCSnackbarFoundation;
export {MDCSnackbarFoundation as default, MDCSnackbarFoundation};
Loading

0 comments on commit e95ff8a

Please sign in to comment.