diff --git a/packages/mdc-snackbar/README.md b/packages/mdc-snackbar/README.md index fe4b3929fcc..026a894d185 100644 --- a/packages/mdc-snackbar/README.md +++ b/packages/mdc-snackbar/README.md @@ -206,6 +206,7 @@ The adapter for snackbars must provide the following functions, with correct sig | `setActionText(actionText: string) => void` | Set the text content of the action element. | | `setMessageText(message: string) => void` | Set the text content of the message element. | | `setFocus() => void` | Sets focus on the action button. | +| `isFocused() => boolean` | Detects focus on the action button. | | `visibilityIsHidden() => boolean` | Returns document.hidden property. | | `registerBlurHandler(handler: EventListener) => void` | Registers an event handler to be called when a `blur` event is triggered on the action button | | `deregisterBlurHandler(handler: EventListener) => void` | Deregisters a `blur` event handler from the actionButton | diff --git a/packages/mdc-snackbar/foundation.js b/packages/mdc-snackbar/foundation.js index 04bb9329d8a..67dae158356 100644 --- a/packages/mdc-snackbar/foundation.js +++ b/packages/mdc-snackbar/foundation.js @@ -37,6 +37,7 @@ export default class MDCSnackbarFoundation extends MDCFoundation { setActionText: (/* actionText: string */) => {}, setMessageText: (/* message: string */) => {}, setFocus: () => {}, + isFocused: () => /* boolean */ false, visibilityIsHidden: () => /* boolean */ false, registerCapturedBlurHandler: (/* handler: EventListener */) => {}, deregisterCapturedBlurHandler: (/* handler: EventListener */) => {}, @@ -81,12 +82,15 @@ export default class MDCSnackbarFoundation extends MDCFoundation { } }; this.interactionHandler_ = (evt) => { - if (evt.type == 'touchstart' || evt.type == 'mousedown') { + if (evt.type === 'focus' && !this.adapter_.isFocused()) { + return; + } + if (evt.type === 'touchstart' || evt.type === 'mousedown') { this.pointerDownRecognized_ = true; } this.handlePossibleTabKeyboardFocus_(evt); - if (evt.type == 'focus') { + if (evt.type === 'focus') { this.pointerDownRecognized_ = false; } }; diff --git a/packages/mdc-snackbar/index.js b/packages/mdc-snackbar/index.js index f9283435978..0256ceac6e3 100644 --- a/packages/mdc-snackbar/index.js +++ b/packages/mdc-snackbar/index.js @@ -48,6 +48,7 @@ export class MDCSnackbar extends MDCComponent { setActionText: (text) => {getActionButton().textContent = text;}, setMessageText: (text) => {getText().textContent = text;}, setFocus: () => getActionButton().focus(), + isFocused: () => document.activeElement === getActionButton(), visibilityIsHidden: () => document.hidden, registerCapturedBlurHandler: (handler) => getActionButton().addEventListener('blur', handler, true), deregisterCapturedBlurHandler: (handler) => getActionButton().removeEventListener('blur', handler, true), diff --git a/test/unit/mdc-snackbar/foundation.test.js b/test/unit/mdc-snackbar/foundation.test.js index 6f4534f7a29..4dea45119d0 100644 --- a/test/unit/mdc-snackbar/foundation.test.js +++ b/test/unit/mdc-snackbar/foundation.test.js @@ -44,7 +44,7 @@ test('defaultAdapter returns a complete adapter implementation', () => { assert.equal(methods.length, Object.keys(defaultAdapter).length, 'Every adapter key must be a function'); assert.deepEqual(methods, [ 'addClass', 'removeClass', 'setAriaHidden', 'unsetAriaHidden', 'setActionAriaHidden', - 'unsetActionAriaHidden', 'setActionText', 'setMessageText', 'setFocus', 'visibilityIsHidden', + 'unsetActionAriaHidden', 'setActionText', 'setMessageText', 'setFocus', 'isFocused', 'visibilityIsHidden', 'registerCapturedBlurHandler', 'deregisterCapturedBlurHandler', 'registerVisibilityChangeHandler', 'deregisterVisibilityChangeHandler', 'registerCapturedInteractionHandler', 'deregisterCapturedInteractionHandler', 'registerActionClickHandler', diff --git a/test/unit/mdc-snackbar/mdc-snackbar.test.js b/test/unit/mdc-snackbar/mdc-snackbar.test.js index 4a0ec672c31..812dd1b41a0 100644 --- a/test/unit/mdc-snackbar/mdc-snackbar.test.js +++ b/test/unit/mdc-snackbar/mdc-snackbar.test.js @@ -146,6 +146,18 @@ test('adapter#setFocus sets focus on the action button', () => { document.body.removeChild(root); }); +test('adapter#isFocused detects focus on the action button', () => { + const {root, component} = setupTest(); + const handler = td.func('fixture focus handler'); + root.addEventListener('focus', handler); + document.body.appendChild(root); + + component.getDefaultFoundation().adapter_.setFocus(); + + assert.isOk(component.getDefaultFoundation().adapter_.isFocused()); + document.body.removeChild(root); +}); + test('adapter#visibilityIsHidden returns the document.hidden property', () => { const {component} = setupTest(); assert.equal(component.getDefaultFoundation().adapter_.visibilityIsHidden(), document.hidden);