Merge pull request #269 from marcosmoura/components/mdFile

Components/md file
This commit is contained in:
Marcos Moura 2016-12-29 01:56:28 -02:00 committed by GitHub
commit 449e358cb7
11 changed files with 343 additions and 15 deletions

View file

@ -71,6 +71,10 @@
<router-link exact to="/components/dialog">Dialog</router-link>
</md-list-item>
<md-list-item class="md-inset">
<router-link exact to="/components/file">File</router-link>
</md-list-item>
<md-list-item class="md-inset">
<router-link exact to="/components/icon">Icon</router-link>
</md-list-item>

View file

@ -0,0 +1,122 @@
<template>
<page-content page-title="Components - File">
<docs-component>
<div slot="description">
<p>The file picker aim to select files like images, videos and other formats. They can have multiselection and use the devide file system to pick the file.</p>
</div>
<div slot="api">
<api-table name="md-file">
<md-table slot="properties">
<md-table-header>
<md-table-row>
<md-table-head>Name</md-table-head>
<md-table-head>Type</md-table-head>
<md-table-head>Description</md-table-head>
</md-table-row>
</md-table-header>
<md-table-body>
<md-table-row>
<md-table-cell>v-model</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>A required model object to bind the value.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>id</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>Sets the input id.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>name</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>Sets the input name.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>disabled</md-table-cell>
<md-table-cell><code>Boolean</code></md-table-cell>
<md-table-cell>Disable the input and prevent his actions. Default <code>false</code></md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>required</md-table-cell>
<md-table-cell><code>Boolean</code></md-table-cell>
<md-table-cell>Apply the required rule to style the label with an "*". Default <code>false</code></md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>accept</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>Filter files that can be selected by mimetype pattern.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>multiple</md-table-cell>
<md-table-cell><code>Boolean</code></md-table-cell>
<md-table-cell>Enable multiple selection.</md-table-cell>
</md-table-row>
</md-table-body>
</md-table>
</api-table>
</div>
<div slot="example">
<example-box card-title="Single File">
<div slot="demo">
<md-input-container>
<label>Single</label>
<md-file v-model="single"></md-file>
</md-input-container>
<md-input-container>
<md-file v-model="placeholder" placeholder="A nice input placeholder"></md-file>
</md-input-container>
<md-input-container>
<md-file placeholder="Disabled" disabled></md-file>
</md-input-container>
<md-input-container>
<label>Initial Value</label>
<md-file v-model="initialValue"></md-file>
</md-input-container>
<md-input-container>
<label>Multiple</label>
<md-file v-model="multiple" multiple></md-file>
</md-input-container>
<md-input-container>
<label>Only Images</label>
<md-file v-model="onlyImages" accept="image/*"></md-file>
</md-input-container>
</div>
<div slot="code">
<code-block lang="xml">
</code-block>
</div>
</example-box>
</div>
</docs-component>
</page-content>
</template>
<script>
export default {
data: () => ({
single: null,
placeholder: null,
initialValue: 'my-profile-picture.jpg',
multiple: null,
onlyImages: null
}),
methods: {
}
};
</script>

View file

@ -14,6 +14,7 @@ const Card = (resolve) => require(['./pages/components/Card'], resolve);
const Checkbox = (resolve) => require(['./pages/components/Checkbox'], resolve);
const Chips = (resolve) => require(['./pages/components/Chips'], resolve);
const Dialog = (resolve) => require(['./pages/components/Dialog'], resolve);
const File = (resolve) => require(['./pages/components/File'], resolve);
const Icon = (resolve) => require(['./pages/components/Icon'], resolve);
const ImageLoader = (resolve) => require(['./pages/components/ImageLoader'], resolve);
const InkRipple = (resolve) => require(['./pages/components/InkRipple'], resolve);
@ -110,6 +111,11 @@ const components = [
name: 'components:dialog',
component: Dialog
},
{
path: '/components/file',
name: 'components:file',
component: File
},
{
path: '/components/icon',
name: 'components:icon',

View file

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

View file

@ -0,0 +1,21 @@
@import '../../core/stylesheets/variables.scss';
.md-file {
display: flex;
flex: 1;
input[type="file"] {
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
position: absolute;
clip: rect(0 0 0 0);
border: 0;
}
.md-icon {
cursor: pointer;
}
}

View file

@ -0,0 +1,5 @@
.THEME_NAME {
&.md-file {
}
}

View file

@ -0,0 +1,100 @@
<template>
<div class="md-file" @click="openPicker">
<md-input
readonly
v-model="filename"
:required="required"
:placeholder="placeholder"
:disabled="disabled"
ref="textInput">
</md-input>
<md-icon>attach_file</md-icon>
<input
type="file"
:id="id"
:name="name"
:disabled="disabled"
:multiple="multiple"
:accept="accept"
@change="onFileSelected"
ref="fileInput">
</div>
</template>
<style lang="scss" src="./mdFile.scss"></style>
<script>
import getClosestVueParent from '../../core/utils/getClosestVueParent';
export default {
props: {
value: String,
id: String,
name: String,
disabled: Boolean,
required: Boolean,
placeholder: String,
accept: String,
multiple: Boolean
},
data() {
return {
filename: this.value
};
},
watch: {
value() {
this.filename = this.value;
}
},
methods: {
getMultipleName(files) {
let names = [];
[...files].forEach((file) => {
names.push(file.name);
});
return names.join(', ');
},
openPicker() {
if (!this.disabled) {
this.$refs.fileInput.click();
this.$refs.textInput.$el.focus();
}
},
onFileSelected($event) {
const files = $event.target.files || $event.dataTransfer.files;
if (files) {
if (files.length > 1) {
this.filename = this.getMultipleName(files);
} else if (files.length === 1) {
this.filename = files[0].name;
}
} else {
this.filename = $event.target.value.split('\\').pop();
}
this.$emit('selected', files || $event.target.value);
this.$emit('input', this.filename);
}
},
mounted() {
this.parentContainer = getClosestVueParent(this.$parent, 'md-input-container');
if (!this.parentContainer) {
this.$destroy();
throw new Error('You should wrap the md-file in a md-input-container');
}
this.parentContainer.hasFile = true;
},
beforeDestroy() {
this.parentContainer.hasFile = false;
}
};
</script>

View file

@ -7,6 +7,7 @@ $input-size: 32px;
min-height: 48px;
margin: 4px 0 24px;
padding-top: 16px;
display: flex;
position: relative;
&:after {
@ -38,6 +39,7 @@ $input-size: 32px;
height: $input-size;
padding: 0;
display: block;
flex: 1;
border: none;
background: none;
transition: $swift-ease-out;
@ -57,6 +59,15 @@ $input-size: 32px;
text-shadow: none;
-webkit-text-fill-color: initial;
}
~ .md-icon {
margin-left: 12px;
&:after {
right: 0;
left: auto;
}
}
}
textarea {
@ -67,22 +78,51 @@ $input-size: 32px;
line-height: 1.3em;
}
.md-error {
height: 20px;
display: block !important;
position: absolute;
opacity: 0;
transform: translate3d(0, -8px, 0);
transition: $swift-ease-in;
font-size: 12px;
}
.md-error,
.md-count {
height: 20px;
position: absolute;
right: 0;
top: 50px;
font-size: 12px;
}
.md-error {
display: block !important;
opacity: 0;
transform: translate3d(0, -8px, 0);
transition: $swift-ease-in;
}
.md-count {
right: 0;
}
.md-icon {
color: rgba(#000, .54);
transition: $swift-ease-out;
&:after {
width: 36px;
height: 2px;
position: absolute;
left: 0;
bottom: 0;
z-index: 2;
content: "";
}
~ {
label {
left: 36px;
}
.md-input,
.md-textarea,
.md-file {
margin-left: 12px;
}
}
}
}
.md-input-container {

View file

@ -6,10 +6,11 @@
}
label,
input,
textarea,
.md-error,
.md-count,
input,
textarea {
.md-icon {
color: #{'WARN-COLOR'};
}
}
@ -39,9 +40,26 @@
-webkit-text-fill-color: transparent;
}
label {
label,
.md-icon {
color: #{'PRIMARY-COLOR'};
}
}
&.md-input-disabled {
label,
input,
textarea,
.md-error,
.md-count,
.md-icon,
::-webkit-input-placeholder {
color: #{'BACKGROUND-CONTRAST-0.38'};
}
}
.md-icon:after {
background: #{'BACKGROUND-COLOR'};
}
}
}

View file

@ -30,6 +30,7 @@
enableCounter: false,
hasSelect: false,
hasPlaceholder: false,
hasFile: false,
isDisabled: false,
isRequired: false,
isFocused: false,
@ -50,6 +51,7 @@
'md-input-inline': this.mdInline,
'md-has-password': this.mdHasPassword,
'md-has-select': this.hasSelect,
'md-has-file': this.hasFile,
'md-has-value': this.hasValue,
'md-input-placeholder': this.hasPlaceholder,
'md-input-disabled': this.isDisabled,
@ -80,7 +82,7 @@
}
},
mounted() {
this.input = this.$el.querySelectorAll('input, textarea, select')[0];
this.input = this.$el.querySelectorAll('input, textarea, select, .md-file')[0];
if (!this.input) {
this.$destroy();

View file

@ -9,6 +9,7 @@ import MdCheckbox from './components/mdCheckbox';
import MdChips from './components/mdChips';
import MdDialog from './components/mdDialog';
import MdDivider from './components/mdDivider';
import MdFile from './components/mdFile';
import MdIcon from './components/mdIcon';
import MdImage from './components/mdImage';
import MdInputContainer from './components/mdInputContainer';
@ -40,6 +41,7 @@ const options = {
MdChips,
MdDialog,
MdDivider,
MdFile,
MdIcon,
MdImage,
MdInputContainer,