diff --git a/demos/checkbox.html b/demos/checkbox.html
index d80046e52c7..b1935d53d0a 100644
--- a/demos/checkbox.html
+++ b/demos/checkbox.html
@@ -159,6 +159,7 @@
Dark Theme
@@ -192,6 +193,9 @@
Dark Theme
var checkbox = document.getElementById('mdc-js-checkbox');
var checkboxInstance = new MDCCheckbox(checkbox);
+ var disabledCheckbox = document.getElementById('mdc-disabled-js-checkbox');
+ var disabledCheckboxInstance = new MDCCheckbox(disabledCheckbox);
+
var formField = checkbox.parentElement;
var formFieldInstance = new MDCFormField(formField);
formFieldInstance.input = checkboxInstance;
diff --git a/packages/mdc-checkbox/README.md b/packages/mdc-checkbox/README.md
index 7ea3c3bc743..37935ca47b9 100644
--- a/packages/mdc-checkbox/README.md
+++ b/packages/mdc-checkbox/README.md
@@ -211,6 +211,7 @@ The adapter for checkboxes must provide the following functions, with correct si
| `forceLayout() => void` | Force-trigger a layout on the root element. This is needed to restart animations correctly. If you find that you do not need to do this, you can simply make it a no-op. |
| `isAttachedToDOM() => boolean` | Returns true if the component is currently attached to the DOM, false otherwise.` |
+
#### MDCCheckboxFoundation API
##### MDCCheckboxFoundation.isChecked() => boolean
diff --git a/packages/mdc-radio/README.md b/packages/mdc-radio/README.md
index 0c08a4dd601..05cc0d93fb6 100644
--- a/packages/mdc-radio/README.md
+++ b/packages/mdc-radio/README.md
@@ -162,6 +162,7 @@ Since MDC Radio is primarily driven by its native control, the adapter API is ex
| `addClass(className: string) => void` | Adds a class to the root element. |
| `removeClass(className: string) => void` | Removes a class from the root element. |
+
#### The full foundation API
##### MDCRadioFoundation.isChecked() => boolean
diff --git a/packages/mdc-ripple/README.md b/packages/mdc-ripple/README.md
index b1ae1b0813f..5ef77bb6cf6 100644
--- a/packages/mdc-ripple/README.md
+++ b/packages/mdc-ripple/README.md
@@ -261,6 +261,7 @@ ripple to. The adapter API is as follows:
| `browserSupportsCssVars() => boolean` | Whether or not the given browser supports CSS Variables. When implementing this, please take the [Safari considerations](#caveat-safari) into account. We provide a `supportsCssVariables` function within the `util.js` which we recommend using, as it handles this for you. |
| `isUnbounded() => boolean` | Whether or not the ripple should be considered unbounded. |
| `isSurfaceActive() => boolean` | Whether or not the surface the ripple is acting upon is [active](https://www.w3.org/TR/css3-selectors/#useraction-pseudos). We use this to detect whether or not a keyboard event has activated the surface the ripple is on. This does not need to make use of `:active` (which is what we do); feel free to supply your own heuristics for it. |
+| `isSurfaceDisabled() => boolean` | Whether or not the ripple is attached to a disabled component. If true, the ripple will not activate. |
| `addClass(className: string) => void` | Adds a class to the ripple surface |
| `removeClass(className: string) => void` | Removes a class from the ripple surface |
| `registerInteractionHandler(evtType: string, handler: EventListener) => void` | Registers an event handler that's invoked when the ripple is interacted with using type `evtType`. Essentially equivalent to `HTMLElement.prototype.addEventListener`. |
diff --git a/packages/mdc-ripple/foundation.js b/packages/mdc-ripple/foundation.js
index d4c77621918..aaf9af0ad32 100644
--- a/packages/mdc-ripple/foundation.js
+++ b/packages/mdc-ripple/foundation.js
@@ -45,6 +45,7 @@ export default class MDCRippleFoundation extends MDCFoundation {
browserSupportsCssVars: () => /* boolean - cached */ {},
isUnbounded: () => /* boolean */ {},
isSurfaceActive: () => /* boolean */ {},
+ isSurfaceDisabled: () => /* boolean */ {},
addClass: (/* className: string */) => {},
removeClass: (/* className: string */) => {},
registerInteractionHandler: (/* evtType: string, handler: EventListener */) => {},
@@ -67,6 +68,7 @@ export default class MDCRippleFoundation extends MDCFoundation {
constructor(adapter) {
super(Object.assign(MDCRippleFoundation.defaultAdapter, adapter));
+
this.layoutFrame_ = 0;
this.frame_ = {width: 0, height: 0};
this.activationState_ = this.defaultActivationState_();
@@ -142,6 +144,10 @@ export default class MDCRippleFoundation extends MDCFoundation {
}
activate_(e) {
+ if (this.adapter_.isSurfaceDisabled()) {
+ return;
+ }
+
const {activationState_: activationState} = this;
if (activationState.isActivated) {
return;
diff --git a/packages/mdc-ripple/index.js b/packages/mdc-ripple/index.js
index 10fa98c3690..f4919b2fb96 100644
--- a/packages/mdc-ripple/index.js
+++ b/packages/mdc-ripple/index.js
@@ -37,6 +37,7 @@ export class MDCRipple extends MDCComponent {
browserSupportsCssVars: () => supportsCssVariables(window),
isUnbounded: () => instance.unbounded,
isSurfaceActive: () => instance.root_[MATCHES](':active'),
+ isSurfaceDisabled: () => instance.disabled,
addClass: (className) => instance.root_.classList.add(className),
removeClass: (className) => instance.root_.classList.remove(className),
registerInteractionHandler: (evtType, handler) => instance.root_.addEventListener(evtType, handler),
diff --git a/test/unit/mdc-ripple/foundation-activation.test.js b/test/unit/mdc-ripple/foundation-activation.test.js
index 1be61071fdd..81fe74daa85 100644
--- a/test/unit/mdc-ripple/foundation-activation.test.js
+++ b/test/unit/mdc-ripple/foundation-activation.test.js
@@ -21,6 +21,20 @@ import {cssClasses, strings, numbers} from '../../../packages/mdc-ripple/constan
suite('MDCRippleFoundation - Activation Logic');
+testFoundation('does nothing if component if isSurfaceDisabled is true',
+ ({foundation, adapter, mockRaf}) => {
+ const handlers = captureHandlers(adapter);
+ foundation.init();
+ mockRaf.flush();
+
+ td.when(adapter.isSurfaceDisabled()).thenReturn(true);
+
+ handlers.mousedown();
+
+ td.verify(adapter.addClass(cssClasses.BG_ACTIVE_FILL), {times: 0});
+ td.verify(adapter.addClass(cssClasses.FG_ACTIVATION), {times: 0});
+});
+
testFoundation('adds activation classes on mousedown', ({foundation, adapter, mockRaf}) => {
const handlers = captureHandlers(adapter);
foundation.init();
diff --git a/test/unit/mdc-ripple/foundation.test.js b/test/unit/mdc-ripple/foundation.test.js
index 72d17ea8088..32c0b8b74a2 100644
--- a/test/unit/mdc-ripple/foundation.test.js
+++ b/test/unit/mdc-ripple/foundation.test.js
@@ -39,9 +39,10 @@ test('numbers returns constants.numbers', () => {
test('defaultAdapter returns a complete adapter implementation', () => {
verifyDefaultAdapter(MDCRippleFoundation, [
- 'browserSupportsCssVars', 'isUnbounded', 'isSurfaceActive', 'addClass', 'removeClass',
- 'registerInteractionHandler', 'deregisterInteractionHandler', 'registerResizeHandler',
- 'deregisterResizeHandler', 'updateCssVariable', 'computeBoundingRect', 'getWindowPageOffset',
+ 'browserSupportsCssVars', 'isUnbounded', 'isSurfaceActive', 'isSurfaceDisabled',
+ 'addClass', 'removeClass', 'registerInteractionHandler', 'deregisterInteractionHandler',
+ 'registerResizeHandler', 'deregisterResizeHandler', 'updateCssVariable',
+ 'computeBoundingRect', 'getWindowPageOffset',
]);
});
diff --git a/test/unit/mdc-ripple/mdc-ripple.test.js b/test/unit/mdc-ripple/mdc-ripple.test.js
index f336e9ed430..10ec77398fa 100644
--- a/test/unit/mdc-ripple/mdc-ripple.test.js
+++ b/test/unit/mdc-ripple/mdc-ripple.test.js
@@ -111,6 +111,12 @@ test('adapter#isSurfaceActive calls the correct :matches API method on the root
assert.isOk(component.getDefaultFoundation().adapter_.isSurfaceActive());
});
+test('adapter#isSurfaceDisabled delegates to component\'s disabled getter', () => {
+ const {component} = setupTest();
+ component.disabled = true;
+ assert.isTrue(component.getDefaultFoundation().adapter_.isSurfaceDisabled());
+});
+
test('adapter#addClass adds a class to the root', () => {
const {root, component} = setupTest();
component.getDefaultFoundation().adapter_.addClass('foo');