mirror of
https://github.com/Hopiu/vue-material.git
synced 2026-03-31 05:10:32 +00:00
Merge pull request #269 from marcosmoura/components/mdFile
Components/md file
This commit is contained in:
commit
449e358cb7
11 changed files with 343 additions and 15 deletions
|
|
@ -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>
|
||||
|
|
|
|||
122
docs/src/pages/components/File.vue
Normal file
122
docs/src/pages/components/File.vue
Normal 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>
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
8
src/components/mdFile/index.js
Normal file
8
src/components/mdFile/index.js
Normal 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);
|
||||
}
|
||||
21
src/components/mdFile/mdFile.scss
Normal file
21
src/components/mdFile/mdFile.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
5
src/components/mdFile/mdFile.theme
Normal file
5
src/components/mdFile/mdFile.theme
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.THEME_NAME {
|
||||
&.md-file {
|
||||
|
||||
}
|
||||
}
|
||||
100
src/components/mdFile/mdFile.vue
Normal file
100
src/components/mdFile/mdFile.vue
Normal 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>
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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'};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue