Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.
126 changes: 100 additions & 26 deletions demos/snackbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
<style>
/* initialize it off screen. */
.loading .example .mdc-snackbar { transform: translateY(100%); }
.loading .example .mdc-snackbar { transform: translateY(200%); }

.mdc-theme--dark {
background-color: #333;
}

.mdc-theme--dark .hero {
background-color: #2d2d2d;
}

/* Override style for hero example. */
.hero .mdc-snackbar {
Expand All @@ -43,6 +51,9 @@
padding-bottom: 8px;
}

.demo-activate-button {
margin-top: 14px;
}

</style>
</head>
Expand Down Expand Up @@ -88,33 +99,26 @@ <h2 class="mdc-typography--title">Basic Example</h2>
</div>
<label for="multiline" id="multiline-label">Multiline</label>
</div>
<br/>

<div class="mdc-checkbox-wrapper">
<div class="mdc-checkbox-wrapper__layout">
<div class="mdc-checkbox">
<input type="checkbox"
class="mdc-checkbox__native-control"
id="action-on-bottom"
aria-labelledby="action-on-bottom-label" />
<div class="mdc-checkbox__background">
<div class="mdc-form-field">
<div class="mdc-checkbox" id="action-on-bottom-checkbox">
<input type="checkbox" class="mdc-checkbox__native-control" id="action-on-bottom" aria-labelledby="action-on-bottom-label" />
<div class="mdc-checkbox__background">
<svg class="mdc-checkbox__checkmark" viewBox="0 0 24 24">
<path class="mdc-checkbox__checkmark__path" fill="none" stroke="white"
d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
d="M1.73,12.91 8.1,19.28 22.79,4.59"/>
</svg>
<div class="mdc-checkbox__mixedmark"></div>
</div>
</div>
<label for="action-on-bottom" id="action-on-bottom-label">Action On Bottom</label>
</div>
<br/>

<div class="mdc-checkbox-wrapper">
<div class="mdc-checkbox-wrapper__layout">
<div class="mdc-form-field">
<div class="mdc-checkbox">
<input type="checkbox"
checked
class="mdc-checkbox__native-control"
id="dismiss-on-action"
aria-labelledby="dismiss-on-action-label" />
<input type="checkbox" checked class="mdc-checkbox__native-control" id="dismiss-on-action" aria-labelledby="dismiss-on-action-label" />
<div class="mdc-checkbox__background">
<svg class="mdc-checkbox__checkmark" viewBox="0 0 24 24">
<path class="mdc-checkbox__checkmark__path" fill="none" stroke="white"
Expand All @@ -125,19 +129,27 @@ <h2 class="mdc-typography--title">Basic Example</h2>
</div>
<label for="dismiss-on-action" id="dismiss-on-action-label">Dismiss On Action</label>
</div>
<br/>

<div class="field">
<label for="message">Message Text</label>
<input type="text" id="message" value="Message deleted">
<button type="button" class="mdc-button mdc-button--raised mdc-button--primary" id="toggle-dark-theme">Toggle Dark Theme</button>
<br/>

<div class="mdc-textfield">
<input type="text" id="message" class="mdc-textfield__input" value="Message deleted">
<label class="mdc-textfield__label" for="message">Message Text</label>
</div>
<br/>

<div class="field">
<label for="action">Action Text</label>
<input type="text" id="action" value="Undo">
<div class="mdc-textfield">
<input type="text" id="action" class="mdc-textfield__input" value="Undo">
<label class="mdc-textfield__label" for="action">Action Text</label>
</div>
<br/>

<button type="button" id="show-snackbar">Show</button>
<button type="button" id="show-rtl-snackbar">Show RTL</button>
<button type="button" class="demo-activate-button mdc-button mdc-button--raised mdc-button--secondary" id="show-snackbar">Show</button>
<button type="button" class="demo-activate-button mdc-button mdc-button--raised mdc-button--secondary" id="show-rtl-snackbar">Show RTL</button>
<button type="button" class="demo-activate-button mdc-button mdc-button--raised mdc-button--secondary" id="show-start-aligned-snackbar">Show Start Aligned</button>
<button type="button" class="demo-activate-button mdc-button mdc-button--raised mdc-button--secondary" id="show-start-aligned-rtl-snackbar">Show Start Aligned (RTL)</button>

<div id="mdc-js-snackbar"
class="mdc-snackbar demo-hidden"
Expand All @@ -161,6 +173,28 @@ <h2 class="mdc-typography--title">Basic Example</h2>
</div>
</div>
</div>
<div id="mdc-align-start-js-snackbar"
class="mdc-snackbar mdc-snackbar--align-start demo-hidden"
aria-live="assertive"
aria-atomic="true"
aria-hidden="true">
<div class="mdc-snackbar__text"></div>
<div class="mdc-snackbar__action-wrapper">
<button type="button" class="mdc-button mdc-snackbar__action-button"></button>
</div>
</div>
<div dir="rtl">
<div id="mdc-align-start-rtl-js-snackbar"
class="mdc-snackbar mdc-snackbar--align-start demo-hidden"
aria-live="assertive"
aria-atomic="true"
aria-hidden="true">
<div class="mdc-snackbar__text"></div>
<div class="mdc-snackbar__action-wrapper">
<button type="button" class="mdc-button mdc-snackbar__action-button"></button>
</div>
</div>
</div>
</div>
</section>
</main>
Expand All @@ -171,28 +205,52 @@ <h2 class="mdc-typography--title">Basic Example</h2>
var MDCSnackbar = global.mdc.snackbar.MDCSnackbar;
var snackbar = new MDCSnackbar(document.getElementById('mdc-js-snackbar'));
var rtlSnackbar = new MDCSnackbar(document.getElementById('mdc-rtl-js-snackbar'));
var alignStartSnackbar = new MDCSnackbar(document.getElementById('mdc-align-start-js-snackbar'));
var alignStartRTLSnackbar = new MDCSnackbar(document.getElementById('mdc-align-start-rtl-js-snackbar'));
var messageInput = document.getElementById('message');
var actionInput = document.getElementById('action');
var multilineInput = document.getElementById('multiline');
var actionOnBottomInput = document.getElementById('action-on-bottom');
var actionOnBottomCheckbox = document.getElementById('action-on-bottom-checkbox');
var dismissOnActionInput = document.getElementById('dismiss-on-action');
var textFields = document.querySelectorAll('.mdc-textfield');

// Since Action on Bottom cannot be checked if Multi-line Input
// is not, we start with a disabled Action on Bottom option
actionOnBottomCheckbox.classList.add('mdc-checkbox--disabled');
actionOnBottomInput.disabled = true;
actionOnBottomInput.checked = false;

var show = function(sb) {
snackbar.dismissesOnAction = dismissOnActionInput.checked;
var data = {
message: messageInput.value,
actionOnBottom: actionOnBottomInput.checked,
multiline: multilineInput.checked
multiline: multilineInput.checked,
timeout: 2750
};

if (actionInput.value) {
data.actionText = actionInput.value;
data.actionHandler = function() {
console.log(data);
}
}

sb.show(data);
};

multilineInput.addEventListener('click', function () {
if (!multilineInput.checked) {
actionOnBottomCheckbox.classList.add('mdc-checkbox--disabled');
actionOnBottomInput.disabled = true;
actionOnBottomInput.checked = false;
} else {
actionOnBottomCheckbox.classList.remove('mdc-checkbox--disabled');
actionOnBottomInput.disabled = false;
}
});

document.getElementById('show-snackbar').addEventListener('click', function() {
show(snackbar);
});
Expand All @@ -201,6 +259,22 @@ <h2 class="mdc-typography--title">Basic Example</h2>
show(rtlSnackbar);
});

document.getElementById('show-start-aligned-snackbar').addEventListener('click', function() {
show(alignStartSnackbar);
});

document.getElementById('show-start-aligned-rtl-snackbar').addEventListener('click', function() {
show(alignStartRTLSnackbar);
});

document.getElementById('toggle-dark-theme').addEventListener('click', function(evt) {
document.body.classList.contains('mdc-theme--dark') ? document.body.classList.remove('mdc-theme--dark') : document.body.classList.add('mdc-theme--dark');
});

textFields.forEach(function(tf) {
mdc.textfield.MDCTextfield.attachTo(tf);
})

// Remove any element hiding after loading.
window.onload = function() { document.body.className = ''; };
})(this);
Expand Down
63 changes: 60 additions & 3 deletions packages/mdc-snackbar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ path: /catalog/snackbars/

The MDC Snackbar component is a spec-aligned snackbar/toast component adhering to the
[Material Design snackbars & toasts requirements](https://material.io/guidelines/components/snackbars-toasts.html#snackbars-toasts-specs).
It requires JavaScript the trigger the display and hide of the snackbar.
It requires JavaScript to show and hide itself.

## Design & API Documentation

Expand Down Expand Up @@ -53,6 +53,23 @@ npm install --save @material/snackbar
</div>
```

### Start Aligned Snackbars (tablet and desktop only)

MDC Snackbar can be start aligned (including in RTL contexts). To create a start-aligned
snackbar, add the `mdc-snackbar--align-start` modifier class to the root element.

```html
<div class="mdc-snackbar mdc-snackbar--align-start"
aria-live="assertive"
aria-atomic="true"
aria-hidden="true">
<div class="mdc-snackbar__text"></div>
<div class="mdc-snackbar__action-wrapper">
<button type="button" class="mdc-button mdc-snackbar__action-button"></button>
</div>
</div>
```

### Using the JS Component

MDC Snackbar ships with a Component / Foundation combo which provides the API for showing snackbar
Expand Down Expand Up @@ -125,6 +142,38 @@ properties and their usage.
| multiline | Whether to show the snackbar with space for multiple lines of text | Optional | Boolean |
| actionOnBottom | Whether to show the action below the multiple lines of text | Optional, applies when multiline is true | Boolean |

### Responding to a Snackbar Action

To respond to a snackbar action, assign a function to the optional `actionHandler` property in the object that gets passed to the `show` method. If you choose to set this property, you *must _also_* set the `actionText` property.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Could we also document it will throw an error in that case?

```html
<div class="mdc-snackbar"
aria-live="assertive"
aria-atomic="true"
aria-hidden="true">
<div class="mdc-snackbar__text"></div>
<div class="mdc-snackbar__action-wrapper">
<button type="button" class="mdc-button mdc-snackbar__action-button"></button>
</div>
</div>
```

```js
import {MDCSnackbar} from 'mdc-snackbar';

const snackbar = new MDCSnackbar(document.querySelector('.mdc-snackbar'));
const dataObj = {
message: messageInput.value,
actionText: 'Undo',
actionHandler: function () {
console.log('my cool function');
}
};

snackbar.show(dataObj);
```


### Keep snackbar when the action button is pressed

By default the snackbar will be dimissed when the user presses the action button.
Expand All @@ -149,10 +198,18 @@ The adapter for snackbars must provide the following functions, with correct sig
| `removeClass(className: string) => void` | Removes a class from the root element. |
| `setAriaHidden() => void` | Sets `aria-hidden="true"` on the root element. |
| `unsetAriaHidden() => void` | Removes the `aria-hidden` attribute from the root element. |
| `setMessageText(message: string) => void` | Set the text content of the message element. |
| `setActionText(actionText: string) => void` | Set the text content of the action element. |
| `setActionAriaHidden() => void` | Sets `aria-hidden="true"` on the action element. |
| `unsetActionAriaHidden() => void` | Removes the `aria-hidden` attribute from the action element. |
| `setActionText(actionText: string) => void` | Set the text content of the action element. |
Copy link
Contributor

Choose a reason for hiding this comment

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

super nit: Set => Sets

| `setMessageText(message: string) => void` | Set the text content of the message element. |
Copy link
Contributor

Choose a reason for hiding this comment

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

same thing here :)

| `setFocus() => void` | Sets 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 |
| `registerVisibilityChangeHandler(handler: EventListener) => void` | Registers an event handler to be called when a 'visibilitychange' event occurs |
| `deregisterVisibilityChangeHandler(handler: EventListener) => void` | Deregisters an event handler to be called when a 'visibilitychange' event occurs |
| `registerCapturedInteractionHandler(evtType: string, handler: EventListener) => void` | Registers an event handler to be called when the given event type is triggered on the `body` |
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: should we call it capture or capturing, that seems better aligned with MDN description and make people aware that these handlers are using useCapture?

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 don't think so. What this name suggests is that we are doing something with an interaction that has previously been captured (albeit immediately after).

I agree we should be acknowledging that we are listening during the capture phase. 👍

| `deregisterCapturedInteractionHandler(evtType: string, handler: EventListener) => void` | Deregisters an event handler from the `body` |
| `registerActionClickHandler(handler: EventListener) => void` | Registers an event handler to be called when a `click` event is triggered on the action element. |
| `deregisterActionClickHandler(handler: EventListener) => void` | Deregisters an event handler from a `click` event on the action element. This will only be called with handlers that have previously been passed to `registerActionClickHandler` calls. |
| `registerTransitionEndHandler(handler: EventListener) => void` | Registers an event handler to be called when an `transitionend` event is triggered on the root element. Note that you must account for vendor prefixes in order for this to work correctly. |
Expand Down
1 change: 1 addition & 0 deletions packages/mdc-snackbar/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

// Hard coded since the color is not present in any palette.
$mdc-snackbar-background-color: #323232;
$mdc-snackbar-background-color-on-dark: #fafafa;
$mdc-snackbar-foreground-color: white;
// TODO: Better spot to pull this breakpoint?
//$snackbar-tablet-breakpoint: $grid-tablet-breakpoint;
Expand Down
Loading