Skip to content

Commit c6a46dd

Browse files
pgbrossstasson
authored andcommitted
feat(top-app-bar): Implement mdc-top-app-bar
as per MDC 0.32.0
1 parent f09aa67 commit c6a46dd

File tree

13 files changed

+336
-94
lines changed

13 files changed

+336
-94
lines changed

components/index.js

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,65 @@
11
//
22
// vue PlugIn
33
//
4-
import VueMDCButton from './button'
5-
import VueMDCCard from './card'
6-
import VueMDCCheckbox from './checkbox'
7-
import VueMDCChipSet from './chips'
8-
import VueMDCDialog from './dialog'
9-
import VueMDCDrawer from './drawer'
10-
import VueMDCElevation from './elevation'
11-
import VueMDCFab from './fab'
12-
import VueMDCGridList from './grid-list'
13-
import VueMDCIcon from './icon'
14-
import VueMDCIconToggle from './icon-toggle'
15-
import VueMDCLayoutApp from './layout-app'
16-
import VueMDCLayoutGrid from './layout-grid'
17-
import VueMDCLinearProgress from './linear-progress'
18-
import VueMDCList from './list'
19-
import VueMDCMenu from './menu'
20-
import VueMDCRadio from './radio'
21-
import VueMDCRipple from './ripple'
22-
import VueMDCSelect from './select'
23-
import VueMDCSlider from './slider'
24-
import VueMDCSnackbar from './snackbar'
25-
import VueMDCSwitch from './switch'
26-
import VueMDCTabs from './tabs'
27-
import VueMDCTextfield from './textfield'
28-
import VueMDCTheme from './theme'
29-
import VueMDCToolbar from './toolbar'
30-
import VueMDCTypography from './typography'
4+
import VueMDCButton from './button';
5+
import VueMDCCard from './card';
6+
import VueMDCCheckbox from './checkbox';
7+
import VueMDCChipSet from './chips';
8+
import VueMDCDialog from './dialog';
9+
import VueMDCDrawer from './drawer';
10+
import VueMDCElevation from './elevation';
11+
import VueMDCFab from './fab';
12+
import VueMDCGridList from './grid-list';
13+
import VueMDCIcon from './icon';
14+
import VueMDCIconToggle from './icon-toggle';
15+
import VueMDCLayoutApp from './layout-app';
16+
import VueMDCLayoutGrid from './layout-grid';
17+
import VueMDCLinearProgress from './linear-progress';
18+
import VueMDCList from './list';
19+
import VueMDCMenu from './menu';
20+
import VueMDCRadio from './radio';
21+
import VueMDCRipple from './ripple';
22+
import VueMDCSelect from './select';
23+
import VueMDCSlider from './slider';
24+
import VueMDCSnackbar from './snackbar';
25+
import VueMDCSwitch from './switch';
26+
import VueMDCTabs from './tabs';
27+
import VueMDCTextfield from './textfield';
28+
import VueMDCTheme from './theme';
29+
import VueMDCToolbar from './toolbar';
30+
import VueMDCTopAppBar from './top-app-bar';
31+
import VueMDCTypography from './typography';
3132

3233
export default {
3334
version: '__VERSION__',
34-
install (vm) {
35-
vm.use(VueMDCButton)
36-
vm.use(VueMDCCard)
37-
vm.use(VueMDCCheckbox)
38-
vm.use(VueMDCChipSet)
39-
vm.use(VueMDCDialog)
40-
vm.use(VueMDCDrawer)
41-
vm.use(VueMDCElevation)
42-
vm.use(VueMDCFab)
43-
vm.use(VueMDCGridList)
44-
vm.use(VueMDCIcon)
45-
vm.use(VueMDCIconToggle)
46-
vm.use(VueMDCLayoutApp)
47-
vm.use(VueMDCLayoutGrid)
48-
vm.use(VueMDCLinearProgress)
49-
vm.use(VueMDCList)
50-
vm.use(VueMDCMenu)
51-
vm.use(VueMDCRadio)
52-
vm.use(VueMDCRipple)
53-
vm.use(VueMDCSelect)
54-
vm.use(VueMDCSlider)
55-
vm.use(VueMDCSnackbar)
56-
vm.use(VueMDCSwitch)
57-
vm.use(VueMDCTabs)
58-
vm.use(VueMDCTextfield)
59-
vm.use(VueMDCTheme)
60-
vm.use(VueMDCToolbar)
61-
vm.use(VueMDCTypography)
62-
}
63-
}
35+
install(vm) {
36+
vm.use(VueMDCButton);
37+
vm.use(VueMDCCard);
38+
vm.use(VueMDCCheckbox);
39+
vm.use(VueMDCChipSet);
40+
vm.use(VueMDCDialog);
41+
vm.use(VueMDCDrawer);
42+
vm.use(VueMDCElevation);
43+
vm.use(VueMDCFab);
44+
vm.use(VueMDCGridList);
45+
vm.use(VueMDCIcon);
46+
vm.use(VueMDCIconToggle);
47+
vm.use(VueMDCLayoutApp);
48+
vm.use(VueMDCLayoutGrid);
49+
vm.use(VueMDCLinearProgress);
50+
vm.use(VueMDCList);
51+
vm.use(VueMDCMenu);
52+
vm.use(VueMDCRadio);
53+
vm.use(VueMDCRipple);
54+
vm.use(VueMDCSelect);
55+
vm.use(VueMDCSlider);
56+
vm.use(VueMDCSnackbar);
57+
vm.use(VueMDCSwitch);
58+
vm.use(VueMDCTabs);
59+
vm.use(VueMDCTextfield);
60+
vm.use(VueMDCTheme);
61+
vm.use(VueMDCToolbar);
62+
vm.use(VueMDCTopAppBar);
63+
vm.use(VueMDCTypography);
64+
},
65+
};

components/styles.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@
2424
@import './tabs/styles';
2525
@import './textfield/styles';
2626
@import './toolbar/styles';
27+
@import './top-app-bar/styles';
2728
@import './theme/styles';
2829
@import './typography/styles';

components/textfield/demo.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ export default {
4444
};
4545
</script>
4646

47-
<<style>
47+
<style>
4848
@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');
4949
</style>

components/top-app-bar/README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
## Usage
2+
3+
```html
4+
<mdc-top-app-bar title="Title2">
5+
<mdc-top-app-bar--action event="show-help" icon="help"></mdc-top-app-bar--action>
6+
</mdc-top-app-bar>
7+
```
8+
9+
### top-app-bars
10+
11+
`mdc-top-app-bar` acts as a container for multiple rows containing items such as
12+
application title, navigation menu, and tabs, among other things.
13+
top-app-bars scroll with content by default.
14+
15+
| props | Type | Default | Description |
16+
| -------------- | ------- | -------- | --------------------------------------------------------------- |
17+
| `short` | Boolean | | Short top app bars should only be used with one action item |
18+
| `collapsed` | String | false | Short top app bars can be configured to always appear collapsed |
19+
| `event` | String | optional | optional event to emit on navigation click |
20+
| `event-target` | Object | vm.$root | optional event target, defaults to root bus |
21+
22+
Short top app bars should only be used with one action item.
23+
Short top app bars can be configured to always appear collapsed by applying the `collapsed` attribute.
24+
25+
### Action icons
26+
27+
* `mdc-top-app-bar--action` wraps any icons placed on the right side of an
28+
mdc-top-app-bar.
29+
30+
| props | Type | Default | Description |
31+
| -------------- | ------ | -------- | ------------------------------------------- |
32+
| `icon` | String | | the material icon name |
33+
| `event` | String | optional | optional event to emit on action click |
34+
| `event-target` | Object | vm.$root | optional event target, defaults to root bus |
35+
36+
```html
37+
<mdc-top-app-bar title="Title" event="toggle-drawer">
38+
<mdc-top-app-bar--action event="show-help" icon="help"></mdc-top-app-bar--action>
39+
<mdc-top-app-bar--action event="do-download" icon="file_download"></mdc-top-app-bar--action>
40+
</mdc-top-app-bar>
41+
```
42+
43+
> if the `event` property is not specified, use @click to catch click events
44+
> do not set the icon prop to render your custom icons
45+
46+
**Font Awsome**
47+
48+
```html
49+
<mdc-top-app-bar--action event="show-help" iconClasses="fa fa-star"></mdc-top-app-bar--action>
50+
```
51+
52+
refer to the [MDC Documentation](https://material.io/components/web/catalog/toolbar/#flexible-toolbar-requires-javascript) to learn about customization options.
53+
54+
### Reference
55+
56+
* <https://material.io/components/web/catalog/top-app-bar>

components/top-app-bar/demo.vue

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<template>
2+
<div class="mdc-demo--appbar">
3+
<section class="mdc-demo">
4+
<mdc-top-app-bar title="Title2">
5+
<mdc-top-app-bar--action event="show-help" icon="help"></mdc-top-app-bar--action>
6+
<mdc-top-app-bar--action event="show-info" icon="info_outline"></mdc-top-app-bar--action>
7+
</mdc-top-app-bar>
8+
</section>
9+
10+
</div>
11+
</template>
12+
13+
<script>
14+
</script>
15+
16+
<style>
17+
@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css');
18+
19+
.mdc-demo--appbar {
20+
width: 100%;
21+
}
22+
</style>

components/top-app-bar/entry.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import './styles.scss'
2+
import {autoInit} from '../base'
3+
import plugin from './index.js'
4+
export default plugin
5+
6+
autoInit(plugin)

components/top-app-bar/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { BasePlugin } from '../base';
2+
import mdcTopAppBar from './mdc-top-app-bar.vue';
3+
import mdcTopAppBarAction from './mdc-top-app-bar--action.vue';
4+
5+
export { mdcTopAppBar, mdcTopAppBarAction };
6+
7+
export default BasePlugin({
8+
mdcTopAppBar,
9+
mdcTopAppBarAction,
10+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<a href="#" class="mdc-top-app-bar--action mdc-top-app-bar__action-item" :class="actioniconClasses" @click="dispatchEvent">
3+
<slot>{{icon}}</slot>
4+
</a>
5+
</template>
6+
7+
<script>
8+
import { DispatchEventMixin } from '../base';
9+
import { RippleMixin } from '../ripple';
10+
11+
export default {
12+
name: 'mdc-top-app-bar--action',
13+
mixins: [DispatchEventMixin, RippleMixin],
14+
props: {
15+
icon: String,
16+
iconClasses: Object,
17+
},
18+
computed: {
19+
actioniconClasses() {
20+
return {
21+
'material-icons': !!this.icon,
22+
...this.iconClasses,
23+
};
24+
},
25+
},
26+
};
27+
</script>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<template>
2+
<header ref="root" :class="rootClasses">
3+
<div class="mdc-top-app-bar__row">
4+
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start">
5+
<a ref="navigationIcon" href="#" :class="naviconClasses" v-if="haveNavigationIcon" @click="dispatchEvent">{{icon}}</a>
6+
<span class="mdc-top-app-bar__title" v-if="!!title">{{title}}</span>
7+
</section>
8+
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-end" v-if="$slots.default">
9+
<slot></slot>
10+
</section>
11+
</div>
12+
</header>
13+
</template>
14+
15+
<script>
16+
import MDCTopAppBarFoundation from '@material/top-app-bar/foundation';
17+
import * as util from '@material/top-app-bar/util';
18+
import { DispatchEventMixin, emitCustomEvent } from '../base';
19+
20+
export default {
21+
name: 'mdc-top-app-bar',
22+
props: {
23+
short: Boolean,
24+
shortCollapsed: Boolean,
25+
title: String,
26+
icon: {
27+
type: String,
28+
default: 'menu',
29+
},
30+
iconClasses: Object,
31+
},
32+
data() {
33+
return {
34+
rootClasses: {
35+
'mdc-top-app-bar': true,
36+
'mdc-top-app-bar--short': this.short,
37+
'mdc-top-app-bar--short-collapsed': this.shortCollapsed,
38+
},
39+
foundation: null,
40+
};
41+
},
42+
mixins: [DispatchEventMixin],
43+
mounted() {
44+
this.foundation = new MDCTopAppBarFoundation({
45+
addClass: className => {
46+
this.$set(this.rootClasses, className, true);
47+
},
48+
removeClass: className => {
49+
this.$delete(this.rootClasses, className);
50+
},
51+
hasClass: className => {
52+
return this.$refs.root.classList.contains(className);
53+
},
54+
registerNavigationIconInteractionHandler: (type, handler) => {
55+
if (this.$refs.navigationIcon) {
56+
this.$refs.navigationIcon.addEventListener(type, handler);
57+
}
58+
},
59+
deregisterNavigationIconInteractionHandler: (type, handler) => {
60+
if (this.$refs.navigationIcon) {
61+
this.$refs.navigationIcon.removeEventListener(type, handler);
62+
}
63+
},
64+
notifyNavigationIconClicked: () => {
65+
emitCustomEvent(
66+
this.$el,
67+
MDCTopAppBarFoundation.strings.NAVIGATION_EVENT,
68+
{},
69+
true,
70+
);
71+
},
72+
registerScrollHandler: handler => {
73+
window.addEventListener('scroll', handler, util.applyPassive());
74+
},
75+
deregisterScrollHandler: handler => {
76+
window.removeEventListener('scroll', handler);
77+
},
78+
79+
getViewportScrollY: () => {
80+
return window.pageYOffset;
81+
},
82+
getTotalActionItems: () =>
83+
this.$refs.root.querySelectorAll(
84+
MDCTopAppBarFoundation.strings.ACTION_ITEM_SELECTOR,
85+
).length,
86+
});
87+
this.foundation.init();
88+
},
89+
computed: {
90+
haveNavigationIcon() {
91+
return !!this.icon || this.iconClasses;
92+
},
93+
naviconClasses() {
94+
return {
95+
'mdc-top-app-bar__navigation-icon': true,
96+
'material-icons': !!this.icon,
97+
...this.iconClasses,
98+
};
99+
},
100+
},
101+
beforeDestroy() {
102+
this.foundation.destroy();
103+
},
104+
};
105+
</script>

components/top-app-bar/styles.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '@material/top-app-bar/mdc-top-app-bar';

components/top-app-bar/test.spec.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { pluginSanityCheck } from '../unit-test'
2+
import plugin from './index.js';
3+
4+
pluginSanityCheck(__dirname, plugin)

0 commit comments

Comments
 (0)