mirror of
https://github.com/Hopiu/vue-material.git
synced 2026-05-14 18:23:10 +00:00
start creation of snackbars
This commit is contained in:
parent
fb57ad2747
commit
09393ad2de
13 changed files with 354 additions and 24 deletions
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ Vue.material.theme.registerAll({
|
|||
},
|
||||
'light-blue': {
|
||||
primary: 'light-blue',
|
||||
accent: {
|
||||
color: 'cyan',
|
||||
hue: 'A200'
|
||||
}
|
||||
accent: 'yellow'
|
||||
},
|
||||
teal: {
|
||||
primary: 'teal',
|
||||
|
|
|
|||
79
docs/src/pages/components/Snackbar.vue
Normal file
79
docs/src/pages/components/Snackbar.vue
Normal 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>
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
8
src/components/mdSnackbar/index.js
Normal file
8
src/components/mdSnackbar/index.js
Normal 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);
|
||||
}
|
||||
137
src/components/mdSnackbar/mdSnackbar.scss
Normal file
137
src/components/mdSnackbar/mdSnackbar.scss
Normal 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);
|
||||
}
|
||||
}
|
||||
8
src/components/mdSnackbar/mdSnackbar.theme
Normal file
8
src/components/mdSnackbar/mdSnackbar.theme
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
.THEME_NAME {
|
||||
.md-snackbar,
|
||||
&.md-snackbar {
|
||||
.md-ink-ripple {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
90
src/components/mdSnackbar/mdSnackbar.vue
Normal file
90
src/components/mdSnackbar/mdSnackbar.vue
Normal 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>
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue