start creation of snackbars

This commit is contained in:
Marcos Moura 2016-12-05 05:19:01 -02:00
parent fb57ad2747
commit 09393ad2de
13 changed files with 354 additions and 24 deletions

View file

@ -101,6 +101,10 @@
<router-link exact to="/components/sidenav">Sidenav</router-link>
</md-list-item>
<md-list-item class="md-inset">
<router-link exact to="/components/snackbar">Snackbar</router-link>
</md-list-item>
<md-list-item class="md-inset">
<router-link exact to="/components/subheader">Subheader</router-link>
</md-list-item>

View file

@ -7,7 +7,7 @@
<md-card-area>
<md-tabs md-right :md-dynamic-height="false" class="md-transparent example-tabs">
<md-tab class="example-content" md-label="Demo">
<md-tab class="example-content" md-label="Demo" md-active>
<slot name="demo"></slot>
</md-tab>

View file

@ -34,10 +34,7 @@ Vue.material.theme.registerAll({
},
'light-blue': {
primary: 'light-blue',
accent: {
color: 'cyan',
hue: 'A200'
}
accent: 'yellow'
},
teal: {
primary: 'teal',

View file

@ -0,0 +1,79 @@
<template>
<page-content page-title="Components - Snackbar">
<docs-component>
<div slot="description">
<p>Snackbars contain a single line of text directly related to the operation performed. They may contain a text action, but no icons.</p>
</div>
<div slot="api">
<api-table name="md-snackbar">
</api-table>
</div>
<div slot="example">
<example-box card-title="Default">
<div slot="demo">
<div>
<md-button class="md-primary md-raised" @click="$refs.snackbar1.open()">Open bottom center</md-button>
<md-button class="md-primary md-raised" @click="$refs.snackbar2.open()">Open bottom left</md-button>
<md-button class="md-primary md-raised" @click="$refs.snackbar3.open()">Open bottom right</md-button>
</div>
<div>
<md-button class="md-primary md-raised" @click="$refs.snackbar4.open()">Open top center</md-button>
<md-button class="md-primary md-raised" @click="$refs.snackbar5.open()">Open top left</md-button>
<md-button class="md-primary md-raised" @click="$refs.snackbar6.open()">Open top right</md-button>
</div>
<md-snackbar md-position="bottom center" ref="snackbar1">
Connection timeout. Showing limited messages.
<md-button class="md-accent" v-md-theme="'light-blue'" @click="$refs.snackbar1.close()">Retry</md-button>
</md-snackbar>
<md-snackbar md-position="bottom left" ref="snackbar2">
Connection timeout. Showing limited messages.
<md-button class="md-accent" v-md-theme="'light-blue'" @click="$refs.snackbar2.close()">Retry</md-button>
</md-snackbar>
<md-snackbar md-position="bottom right" ref="snackbar3">
Connection timeout. Showing limited messages.
<md-button class="md-accent" v-md-theme="'light-blue'" @click="$refs.snackbar3.close()">Retry</md-button>
</md-snackbar>
<md-snackbar md-position="top center" ref="snackbar4">
Connection timeout. Showing limited messages.
<md-button class="md-accent" v-md-theme="'light-blue'" @click="$refs.snackbar4.close()">Retry</md-button>
</md-snackbar>
<md-snackbar md-position="top left" ref="snackbar5">
Connection timeout. Showing limited messages.
<md-button class="md-accent" v-md-theme="'light-blue'" @click="$refs.snackbar5.close()">Retry</md-button>
</md-snackbar>
<md-snackbar md-position="top right" ref="snackbar6">
Connection timeout. Showing limited messages.
<md-button class="md-accent" v-md-theme="'light-blue'" @click="$refs.snackbar6.close()">Retry</md-button>
</md-snackbar>
</div>
<div slot="code">
<code-block lang="xml">
</code-block>
</div>
</example-box>
</div>
</docs-component>
</page-content>
</template>
<style lang="scss" scoped>
</style>
<script>
export default {
};
</script>

View file

@ -14,13 +14,14 @@ import Card from './pages/components/Card';
import Checkbox from './pages/components/Checkbox';
import Dialog from './pages/components/Dialog';
import Icon from './pages/components/Icon';
import InkRipple from './pages/components/InkRipple';
import Input from './pages/components/Input';
import List from './pages/components/List';
import Menu from './pages/components/Menu';
import Radio from './pages/components/Radio';
import InkRipple from './pages/components/InkRipple';
import Select from './pages/components/Select';
import Sidenav from './pages/components/Sidenav';
import Snackbar from './pages/components/Snackbar';
import Subheader from './pages/components/Subheader';
import Switch from './pages/components/Switch';
import Table from './pages/components/Table';
@ -106,6 +107,11 @@ const components = [
name: 'components:icon',
component: Icon
},
{
path: '/components/ink-ripple',
name: 'components:ink-ripple',
component: InkRipple
},
{
path: '/components/input',
name: 'components:input',
@ -126,11 +132,6 @@ const components = [
name: 'components:radio',
component: Radio
},
{
path: '/components/ink-ripple',
name: 'components:ink-ripple',
component: InkRipple
},
{
path: '/components/select',
name: 'components:select',
@ -142,15 +143,20 @@ const components = [
component: Sidenav
},
{
path: '/components/switch',
name: 'components:switch',
component: Switch
path: '/components/snackbar',
name: 'components:snackbar',
component: Snackbar
},
{
path: '/components/subheader',
name: 'components:subheader',
component: Subheader
},
{
path: '/components/switch',
name: 'components:switch',
component: Switch
},
{
path: '/components/table',
name: 'components:table',

View file

@ -135,7 +135,7 @@ $button-icon-size: 40px;
border-radius: $button-fab-size;
line-height: $button-fab-size;
background-clip: padding-box;
transition: $swift-ease-in;
transition: $swift-ease-out;
transition-property: background-color,
box-shadow,
transform;

View file

@ -0,0 +1,8 @@
import mdSnackbar from './mdSnackbar.vue';
import mdSnackbarTheme from './mdSnackbar.theme';
export default function install(Vue) {
Vue.component('md-snackbar', Vue.extend(mdSnackbar));
Vue.material.styles.push(mdSnackbarTheme);
}

View file

@ -0,0 +1,137 @@
@import '../../core/stylesheets/variables.scss';
.md-snackbar {
min-width: 288px;
max-width: 568px;
min-height: 48px;
padding: 14px 24px;
position: fixed;
z-index: 120;
overflow: hidden;
border-radius: 2px;
background-color: #323232;
transition: $swift-ease-out;
color: #fff;
font-size: 14px;
&.md-position-bottom-center {
bottom: 0;
left: 50%;
transform: translate(-50%, 100%, 0);
}
&.md-position-bottom-right {
bottom: 8px;
right: 8px;
transform: translate(0, 100%, 0);
}
&.md-position-bottom-left {
bottom: 8px;
left: 8px;
transform: translate(0, 100%, 0);
}
&.md-position-top-center {
top: 0;
left: 50%;
transform: translate(-50%, -100%, 0);
}
&.md-position-top-right {
top: 8px;
right: 8px;
transform: translate(0, -100%, 0);
}
&.md-position-top-left {
top: 8px;
left: 8px;
transform: translate(0, -100%, 0);
}
&.md-active {
&.md-position-bottom-center {
transform: translate(-50%, 0, 0);
}
&.md-position-bottom-right {
transform: translate(0, 0, 0);
}
&.md-position-bottom-left {
transform: translate(0, 0, 0);
}
&.md-position-top-center {
transform: translate(-50%, 0, 0);
}
&.md-position-top-right {
transform: translate(0, 0, 0);
}
&.md-position-top-left {
transform: translate(0, 0, 0);
}
.md-snackbar-content {
opacity: 1;
transition: opacity .4s .1s $swift-ease-out-timing-function;
}
}
.md-snackbar-content {
display: flex;
align-items: center;
justify-content: space-between;
opacity: 0;
transition: opacity .2s $swift-ease-out-timing-function;
will-change: opacity;
}
.md-button {
min-width: 64px;
margin: -8px -16px;
&:last-child {
margin-left: 48px;
}
}
}
.md-has-toast-top-right {
.md-fab.md-fab-top-right {
transform: translate(0, 48px, 0);
}
}
.md-has-toast-top-center {
.md-fab.md-fab-top-center {
transform: translate(-50%, 48px, 0);
}
}
.md-has-toast-top-left {
.md-fab.md-fab-top-left {
transform: translate(0, 48px, 0);
}
}
.md-has-toast-bottom-right {
.md-fab.md-fab-bottom-right {
transform: translate(0, -48px, 0);
}
}
.md-has-toast-bottom-center {
.md-fab.md-fab-bottom-center {
transform: translate(-50%, -48px, 0);
}
}
.md-has-toast-bottom-left {
.md-fab.md-fab-bottom-left {
transform: translate(0, -48px, 0);
}
}

View file

@ -0,0 +1,8 @@
.THEME_NAME {
.md-snackbar,
&.md-snackbar {
.md-ink-ripple {
color: #fff;
}
}
}

View file

@ -0,0 +1,90 @@
<template>
<div class="md-snackbar" :class="classes">
<div class="md-snackbar-content">
<slot></slot>
</div>
</div>
</template>
<style lang="scss" src="./mdSnackbar.scss"></style>
<script>
import transitionEndEventName from '../../core/utils/transitionEndEventName';
export default {
props: {
mdPosition: {
type: String,
default: 'bottom center'
},
mdDuration: {
type: [String, Number],
default: 4000
}
},
data() {
return {
active: false,
closeTimeout: null,
positionClass: this.mdPosition.replace(/ /g, '-')
};
},
computed: {
classes() {
let cssClasses = {
'md-active': this.active
};
cssClasses['md-position-' + this.positionClass] = true;
return cssClasses;
}
},
methods: {
removeSnackbar() {
const snackbars = [...document.querySelectorAll('.md-snackbar')];
const activeRipple = this.snackbarElement.querySelector('.md-ripple.md-active');
snackbars.forEach((snackbar) => {
if (snackbar.parentNode) {
snackbar.parentNode.removeChild(snackbar);
}
});
if (activeRipple) {
activeRipple.classList.remove('md-active');
}
},
open() {
this.removeSnackbar();
this.rootElement.appendChild(this.snackbarElement);
this.rootElement.classList.add('md-has-toast-' + this.positionClass);
window.getComputedStyle(this.snackbarElement).transition;
this.closeTimeout = window.setTimeout(this.close, this.mdDuration);
this.active = true;
this.$emit('open');
},
close() {
if (this.rootElement.contains(this.snackbarElement)) {
window.clearTimeout(this.closeTimeout);
this.active = false;
this.rootElement.classList.remove('md-has-toast-' + this.positionClass);
this.snackbarElement.removeEventListener(transitionEndEventName, this.removeSnackbar);
this.snackbarElement.addEventListener(transitionEndEventName, this.removeSnackbar);
this.$emit('close');
}
}
},
mounted() {
this.$nextTick(() => {
this.rootElement = this.$root.$el;
this.snackbarElement = this.$el;
this.removeSnackbar();
});
},
beforeDestroy() {
this.removeSnackbar();
}
};
</script>

View file

@ -62,20 +62,20 @@
}
},
mounted() {
let tabData = this.getTabData();
this.parentTabs = getClosestVueParent(this.$parent, 'md-tabs');
if (!this.parentTabs) {
throw new Error('You must wrap the md-tab in a md-tabs');
}
this.$nextTick(() => {
this.mounted = true;
this.parentTabs.registerTab(this.getTabData());
this.mounted = true;
this.parentTabs.registerTab(tabData);
if (this.mdActive) {
this.parentTabs.activeTab = this.tabId;
}
});
if (this.mdActive) {
this.parentTabs.setActiveTab(tabData);
}
},
beforeDestroy() {
this.parentTabs.unregisterTab(this.getTabData());

View file

@ -94,7 +94,6 @@
},
registerTab(tabData) {
this.tabList[tabData.id] = tabData;
this.$forceUpdate();
},
unregisterTab(tabData) {
delete this.tabList[tabData.id];
@ -196,7 +195,7 @@
this.observeElementChanges();
window.addEventListener('resize', this.calculateOnWatch);
if (!this.activeTab) {
if (this.tabList.length && !this.activeTab) {
let firstTab = Object.keys(this.tabList)[0];
this.setActiveTab(this.tabList[firstTab]);

View file

@ -15,6 +15,7 @@ import MdMenu from './components/mdMenu';
import MdRadio from './components/mdRadio';
import MdSelect from './components/mdSelect';
import MdSidenav from './components/mdSidenav';
import MdSnackbar from './components/mdSnackbar';
import MdSubheader from './components/mdSubheader';
import MdSwitch from './components/mdSwitch';
import MdTable from './components/mdTable';
@ -41,6 +42,7 @@ const options = {
MdRadio,
MdSelect,
MdSidenav,
MdSnackbar,
MdSubheader,
MdSwitch,
MdTable,