From f0571553222a95b01ffbecf2c50980f043afc794 Mon Sep 17 00:00:00 2001 From: Marius Date: Sat, 11 Feb 2017 02:31:07 +0200 Subject: [PATCH 001/172] Fix Sidebar Right option (#128) Added missing prop for right option. --- src/components/sidebar/Sidebar.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/sidebar/Sidebar.js b/src/components/sidebar/Sidebar.js index 80b03b6ea7c..c1ed4597563 100755 --- a/src/components/sidebar/Sidebar.js +++ b/src/components/sidebar/Sidebar.js @@ -15,6 +15,8 @@ export default { fixed: Boolean, + right: Boolean, + height: String, mobile: { From bd5502665b078004e73fe60a6cc30c19668c0376 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 11 Feb 2017 22:17:28 -0500 Subject: [PATCH 002/172] start of form refactor --- src/components/forms/TextInput.vue | 14 +- src/stylus/components/_forms.styl | 469 +++++++++++++++++----------- src/stylus/settings/_variables.styl | 11 +- 3 files changed, 311 insertions(+), 183 deletions(-) diff --git a/src/components/forms/TextInput.vue b/src/components/forms/TextInput.vue index 6ebfe6d4d7c..8d259c0f9c9 100755 --- a/src/components/forms/TextInput.vue +++ b/src/components/forms/TextInput.vue @@ -4,7 +4,7 @@ v-bind:class="classes" ) label( - v-bind:for="id" + v-bind:for="id || name" v-html="label" ) input( @@ -37,16 +37,26 @@ classes () { return { 'input-group--focused': this.focused, - 'input-group--dirty': this.value || this.placeholder + 'input-group--dirty': this.value || this.placeholder, + 'input-group--disabled': this.disabled, + 'input-group--light': this.light && !this.dark, + 'input-group--dark': this.dark } } }, props: { + dark: Boolean, + disabled: Boolean, label: String, + light: { + type: Boolean, + default: true + }, + id: String, name: String, diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index 23568de340b..385a75a86af 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -1,216 +1,325 @@ +/** Base Spec */ .input-group + height: $input-group-height position: relative - margin-bottom: 1rem width: 100% - - label - color: $theme.primary + + &:after, &:before + content: '' position: absolute - top: 15px - transition: $primary-transition + left: 0 + + &:after + background-color: $theme.primary + bottom: 7px + height: 2px + transition: .3s $transition.fast-out-slow-in + width: 0% + z-index: 1 - input - border-bottom: 1px solid #ddd - height: 3rem + &:before + bottom: 8px + height: 1px width: 100% - position: relative + z-index: 0 + + +/** Label */ +.input-group label + display: block + font-size $input-font-size + pointer-events: none + position: absolute + transform: translate3d(0, 34px, 0) + transform-origin: top left + transition: .4s $transition.fast-in-fast-out + +/** Input */ +.input-group input + font-size: $input-font-size + margin-top: 36px + margin-bottom: 16px + height: 20px + transition: .3s $transition.ease-in-out + width: 100% + + &:focus + outline: none - &:focus - outline: none - - &[type=radio] - display: none + &:disabled + pointer-events: none + + +/** Themes */ +.input-group + &--light + &:before + background-color: $material-twelve-percent-dark + + input + color: rgba(#000, .87) + + &:disabled + color: rgba(#000, .38) + + label + color: rgba(#000, .38) + + &.input-group--disabled:before + background-image: linear-gradient(to right, rgba(#000,0.38) 0, rgba(#000,0.38) 33%, transparent 0) + + + &--dark + &:before + background-color: $material-twelve-percent-light + + input + color: #fff &:disabled - + label - &:before - border-color: $grey.lighten-2 + color: rgba(#fff, .5) + + label + color: rgba(#fff, .50) + + &.input-group--disabled:before + background-image: linear-gradient(to right, rgba(#fff,0.38) 0, rgba(#fff,0.38) 33%, transparent 0) + + +/** Input States */ +.input-group + &--focused + label + color: $theme.primary + transform: translate3d(0, 16px, 0) scale(.75) + + &:after + width: 100% + + &--dirty + label + transform: translate3d(0, 16px, 0) scale(.75) + + &.input-group--disabled:before + background-color: transparent + background-position: bottom + background-size: 3px 1px + background-repeat: repeat-x + + +// .input-group +// position: relative +// margin-bottom: 1rem +// width: 100% + +// label +// color: $theme.primary +// position: absolute +// top: 15px +// transition: $primary-transition + +// input +// border-bottom: 1px solid #ddd +// height: 3rem +// width: 100% +// position: relative + +// &:focus +// outline: none + +// &[type=radio] +// display: none + +// &:disabled +// + label +// &:before +// border-color: $grey.lighten-2 - &:checked - + label - &:before - border-color: $grey.lighten-2 +// &:checked +// + label +// &:before +// border-color: $grey.lighten-2 - &:after - background: $grey.lighten-2 +// &:after +// background: $grey.lighten-2 - + label - padding-left: 1.5rem - cursor: pointer - position: relative - top: 0 +// + label +// padding-left: 1.5rem +// cursor: pointer +// position: relative +// top: 0 - &:before - content: "" - position: absolute - left: 0 - top: 2px - width: 1rem - height: 1rem - border-radius: 50% - border: 2px solid $grey.darken-1 - z-index: 1 - transition: $secondary-transition +// &:before +// content: "" +// position: absolute +// left: 0 +// top: 2px +// width: 1rem +// height: 1rem +// border-radius: 50% +// border: 2px solid $grey.darken-1 +// z-index: 1 +// transition: $secondary-transition - &:after - content: "" - position: absolute - left: 0 - top: 2px - width: 1rem - height: 1rem - transform: scale(0) - border-radius: 50% - z-index: 2 - background: transparent - transition: $secondary-transition +// &:after +// content: "" +// position: absolute +// left: 0 +// top: 2px +// width: 1rem +// height: 1rem +// transform: scale(0) +// border-radius: 50% +// z-index: 2 +// background: transparent +// transition: $secondary-transition - &:checked - + label - &:before - border: 2px solid $theme.secondary - background: transparent +// &:checked +// + label +// &:before +// border: 2px solid $theme.secondary +// background: transparent - &:after - background: $theme.secondary - transform: scale(1) +// &:after +// background: $theme.secondary +// transform: scale(1) - &.gap - &:checked - + label - &:after - transform: scale(.45) +// &.gap +// &:checked +// + label +// &:after +// transform: scale(.45) - &[type=checkbox] - display: none +// &[type=checkbox] +// display: none - &:disabled - + label - &:before - background: $grey.lighten-2 - border-color: $grey.lighten-2 +// &:disabled +// + label +// &:before +// background: $grey.lighten-2 +// border-color: $grey.lighten-2 - &:checked - + label - &:before - background: transparent - border-bottom-color: $grey.lighten-2 - border-right-color: $grey.lighten-2 +// &:checked +// + label +// &:before +// background: transparent +// border-bottom-color: $grey.lighten-2 +// border-right-color: $grey.lighten-2 - + label - padding-left: 30px - cursor: pointer - position: relative - top: 0 - left: 0 - display: flex - align-items: center - height: 20px - width: 100% +// + label +// padding-left: 30px +// cursor: pointer +// position: relative +// top: 0 +// left: 0 +// display: flex +// align-items: center +// height: 20px +// width: 100% - &:after - top: 0 - left: 0 - width: 20px - height: 20px +// &:after +// top: 0 +// left: 0 +// width: 20px +// height: 20px - &:before - content: "" - position: absolute - left: 0 - top: 0 - width: 20px - height: 20px - z-index: 2 - transition: $secondary-transition - border: 2px solid $grey.darken-1 - transform-origin: 100% 100% +// &:before +// content: "" +// position: absolute +// left: 0 +// top: 0 +// width: 20px +// height: 20px +// z-index: 2 +// transition: $secondary-transition +// border: 2px solid $grey.darken-1 +// transform-origin: 100% 100% - &:checked - + label - &:before - border-bottom-color: $theme.secondary - border-left-color: transparent - border-right-color: $theme.secondary - border-top-color: transparent - transform: rotate(50deg) - width: 8px - top: -2px - left: 0 +// &:checked +// + label +// &:before +// border-bottom-color: $theme.secondary +// border-left-color: transparent +// border-right-color: $theme.secondary +// border-top-color: transparent +// transform: rotate(50deg) +// width: 8px +// top: -2px +// left: 0 - &.filled - + label - &:before - border-color: transparent +// &.filled +// + label +// &:before +// border-color: transparent - &:after - content: "" - background: transparent - position: absolute - border: 2px solid $grey.darken-1 - border-radius: .15rem - transition: $secondary-transition +// &:after +// content: "" +// background: transparent +// position: absolute +// border: 2px solid $grey.darken-1 +// border-radius: .15rem +// transition: $secondary-transition - &:checked - + label - &:before - border-bottom: 2px solid #fff - border-right: 2px solid #fff - top: -3px - left: 0 - transform: rotate(37deg) scale(.8) +// &:checked +// + label +// &:before +// border-bottom: 2px solid #fff +// border-right: 2px solid #fff +// top: -3px +// left: 0 +// transform: rotate(37deg) scale(.8) - &:after - background: $theme.secondary - border-color: $theme.secondary +// &:after +// background: $theme.secondary +// border-color: $theme.secondary - &:indeterminate - + label - &:before - border-right-color: $theme.secondary - left: -15px - top: -6px - border-top: 0px solid transparent - border-left: 0px solid transparent - border-bottom: 0px solid transparent - transform: rotate(90deg) - width: 1.2rem - height: 1.2rem +// &:indeterminate +// + label +// &:before +// border-right-color: $theme.secondary +// left: -15px +// top: -6px +// border-top: 0px solid transparent +// border-left: 0px solid transparent +// border-bottom: 0px solid transparent +// transform: rotate(90deg) +// width: 1.2rem +// height: 1.2rem - &:after - border: none - background: transparent +// &:after +// border: none +// background: transparent - select - border-bottom: 1px solid #ddd - height: 3rem - width: 100% - position: relative +// select +// border-bottom: 1px solid #ddd +// height: 3rem +// width: 100% +// position: relative - &:focus - outline: none +// &:focus +// outline: none - &[multiple] - border: 1px solid #ddd - height: 10rem - top: 9px - margin-bottom: 1rem +// &[multiple] +// border: 1px solid #ddd +// height: 10rem +// top: 9px +// margin-bottom: 1rem - &:after - content: "" - width: 0% - height: 2px - background-color: $theme.primary - position: absolute - bottom: -1px - left: 0 - transition: $primary-transition +// &:after +// content: "" +// width: 0% +// height: 2px +// background-color: $theme.primary +// position: absolute +// bottom: -1px +// left: 0 +// transition: $primary-transition - &--focused, &--dirty - label - top: -9px - font-size: .8rem +// &--focused, &--dirty +// label +// top: -9px +// font-size: .8rem - &--focused - &:after - width: 100% \ No newline at end of file +// &--focused +// &:after +// width: 100% \ No newline at end of file diff --git a/src/stylus/settings/_variables.styl b/src/stylus/settings/_variables.styl index c332ea33685..7411572c568 100755 --- a/src/stylus/settings/_variables.styl +++ b/src/stylus/settings/_variables.styl @@ -124,7 +124,8 @@ $transition := { fast-out-slow-in: cubic-bezier(0.4, 0.0, 0.2, 1), linear-out-slow-in: cubic-bezier(0.0, 0.0, 0.2, 1), fast-out-linear-in: cubic-bezier(0.4, 0.0, 1, 1), - ease-in-out: cubic-bezier(0.4, 0.0, 0.6, 1) + ease-in-out: cubic-bezier(0.4, 0.0, 0.6, 1), + fast-in-fast-out: cubic-bezier(.25,.8,.25,1) } // Components @@ -316,6 +317,14 @@ $sidebar-group-header-active-sidebar-item-active-background-color := rgba($theme // Slider $slider-arrow-size := 2rem +/** Text Input */ +$input-group-height := 72px +$label-font-size := 12px +$label-padding-top := 16px +$label-padding-bottom := 8px +$input-font-size := 16px +$input-padding-bottom := 8px + // Directives // ============================================================ From c0529f55ba21311236c99cfbc44b84e19df435b0 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 12 Feb 2017 14:42:26 -0500 Subject: [PATCH 003/172] moved text-input into button dropdown --- src/components/buttons/ButtonDropdown.vue | 74 ++++++-------- src/stylus/components/_button-dropdown.styl | 101 +++----------------- src/stylus/tools/_button-dropdown.styl | 16 ++++ src/stylus/tools/_mixins.styl | 2 + 4 files changed, 59 insertions(+), 134 deletions(-) create mode 100755 src/stylus/tools/_button-dropdown.styl diff --git a/src/components/buttons/ButtonDropdown.vue b/src/components/buttons/ButtonDropdown.vue index 9fcfa17cb54..4b8f4ebfcc9 100755 --- a/src/components/buttons/ButtonDropdown.vue +++ b/src/components/buttons/ButtonDropdown.vue @@ -3,15 +3,6 @@ class="btn-dropdown" v-bind:class="classes" ) - input( - v-if="editable" - ref="input" - v-bind:class="{ 'active': isActive }" - v-bind:placeholder="placeholder" - v-on:click.stop="isActive = true" - v-on:keyup.enter="updateValue(editableValue)" - v-model="editableValue" - ) v-menu( v-bind:auto="!overflow && !segmented && !editable" v-bind:right="!overflow && !segmented && !editable" @@ -20,21 +11,17 @@ v-model="isActive" bottom ) - v-btn( - v-bind:class="{ 'btn--active': isActive, 'btn--editable': isActive && editable }" + v-text-input( + ref="input" + v-bind:type="editable ? 'text' : 'button'" + v-bind:label="label" + v-on:click.native.stop="isActive = true" + v-on:keyup.native.enter="updateValue(editableValue)" slot="activator" - light + v-model="editableValue" + single-line + menu ) - span( - v-if="inputValue && inputValue.text" - v-text="inputValue.text" - class="btn-dropdown__title" - ) - v-icon(v-if="inputValue && inputValue.action") {{ inputValue.action }} - v-icon( - class="btn-dropdown__arrow" - v-on:click.native.stop="isActive = !isActive" - ) arrow_drop_down v-list v-list-item(v-for="(option, index) in options") v-list-tile( @@ -54,33 +41,29 @@ data () { return { isActive: false, - inputValue: this.value || { text: this.placeholder }, - editableValue: '' + inputValue: this.value, + editableValue: null } }, props: { + dark: Boolean, editable: Boolean, - + light: { + type: Boolean, + default: true + }, options: { type: Array, default: () => [] }, - maxHeight: { type: [String, Number], default: 200 }, - overflow: Boolean, - - placeholder: { - type: String, - default: 'Select' - }, - + label: String, segmented: Boolean, - value: { required: false } @@ -91,7 +74,9 @@ return { 'btn-dropdown--editable': this.editable, 'btn-dropdown--overflow': this.overflow || this.segmented || this.editable, - 'btn-dropdown--segmented': this.segmented + 'btn-dropdown--segmented': this.segmented, + 'btn-dropdown--light': this.light && !this.dark, + 'btn-dropdown--dark': this.dark } }, @@ -101,7 +86,7 @@ } if (this.index !== -1 && - (this.overflow || this.segmented || this.editable) + (this.overflow || this.segmented) ) { return this.options.filter((obj, i) => i !== this.index) } @@ -115,14 +100,16 @@ }, mounted () { - this.editableValue = this.inputValue.text + if (this.inputValue) { + this.editableValue = this.inputValue.text + } }, watch: { isActive () { if (this.editable) { if (!this.isActive) { - this.$refs.input.blur() + this.$refs.input.$el.querySelector('input').blur() } } }, @@ -147,18 +134,11 @@ updateValue (obj) { if (typeof obj === 'string') { - obj = { title: obj } + obj = { text: obj } } this.inputValue = obj - - this.$emit('input', obj) - - if (this.editable) { - this.editableValue = obj.text - this.inputValue = obj - } - + this.editableValue = obj.text || obj.action this.isActive = false } } diff --git a/src/stylus/components/_button-dropdown.styl b/src/stylus/components/_button-dropdown.styl index de7fb6f1aa6..7b57493b404 100755 --- a/src/stylus/components/_button-dropdown.styl +++ b/src/stylus/components/_button-dropdown.styl @@ -3,100 +3,27 @@ position: relative input - background: transparent - font-size: $button-dropdown-font-size - font-weight: $button-dropdown-font-weight - height: calc(100% - 2px) - left: 0 - outline: none - padding-left: $button-dropdown-input-padding-left - position: absolute - top: 1px - width: $button-dropdown-input-width - z-index: 2 - - &.active - background: #fff + text-align: left .menu, .menu__activator width: 100% - .btn - align-items: center - background: transparent - border-bottom: $button-dropdown-border-bottom - border-radius: 0 - box-shadow: initial - color: $color-root - display: flex - font-size: $button-dropdown-font-size - font-weight: $button-dropdown-font-weight - justify-content: space-between - width: 100% - padding: 0 - text-transform: initial - z-index: 1 - - &:after - display: none - - .btn__content - justify-content: space-between - - .icon:not(.btn-dropdown__arrow) - padding: 0 6px - - &__arrow - color: $grey.base - cursor: pointer - position: absolute - right: 7px - top: 50% - transform: translateY(-50%) - transition: $primary-transition + &--overflow, &--editable, &--segmented + input + padding-left: 16px + min-height: 40px - &--segmented .btn, &--editable .btn--active - &:before - background: $material-twelve-percent-dark - content: '' - height: 100% - position: absolute - right: 38px - top: 0 - width: 1px + .input-group--focused .input-group__wrapper + background-color: #fff - &--overflow, &--editable - .btn - border-top: 1px solid $material-twelve-percent-dark - height: $button-dropdown-overflow-editable-height - min-width: $button-dropdown-overflow-editable-min-width - padding: $button-dropdown-overflow-editable-padding + .input-group__wrapper + transition: .3s $transition.ease-in-out &:hover - background-color: $button-dropdown-background - - &.btn--active - background: $button-dropdown-background - border-top-left-radius: 2px - border-top-right-radius: 2px - @extend .z-depth-2 - - &:after - background: #fff - bottom: -4px - height: 3px - top: initial - - .btn-dropdown__arrow - transform: rotate(-180deg) translateY(50%) - - &--overflow, &--editable, &--segmented - .btn - margin: 0 + background-color: #fff - &--editable - .btn - pointer-events: none + &--light + btn-dropdown-theme($material-twelve-percent-dark) - &-dropdown__title - opacity: 0 \ No newline at end of file + &--dark + btn-dropdown-theme($material-twelve-percent-light) \ No newline at end of file diff --git a/src/stylus/tools/_button-dropdown.styl b/src/stylus/tools/_button-dropdown.styl new file mode 100755 index 00000000000..93a5550dc6b --- /dev/null +++ b/src/stylus/tools/_button-dropdown.styl @@ -0,0 +1,16 @@ +btn-dropdown-theme(theme) + &.btn-dropdown--segmented + input + border-right: 1px solid theme + + &.btn-dropdown--editable + .input-group--focused + input + border-right: 1px solid theme + + &.btn-dropdown--overflow, &.btn-dropdown--editable, &.btn-dropdown--segmented + .input-group + border-top: 1px solid theme + + .input-group__hint:after + display: none \ No newline at end of file diff --git a/src/stylus/tools/_mixins.styl b/src/stylus/tools/_mixins.styl index 8a483b2549e..9e5a0db8541 100755 --- a/src/stylus/tools/_mixins.styl +++ b/src/stylus/tools/_mixins.styl @@ -1,4 +1,6 @@ @import './_alerts' +@import './_button-dropdown' @import './_colors' +@import './_forms' @import './_lists' @import './_progress-linear' \ No newline at end of file From 93eb0324d8d9d0f3d21c2fa265c4d520ce4ab2a2 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 12 Feb 2017 14:42:34 -0500 Subject: [PATCH 004/172] updates to text-input --- src/components/forms/TextInput.vue | 45 +++++--- src/stylus/components/_forms.styl | 163 +++++++++++++++++----------- src/stylus/settings/_variables.styl | 16 ++- src/stylus/tools/_forms.styl | 34 ++++++ 4 files changed, 178 insertions(+), 80 deletions(-) create mode 100755 src/stylus/tools/_forms.styl diff --git a/src/components/forms/TextInput.vue b/src/components/forms/TextInput.vue index 8d259c0f9c9..24491ea8d0a 100755 --- a/src/components/forms/TextInput.vue +++ b/src/components/forms/TextInput.vue @@ -7,18 +7,24 @@ v-bind:for="id || name" v-html="label" ) - input( - v-bind:disabled="disabled" - v-bind:id="id" - v-bind:name="name" - v-bind:placeholder="placeholder" - v-bind:required="required" - v-bind:type="type" - v-bind:value="inputValue" - v-on:blur="blur" - v-on:input="updateValue" - v-on:focus="focus" - ref="input" + div(class="input-group__wrapper") + v-icon(v-if="icon") {{ icon }} + input( + v-bind:disabled="disabled" + v-bind:id="id" + v-bind:name="name" + v-bind:required="required" + v-bind:type="type" + v-bind:value="inputValue" + v-on:blur="blur" + v-on:input="updateValue" + v-on:focus="focus" + ref="input" + ) + v-icon(v-if="menu" class="input-group__menu") arrow_drop_down + div( + class="input-group__hint" + v-text="error" ) @@ -37,10 +43,13 @@ classes () { return { 'input-group--focused': this.focused, - 'input-group--dirty': this.value || this.placeholder, + 'input-group--dirty': this.inputValue, 'input-group--disabled': this.disabled, 'input-group--light': this.light && !this.dark, - 'input-group--dark': this.dark + 'input-group--dark': this.dark, + 'input-group--single-line': this.singleLine, + 'input-group--error': this.error, + 'input-group--icon': this.icon } } }, @@ -50,6 +59,8 @@ disabled: Boolean, + error: String, + label: String, light: { @@ -57,14 +68,20 @@ default: true }, + icon: String, + id: String, + menu: Boolean, + name: String, placeholder: String, required: Boolean, + singleLine: Boolean, + type: { default: 'text' }, diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index 385a75a86af..9658a3d4e9f 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -1,27 +1,10 @@ /** Base Spec */ .input-group - height: $input-group-height + display: flex + flex-wrap: wrap + margin: $input-group-margin position: relative width: 100% - - &:after, &:before - content: '' - position: absolute - left: 0 - - &:after - background-color: $theme.primary - bottom: 7px - height: 2px - transition: .3s $transition.fast-out-slow-in - width: 0% - z-index: 1 - - &:before - bottom: 8px - height: 1px - width: 100% - z-index: 0 /** Label */ @@ -30,81 +13,135 @@ font-size $input-font-size pointer-events: none position: absolute - transform: translate3d(0, 34px, 0) + transform: translate3d(0, 3px, 0) transform-origin: top left transition: .4s $transition.fast-in-fast-out - + + /** Input */ .input-group input font-size: $input-font-size - margin-top: 36px - margin-bottom: 16px - height: 20px - transition: .3s $transition.ease-in-out - width: 100% + flex: 1 + margin: 0 + min-width: 0 + height: $input-height + + .icon + padding: 0 6px + transition: .3s $transition.ease-in-out + &:focus outline: none + + .icon + transform: rotate(-180deg) + &:disabled pointer-events: none - -/** Themes */ + +/** Hint Text */ .input-group - &--light - &:before - background-color: $material-twelve-percent-dark - - input - color: rgba(#000, .87) - - &:disabled - color: rgba(#000, .38) - - label - color: rgba(#000, .38) + &__hint + color: $theme.error + flex: 1 0 100% + font-size: 12px + min-height: 16px + position: relative + margin-top: 1px + padding-top: 4px + width: 100% + + &:after, &:before + content: '' + position: absolute + left: 0 + + &:after + background-color: $theme.primary + top: -1.5px + height: 2px + transition: .3s $transition.fast-out-slow-in + width: 0% + z-index: 1 - &.input-group--disabled:before - background-image: linear-gradient(to right, rgba(#000,0.38) 0, rgba(#000,0.38) 33%, transparent 0) - - - &--dark &:before - background-color: $material-twelve-percent-light - - input - color: #fff - - &:disabled - color: rgba(#fff, .5) - - label - color: rgba(#fff, .50) + top: -1px + height: 1px + width: 100% + z-index: 0 - &.input-group--disabled:before - background-image: linear-gradient(to right, rgba(#fff,0.38) 0, rgba(#fff,0.38) 33%, transparent 0) +/** Themes */ +.input-group + &--light + input-group-theme($input-group-light-normal, #000, $input-group-light-focus, $material-twelve-percent-dark) + &--dark + input-group-theme($input-group-dark-normal, #fff, $input-group-dark-focus, $material-twelve-percent-light) /** Input States */ .input-group &--focused label color: $theme.primary - transform: translate3d(0, 16px, 0) scale(.75) + transform: translate3d(0, -18px, 0) scale(.75) - &:after - width: 100% + .input-group__hint + &:after + width: 100% &--dirty label - transform: translate3d(0, 16px, 0) scale(.75) + transform: translate3d(0, -18px, 0) scale(.75) - &.input-group--disabled:before + &.input-group--disabled .input-group__hint:before background-color: transparent background-position: bottom background-size: 3px 1px background-repeat: repeat-x + + +/** Types */ +.input-group + &--error + .input-group__hint:after + background-color: $theme.error + + &--icon + .icon + align-items: center + display: flex + justify-content: flex-start + flex-basis: 56px + transition: .3s $transition.fast-in-fast-out + + .input-group__hint + &:before, &:after + margin-left: 56px + max-width: calc(100% - 56px) + + label + padding-left: 56px + + input + flex: auto + + &.input-group--focused + .icon + color: $theme.primary + + &--single-line + label + transform: translate3d(0,4px,0) + + &.input-group--dirty + label + display: none + + &__wrapper + display: flex + flex-basis: 100% + min-width: 0 // .input-group diff --git a/src/stylus/settings/_variables.styl b/src/stylus/settings/_variables.styl index 7411572c568..0ef85737bc8 100755 --- a/src/stylus/settings/_variables.styl +++ b/src/stylus/settings/_variables.styl @@ -17,7 +17,7 @@ $theme := { secondary: $grey.darken-3 info: $blue.base warning: $amber.base - error: $red.base + error: $red.accent-2 success: $green.base } @@ -318,11 +318,21 @@ $sidebar-group-header-active-sidebar-item-active-background-color := rgba($theme $slider-arrow-size := 2rem /** Text Input */ -$input-group-height := 72px +$input-group-height := 58px +$input-group-margin := 18px 0 +$input-font-size := 16px $label-font-size := 12px +$input-height := 30px + +$input-group-light-normal := rgba(#000, .38) +$input-group-light-focus := rgba(#000, .87) + +$input-group-dark-normal := rgba(#fff, .5) +$input-group-dark-focus := #fff + + $label-padding-top := 16px $label-padding-bottom := 8px -$input-font-size := 16px $input-padding-bottom := 8px // Directives diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_forms.styl new file mode 100755 index 00000000000..6d9752ba893 --- /dev/null +++ b/src/stylus/tools/_forms.styl @@ -0,0 +1,34 @@ +input-group-theme(color, offset, dirty, background) + .input-group__hint:before + background-color: background + + input + color: color + + + .icon + color: color + + &:disabled + color: color + + label + color: color + + &.input-group--disabled + input + color: color !important + + .input-group__hint:before + background-image: linear-gradient(to right, rgba(offset,0.38) 0, rgba(offset,0.38) 33%, transparent 0) + + &.input-group--single-line&.input-group--focused + label + color: color + + &.input-group--icon + .icon + color: rgba(offset, .6) + + &.input-group--dirty + input + color: dirty \ No newline at end of file From 1467c878469a3adea1844096d75b9534215f6906 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 12 Feb 2017 15:01:15 -0500 Subject: [PATCH 005/172] added support for prepended and appended icons --- src/components/buttons/ButtonDropdown.vue | 6 ++++-- src/components/forms/TextInput.vue | 13 ++++++++----- src/stylus/components/_forms.styl | 4 ++-- src/stylus/tools/_forms.styl | 5 ++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/buttons/ButtonDropdown.vue b/src/components/buttons/ButtonDropdown.vue index 4b8f4ebfcc9..0f905382794 100755 --- a/src/components/buttons/ButtonDropdown.vue +++ b/src/components/buttons/ButtonDropdown.vue @@ -15,12 +15,14 @@ ref="input" v-bind:type="editable ? 'text' : 'button'" v-bind:label="label" + v-bind:light="light && !dark" + v-bind:dark="dark" v-on:click.native.stop="isActive = true" v-on:keyup.native.enter="updateValue(editableValue)" - slot="activator" v-model="editableValue" + slot="activator" single-line - menu + append-icon="arrow_drop_down" ) v-list v-list-item(v-for="(option, index) in options") diff --git a/src/components/forms/TextInput.vue b/src/components/forms/TextInput.vue index 24491ea8d0a..328d229589e 100755 --- a/src/components/forms/TextInput.vue +++ b/src/components/forms/TextInput.vue @@ -8,7 +8,7 @@ v-html="label" ) div(class="input-group__wrapper") - v-icon(v-if="icon") {{ icon }} + v-icon(v-if="prependIcon" class="input-group__prepend-icon") {{ prependIcon }} input( v-bind:disabled="disabled" v-bind:id="id" @@ -21,7 +21,7 @@ v-on:focus="focus" ref="input" ) - v-icon(v-if="menu" class="input-group__menu") arrow_drop_down + v-icon(v-if="appendIcon" class="input-group__append-icon") {{ appendIcon }} div( class="input-group__hint" v-text="error" @@ -49,12 +49,15 @@ 'input-group--dark': this.dark, 'input-group--single-line': this.singleLine, 'input-group--error': this.error, - 'input-group--icon': this.icon + 'input-group--append-icon': this.appendIcon, + 'input-group--prepend-icon': this.prependIcon } } }, props: { + appendIcon: String, + dark: Boolean, disabled: Boolean, @@ -68,8 +71,6 @@ default: true }, - icon: String, - id: String, menu: Boolean, @@ -78,6 +79,8 @@ placeholder: String, + prependIcon: String, + required: Boolean, singleLine: Boolean, diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index 9658a3d4e9f..a5c8d1ac485 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -107,8 +107,8 @@ .input-group__hint:after background-color: $theme.error - &--icon - .icon + &--prepend-icon + .input-group__prepend-icon align-items: center display: flex justify-content: flex-start diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_forms.styl index 6d9752ba893..32db3faf682 100755 --- a/src/stylus/tools/_forms.styl +++ b/src/stylus/tools/_forms.styl @@ -25,9 +25,8 @@ input-group-theme(color, offset, dirty, background) label color: color - &.input-group--icon - .icon - color: rgba(offset, .6) + .input-group__append-icon, .input-group__prepend-icon + color: rgba(offset, .6) &.input-group--dirty input From ea59f54b69e1922f4598e060ed882c822419a133 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 12 Feb 2017 16:15:22 -0500 Subject: [PATCH 006/172] removed the stopping of propagation --- src/components/buttons/ButtonDropdown.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/buttons/ButtonDropdown.vue b/src/components/buttons/ButtonDropdown.vue index 0f905382794..23c8d95d299 100755 --- a/src/components/buttons/ButtonDropdown.vue +++ b/src/components/buttons/ButtonDropdown.vue @@ -17,7 +17,7 @@ v-bind:label="label" v-bind:light="light && !dark" v-bind:dark="dark" - v-on:click.native.stop="isActive = true" + v-on:click.native="isActive = true" v-on:keyup.native.enter="updateValue(editableValue)" v-model="editableValue" slot="activator" From e891c8a449d78628b6f9892e53196a3387ee8f00 Mon Sep 17 00:00:00 2001 From: John Leider Date: Mon, 13 Feb 2017 20:03:24 -0500 Subject: [PATCH 007/172] moved textinput to render, added textarea --- src/components/forms/TextInput.js | 157 +++++++++++++++++++++++++++++ src/components/forms/TextInput.vue | 121 ---------------------- src/components/forms/index.js | 2 +- src/stylus/components/_forms.styl | 11 ++ src/stylus/tools/_forms.styl | 6 +- 5 files changed, 172 insertions(+), 125 deletions(-) create mode 100755 src/components/forms/TextInput.js delete mode 100755 src/components/forms/TextInput.vue diff --git a/src/components/forms/TextInput.js b/src/components/forms/TextInput.js new file mode 100755 index 00000000000..95884e6342d --- /dev/null +++ b/src/components/forms/TextInput.js @@ -0,0 +1,157 @@ +export default { + name: 'text-input', + + data () { + return { + focused: false, + inputValue: this.value ? this.value.toString() : null + } + }, + + computed: { + classes () { + return { + 'input-group': true, + 'input-group--focused': this.focused, + 'input-group--dirty': this.inputValue, + 'input-group--disabled': this.disabled, + 'input-group--light': this.light && !this.dark, + 'input-group--dark': this.dark, + 'input-group--single-line': this.singleLine, + 'input-group--error': this.error, + 'input-group--append-icon': this.appendIcon, + 'input-group--prepend-icon': this.prependIcon, + 'input-group--multi-line': this.multiLine + } + } + }, + + props: { + appendIcon: String, + dark: Boolean, + disabled: Boolean, + error: String, + label: String, + light: { + type: Boolean, + default: true + }, + id: String, + menu: Boolean, + multiLine: Boolean, + name: String, + placeholder: String, + prependIcon: String, + required: Boolean, + singleLine: Boolean, + type: { + default: 'text' + }, + value: { + required: false + } + }, + + watch: { + value (value) { + this.inputValue = value + }, + + inputValue () { + this.$emit('input', this.inputValue) + } + }, + + methods: { + blur () { + this.focused = false + }, + + focus () { + this.focused = true + }, + + updateValue (e) { + this.inputValue = e.target.value + } + }, + + render (h) { + const tag = this.multiLine ? 'textarea' : 'input' + const children = [] + const wrapperChildren = [] + + if (this.label) { + children.push( + h('label', { + domProps: { + for: this.id || this.name, + innerHTML: this.label + } + }) + ) + } + + const inputData = { + domProps: { + disabled: this.disabled, + id: this.id || this.name, + name: this.name, + required: this.required, + value: this.inputValue + }, + on: { + blur: this.blur, + input: this.updateValue, + focus: this.focus + } + } + + if (this.multiLine) { + inputData.domProps.rows = 5 + } else { + inputData.domProps.type = this.type + } + + wrapperChildren.push(h(tag, inputData)) + + if (this.prependIcon) { + wrapperChildren.unshift( + h('v-icon', { + 'class': { 'input-group__prepend-icon': true }, + domProps: { + innerText: this.prependIcon + } + }) + ) + } + + if (this.appendIcon) { + wrapperChildren.push( + h('v-icon', { + 'class': { 'input-group__append-icon': true }, + domProps: { + innerText: this.appendIcon + } + }) + ) + } + + children.push( + h('div', { + 'class': { 'input-group__wrapper': true } + }, wrapperChildren) + ) + + children.push( + h('div', { + 'class': { 'input-group__hint': true }, + domProps: { + innerText: this.error || '' + } + }) + ) + + return h('div', { 'class': this.classes }, children) + } +} \ No newline at end of file diff --git a/src/components/forms/TextInput.vue b/src/components/forms/TextInput.vue deleted file mode 100755 index 328d229589e..00000000000 --- a/src/components/forms/TextInput.vue +++ /dev/null @@ -1,121 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/forms/index.js b/src/components/forms/index.js index b424bae3696..35545e50a82 100755 --- a/src/components/forms/index.js +++ b/src/components/forms/index.js @@ -1,7 +1,7 @@ import Checkbox from './Checkbox.vue' import Radio from './Radio.vue' import Select from './Select.vue' -import TextInput from './TextInput.vue' +import TextInput from './TextInput' export default { Checkbox, diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index a5c8d1ac485..a8aa5c50b4b 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -16,6 +16,9 @@ transform: translate3d(0, 3px, 0) transform-origin: top left transition: .4s $transition.fast-in-fast-out + +.input-group.input-group--multi-line:not(.input-group--focused):not(.input-group--dirty) label + transform: translate3d(0,0,0) /** Input */ @@ -39,6 +42,14 @@ &:disabled pointer-events: none +/** Textarea */ +.input-group textarea + font-size: $input-font-size + width: 100% + + &:focus + outline: none + /** Hint Text */ .input-group diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_forms.styl index 32db3faf682..d70928da608 100755 --- a/src/stylus/tools/_forms.styl +++ b/src/stylus/tools/_forms.styl @@ -2,7 +2,7 @@ input-group-theme(color, offset, dirty, background) .input-group__hint:before background-color: background - input + input, textarea color: color + .icon @@ -15,7 +15,7 @@ input-group-theme(color, offset, dirty, background) color: color &.input-group--disabled - input + input, textarea color: color !important .input-group__hint:before @@ -29,5 +29,5 @@ input-group-theme(color, offset, dirty, background) color: rgba(offset, .6) &.input-group--dirty - input + input, textarea color: dirty \ No newline at end of file From eb7907db1d8172d029d540560e263ae159692241 Mon Sep 17 00:00:00 2001 From: David Graham Date: Mon, 13 Feb 2017 21:16:44 -0600 Subject: [PATCH 008/172] smarter menu resizing against edge, fixed gap, fixed misc bugs --- src/components/menus/Menu.vue | 95 +++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index bb0a09cc4c9..0cfc5a89622 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -35,7 +35,7 @@ data () { return { - autoAdjustment: 10, + window: {}, dimensions: { activator: { top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 }, content: { top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 }, @@ -48,6 +48,14 @@ props: { auto: Boolean, + autoVAdjust: { + type: Number, + default: 16 + }, + autoHAdjust: { + type: Number, + default: 9 + }, left: Boolean, bottom: Boolean, right: Boolean, @@ -80,15 +88,21 @@ computed: { direction () { - return { - 'vert': (this.bottom || this.auto) ? 'bottom' : 'top', - 'horiz': (this.right || this.auto) ? 'right' : 'left' - } + const { offsetY, offsetX, edgeDistance: edge } = this + const { content: c } = this.dimensions + let vert = (this.bottom || this.auto) ? 'bottom' : 'top' + let horiz = (this.right || this.auto) ? 'right' : 'left' + + // Flip direction, if needed, to where there's more room from the screen edge. + vert = offsetY && c.height > edge[vert] ? edge.maxVertDir : vert + horiz = offsetX && c.width > edge[horiz] ? edge.maxHorizDir : horiz + + return { vert, horiz } }, offset () { const { activator: a, content: c } = this.dimensions - const { pageYOffset: pageY, pageXOffset: pageX } = window + const { pageYOffset: pageY, pageXOffset: pageX } = this.window return { 'top': this.offsetY ? -c.height + pageY : a.height - c.height + pageY, @@ -112,12 +126,30 @@ return auto }, + edgeDistance () { + const { activator: a } = this.dimensions + const edge = {} + + edge.top = a.top + edge.bottom = this.window.innerHeight - a.bottom + edge.left = a.left + edge.right = this.window.innerWidth - a.right + edge.maxVert = edge.top > edge.bottom ? edge.top : edge.bottom + edge.maxHoriz = edge.left > edge.right ? edge.left : edge.right + edge.maxVertDir = edge.top > edge.bottom ? 'top' : 'bottom' + edge.maxHorizDir = edge.left > edge.right ? 'left' : 'right' + + return edge + }, + offscreen () { + if (this.offsetX || this.offsetY) return { vert: 0, horiz: 0 } + const { activator: a, content: c } = this.dimensions const top = a.top + this.offset[this.direction.vert] + this.autoOffset const left = a.left + this.offset[this.direction.horiz] - const { pageYOffset: pageY, pageXOffset: pageX } = window - const { innerHeight: innerH, innerWidth: innerW } = window + const { pageYOffset: pageY, pageXOffset: pageX } = this.window + const { innerHeight: innerH, innerWidth: innerW } = this.window return { 'vert': top + c.height - pageY > innerH @@ -138,8 +170,8 @@ const a = this.dimensions.activator return { - top: a.top + this.offset[vert] + this.autoOffset + this.offscreen.vert, - left: a.left + this.offset[horiz] + this.offscreen.horiz - (this.auto ? this.autoAdjustment : 0) + top: a.top + this.offset[vert] + this.autoOffset + this.offscreen.vert - (this.auto ? this.autoHAdjust : 0), + left: a.left + this.offset[horiz] + this.offscreen.horiz - (this.auto ? this.autoVAdjust : 0) } }, @@ -169,13 +201,29 @@ updateDimensions () { this.sneakPeek() - this.$refs.content.style.minWidth = `${this.$el.clientWidth + (this.auto ? this.autoAdjustment : 0)}px` - this.$refs.content.style.maxHeight = isNaN(this.maxHeight) ? this.maxHeight : `${this.maxHeight}px` + // Set minWidth & maxHeight. + const { $el, $refs, maxHeight, auto, autoVAdjust } = this + $refs.content.style.minWidth = `${$el.clientWidth + (auto ? autoVAdjust : 0)}px` + $refs.content.style.maxHeight = null + $refs.content.style.maxHeight = isNaN(maxHeight) ? maxHeight : `${maxHeight}px` + + // Let the DOM compute dimensions. + this.window = window this.dimensions = { - 'activator': this.rect(this.$refs.activator), - 'content': this.rect(this.$refs.content), - 'list': this.rect(this.$refs.content, '.list'), - 'selected': this.rect(this.$refs.content, '.list__tile--active', 'parent') + 'activator': $refs.activator.children + ? this.rect($refs.activator.children[0]) + : this.rect($refs.activator), + 'content': this.rect($refs.content), + 'list': this.rect($refs.content, '.list'), + 'selected': this.rect($refs.content, '.list__tile--active', 'parent') + } + + // If offsetY, reduce height to the max vertical distance to a screen edge. + const { edgeDistance: edge } = this + const { vert } = this.direction + if (this.offsetY && this.dimensions.content.height > edge[vert]) { + $refs.content.style.maxHeight = `${edge.maxVert}px` + this.dimensions.content.height = $refs.content.getBoundingClientRect().height } this.updateScroll() @@ -185,10 +233,15 @@ updateScroll () { if (!(this.auto && this.dimensions.selected)) return - const { content: c, selected: s } = this.dimensions + const { content: c, selected: s, list: l } = this.dimensions const scrollMiddle = (c.height - s.height) / 2 + const scrollMax = l.height - c.height + let offsetTop = s.offsetTop - scrollMiddle + + if (this.offscreen.vert && offsetTop > scrollMax) offsetTop = scrollMax + if (this.offscreen.vert && offsetTop < 0) offsetTop = 0 - this.$refs.content.scrollTop = s.offsetTop - scrollMiddle + this.offscreen.vert + this.$refs.content.scrollTop = offsetTop + this.offscreen.vert }, // Utils @@ -198,9 +251,9 @@ el = selector ? el.querySelector(selector) : el el = el && getParent ? el.parentElement : el - return el - ? Object.assign(el.getBoundingClientRect(), { 'offsetTop': el.offsetTop }) - : null + if (!el) return null + const { top, bottom, right, left, width, height } = el.getBoundingClientRect() + return { top, bottom, right, left, width, height, offsetTop: el.offsetTop } }, sneakPeek () { From 51041a8531915cc231d43cf95bebbd937ae95615 Mon Sep 17 00:00:00 2001 From: John Leider Date: Mon, 13 Feb 2017 22:26:44 -0500 Subject: [PATCH 009/172] text input tweaks --- src/components/forms/TextInput.js | 38 +++++++++++++++++++++++++++++-- src/stylus/components/_forms.styl | 25 +++++++++++++++----- src/stylus/tools/_forms.styl | 7 ++++-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/components/forms/TextInput.js b/src/components/forms/TextInput.js index 95884e6342d..ce245b47491 100755 --- a/src/components/forms/TextInput.js +++ b/src/components/forms/TextInput.js @@ -23,11 +23,16 @@ export default { 'input-group--prepend-icon': this.prependIcon, 'input-group--multi-line': this.multiLine } + }, + + count () { + return `${(this.inputValue || '').length} / ${this.max}` } }, props: { appendIcon: String, + counter: Boolean, dark: Boolean, disabled: Boolean, error: String, @@ -37,6 +42,14 @@ export default { default: true }, id: String, + min: { + type: [Number, String], + default: 0 + }, + max: { + type: [Number, String], + default: 25 + }, menu: Boolean, multiLine: Boolean, name: String, @@ -80,6 +93,7 @@ export default { const tag = this.multiLine ? 'textarea' : 'input' const children = [] const wrapperChildren = [] + const detailsChildren = [] if (this.label) { children.push( @@ -143,7 +157,7 @@ export default { }, wrapperChildren) ) - children.push( + detailsChildren.push( h('div', { 'class': { 'input-group__hint': true }, domProps: { @@ -152,6 +166,26 @@ export default { }) ) + if (this.counter) { + detailsChildren.push( + h('div', { + 'class': { + 'input-group__counter': true, + 'input-group__counter--error': (this.inputValue || '').length > this.max + }, + domProps: { + innerText: this.count + } + }) + ) + } + + children.push( + h('div', { + 'class': { 'input-group__details': true } + }, detailsChildren) + ) + return h('div', { 'class': this.classes }, children) } -} \ No newline at end of file +} diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index a8aa5c50b4b..bb946a889ba 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -51,10 +51,11 @@ outline: none -/** Hint Text */ +/** Details */ .input-group - &__hint + &__details color: $theme.error + display: flex flex: 1 0 100% font-size: 12px min-height: 16px @@ -81,6 +82,18 @@ height: 1px width: 100% z-index: 0 + +/** Hint */ +.input-group + &__hint + flex: 1 0 + + +/** Counter */ +.input-group + &__counter--error + color: inherit !important + /** Themes */ .input-group @@ -97,7 +110,7 @@ color: $theme.primary transform: translate3d(0, -18px, 0) scale(.75) - .input-group__hint + .input-group__details &:after width: 100% @@ -105,7 +118,7 @@ label transform: translate3d(0, -18px, 0) scale(.75) - &.input-group--disabled .input-group__hint:before + &.input-group--disabled .input-group__details:before background-color: transparent background-position: bottom background-size: 3px 1px @@ -115,7 +128,7 @@ /** Types */ .input-group &--error - .input-group__hint:after + .input-group__details:after background-color: $theme.error &--prepend-icon @@ -126,7 +139,7 @@ flex-basis: 56px transition: .3s $transition.fast-in-fast-out - .input-group__hint + .input-group__details &:before, &:after margin-left: 56px max-width: calc(100% - 56px) diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_forms.styl index d70928da608..1d532ff3671 100755 --- a/src/stylus/tools/_forms.styl +++ b/src/stylus/tools/_forms.styl @@ -1,5 +1,5 @@ input-group-theme(color, offset, dirty, background) - .input-group__hint:before + .input-group__details:before background-color: background input, textarea @@ -30,4 +30,7 @@ input-group-theme(color, offset, dirty, background) &.input-group--dirty input, textarea - color: dirty \ No newline at end of file + color: dirty + + .input-group__counter + color: color \ No newline at end of file From 686dd1b76c2fd19a4f768458106b1605d32adad1 Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 14 Feb 2017 09:00:19 -0500 Subject: [PATCH 010/172] tweaked button styles after menu merge --- src/components/buttons/ButtonDropdown.vue | 5 ++++- src/stylus/components/_button-dropdown.styl | 9 +++++++-- src/stylus/components/_forms.styl | 8 +++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/buttons/ButtonDropdown.vue b/src/components/buttons/ButtonDropdown.vue index 23c8d95d299..b64e66e4860 100755 --- a/src/components/buttons/ButtonDropdown.vue +++ b/src/components/buttons/ButtonDropdown.vue @@ -64,7 +64,10 @@ default: 200 }, overflow: Boolean, - label: String, + label: { + type: String, + default: 'Select' + }, segmented: Boolean, value: { required: false diff --git a/src/stylus/components/_button-dropdown.styl b/src/stylus/components/_button-dropdown.styl index 7b57493b404..065b34d2c9a 100755 --- a/src/stylus/components/_button-dropdown.styl +++ b/src/stylus/components/_button-dropdown.styl @@ -9,10 +9,12 @@ width: 100% &--overflow, &--editable, &--segmented - input - padding-left: 16px + input, label min-height: 40px + input, label + padding-left: 16px + .input-group--focused .input-group__wrapper background-color: #fff @@ -21,6 +23,9 @@ &:hover background-color: #fff + + .input-group__details:after + display: none &--light btn-dropdown-theme($material-twelve-percent-dark) diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index bb946a889ba..369d92a516d 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -9,11 +9,13 @@ /** Label */ .input-group label - display: block + display: flex + align-items: center font-size $input-font-size + height: $input-height pointer-events: none position: absolute - transform: translate3d(0, 3px, 0) + transform: translate3d(0, 0, 0) transform-origin: top left transition: .4s $transition.fast-in-fast-out @@ -156,7 +158,7 @@ &--single-line label - transform: translate3d(0,4px,0) + transform: translate3d(0,0,0) &.input-group--dirty label From bc070c9e594d11b7a7307cfe3db4f3f5db4c914c Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 14 Feb 2017 12:44:17 -0500 Subject: [PATCH 011/172] bug fix for sidebar --- src/components/lists/List.js | 12 +++++++++++- src/components/lists/ListGroup.vue | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/components/lists/List.js b/src/components/lists/List.js index abbc3c60959..766b32de312 100755 --- a/src/components/lists/List.js +++ b/src/components/lists/List.js @@ -49,8 +49,18 @@ export default { }) }, - listClick (uid) { + listClick (uid, force) { + if (force) { + return this.uid = uid + } + this.uid = this.uid === uid ? null : uid + }, + + listClose (uid) { + if (this.uid === uid) { + this.uid = null + } } }, diff --git a/src/components/lists/ListGroup.vue b/src/components/lists/ListGroup.vue index b9beb219724..e2ee5107d29 100755 --- a/src/components/lists/ListGroup.vue +++ b/src/components/lists/ListGroup.vue @@ -67,6 +67,10 @@ if (this.isActive !== this.active) { this.$emit('active', this.active) } + + if (!this.isActive) { + this.list.listClose(this._uid) + } }, '$route' (to) { From 428f51161c9f9bf1518fd21303fa92731d5cf0a2 Mon Sep 17 00:00:00 2001 From: John Leider Date: Tue, 14 Feb 2017 13:24:15 -0500 Subject: [PATCH 012/172] button dropdown tweaks --- src/components/buttons/ButtonDropdown.vue | 2 +- src/components/forms/TextInput.js | 4 ++++ src/stylus/components/_button-dropdown.styl | 13 +++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/buttons/ButtonDropdown.vue b/src/components/buttons/ButtonDropdown.vue index b64e66e4860..f738b03bb97 100755 --- a/src/components/buttons/ButtonDropdown.vue +++ b/src/components/buttons/ButtonDropdown.vue @@ -17,8 +17,8 @@ v-bind:label="label" v-bind:light="light && !dark" v-bind:dark="dark" - v-on:click.native="isActive = true" v-on:keyup.native.enter="updateValue(editableValue)" + v-on:focused="isActive = arguments[0]" v-model="editableValue" slot="activator" single-line diff --git a/src/components/forms/TextInput.js b/src/components/forms/TextInput.js index ce245b47491..395701ee281 100755 --- a/src/components/forms/TextInput.js +++ b/src/components/forms/TextInput.js @@ -72,6 +72,10 @@ export default { inputValue () { this.$emit('input', this.inputValue) + }, + + focused () { + this.$emit('focused', this.focused) } }, diff --git a/src/stylus/components/_button-dropdown.styl b/src/stylus/components/_button-dropdown.styl index 065b34d2c9a..1509850c797 100755 --- a/src/stylus/components/_button-dropdown.styl +++ b/src/stylus/components/_button-dropdown.styl @@ -17,14 +17,23 @@ .input-group--focused .input-group__wrapper background-color: #fff + @extend .z-depth-2 .input-group__wrapper transition: .3s $transition.ease-in-out &:hover background-color: #fff - - .input-group__details:after + + .input-group__details + height: 0 + min-height: 0 + padding: 0 + + &:after + display: none + + .input-group__hint display: none &--light From 8e235d746eb7c73bff7ec00bd621ac9d2bbdd437 Mon Sep 17 00:00:00 2001 From: David Graham Date: Tue, 14 Feb 2017 22:14:48 -0600 Subject: [PATCH 013/172] redo menu without need to move it to body --- src/components/menus/Menu.vue | 165 ++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 79 deletions(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 0cfc5a89622..1c2322e6cf4 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -37,25 +37,25 @@ return { window: {}, dimensions: { - activator: { top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 }, - content: { top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 }, + activator: { + cssTop: 0, cssLeft: 0, + top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 + }, + content: { + cssTop: 0, cssLeft: 0, + top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 + }, list: null, selected: null }, - minWidth: 'auto' + minWidth: 'auto', + autoNudgeX: -8, + autoNudgeY: -8 } }, props: { auto: Boolean, - autoVAdjust: { - type: Number, - default: 16 - }, - autoHAdjust: { - type: Number, - default: 9 - }, left: Boolean, bottom: Boolean, right: Boolean, @@ -88,52 +88,55 @@ computed: { direction () { - const { offsetY, offsetX, edgeDistance: edge } = this + const { edgeDistance: edge } = this const { content: c } = this.dimensions - let vert = (this.bottom || this.auto) ? 'bottom' : 'top' - let horiz = (this.right || this.auto) ? 'right' : 'left' + let vert = this.top && !this.auto ? 'top' : 'bottom' + let horiz = this.left && !this.auto ? 'left' : 'left' // Flip direction, if needed, to where there's more room from the screen edge. - vert = offsetY && c.height > edge[vert] ? edge.maxVertDir : vert - horiz = offsetX && c.width > edge[horiz] ? edge.maxHorizDir : horiz + vert = !this.auto && c.height > edge[vert] ? edge.maxVertDir : vert + horiz = !this.auto && c.width > edge[horiz] ? edge.maxHorizDir : horiz return { vert, horiz } }, offset () { const { activator: a, content: c } = this.dimensions - const { pageYOffset: pageY, pageXOffset: pageX } = this.window + const y = a.top - c.top // <-- Start with the diff between content and activator to + const x = a.left - c.left // <-- shift content to activator's position. return { - 'top': this.offsetY ? -c.height + pageY : a.height - c.height + pageY, - 'left': this.offsetX ? -c.width + pageX : a.width - c.width + pageX, - 'bottom': this.offsetY ? a.height + pageY : pageY, - 'right': this.offsetX ? a.width + pageX : pageX + 'top': this.offsetY ? y - c.height : y + a.height - c.height, + 'left': this.offsetX ? x - c.width : x + a.width - c.width, + 'bottom': this.offsetY ? y + a.height : y, + 'right': this.offsetX ? x + a.width : x } }, - autoOffset () { - if (!(this.auto && this.dimensions.selected)) return 0 + autoOffsetY () { + if (!this.auto || !this.dimensions.selected) return this.auto ? this.autoNudgeY - 8 : 0 const { activator: a, content: c, selected: s, list } = this.dimensions const offsetBottom = list.height - s.height - s.offsetTop const scrollMiddle = (c.height - s.height) / 2 + let auto = (a.height - c.height) / 2 + this.autoNudgeY - let auto = (a.height - c.height) / 2 if (s.offsetTop < scrollMiddle) auto += scrollMiddle - s.offsetTop if (offsetBottom < scrollMiddle) auto += offsetBottom - scrollMiddle return auto }, + autoOffsetX () { + return this.auto ? this.autoNudgeX : 0 + }, + edgeDistance () { const { activator: a } = this.dimensions - const edge = {} + const { innerHeight: innerH, innerWidth: innerW } = this.window + let edge = {} - edge.top = a.top - edge.bottom = this.window.innerHeight - a.bottom - edge.left = a.left - edge.right = this.window.innerWidth - a.right + edge = { top: a.top, left: a.left, bottom: innerH - a.bottom, right: innerW - a.right } edge.maxVert = edge.top > edge.bottom ? edge.top : edge.bottom edge.maxHoriz = edge.left > edge.right ? edge.left : edge.right edge.maxVertDir = edge.top > edge.bottom ? 'top' : 'bottom' @@ -143,35 +146,31 @@ }, offscreen () { - if (this.offsetX || this.offsetY) return { vert: 0, horiz: 0 } - - const { activator: a, content: c } = this.dimensions - const top = a.top + this.offset[this.direction.vert] + this.autoOffset - const left = a.left + this.offset[this.direction.horiz] - const { pageYOffset: pageY, pageXOffset: pageX } = this.window - const { innerHeight: innerH, innerWidth: innerW } = this.window + const { content: c } = this.dimensions + const top = c.top + this.offset[this.direction.vert] + this.autoOffsetY + const left = c.left + this.offset[this.direction.horiz] + this.autoOffsetX return { - 'vert': top + c.height - pageY > innerH - ? innerH - (top + c.height - pageY) - : top - pageY < 0 - ? pageY - top + 'vert': this.auto && top + c.height > this.window.innerHeight + ? this.window.innerHeight - (top + c.height) + : this.auto && top < 0 + ? -top : 0, - 'horiz': left + c.width - pageX > innerW - ? innerW - (left + c.width - pageX) - : left - pageX < 0 - ? pageX - left + 'horiz': this.auto && left + c.width > this.window.innerWidth + ? this.window.innerWidth - (left + c.width) + : this.auto && left < 0 + ? -left : 0 } }, position () { const { vert, horiz } = this.direction - const a = this.dimensions.activator + const { content: c } = this.dimensions return { - top: a.top + this.offset[vert] + this.autoOffset + this.offscreen.vert - (this.auto ? this.autoHAdjust : 0), - left: a.left + this.offset[horiz] + this.offscreen.horiz - (this.auto ? this.autoVAdjust : 0) + top: c.cssTop + this.offset[vert] + this.autoOffsetY + this.offscreen.vert, + left: c.cssLeft + this.offset[horiz] + this.autoOffsetX + this.offscreen.horiz } }, @@ -183,13 +182,9 @@ } }, - mounted () { - // Move content to beginning of the document (for more functionality). - document.body.appendChild(this.$refs.content) - }, - methods: { activate () { + console.log(this.auto) // Get measurements before transitions mess with them. this.updateDimensions() @@ -200,34 +195,41 @@ updateDimensions () { this.sneakPeek() - - // Set minWidth & maxHeight. - const { $el, $refs, maxHeight, auto, autoVAdjust } = this - $refs.content.style.minWidth = `${$el.clientWidth + (auto ? autoVAdjust : 0)}px` - $refs.content.style.maxHeight = null - $refs.content.style.maxHeight = isNaN(maxHeight) ? maxHeight : `${maxHeight}px` + this.updateMaxMin() // Let the DOM compute dimensions. this.window = window this.dimensions = { - 'activator': $refs.activator.children - ? this.rect($refs.activator.children[0]) - : this.rect($refs.activator), - 'content': this.rect($refs.content), - 'list': this.rect($refs.content, '.list'), - 'selected': this.rect($refs.content, '.list__tile--active', 'parent') + 'activator': this.$refs.activator.children + ? this.measure(this.$refs.activator.children[0]) + : this.measure(this.$refs.activator), + 'content': this.measure(this.$refs.content), + 'list': this.measure(this.$refs.content, '.list'), + 'selected': this.measure(this.$refs.content, '.list__tile--active', 'parent') } - // If offsetY, reduce height to the max vertical distance to a screen edge. - const { edgeDistance: edge } = this + this.fixOffscreen() + this.updateScroll() + this.sneakPeek(false) + }, + + updateMaxMin () { + const { $el, $refs, maxHeight, auto, autoNudgeX } = this + + $refs.content.style.minWidth = `${$el.clientWidth + Math.abs(auto ? autoNudgeX : 0)}px` + $refs.content.style.maxHeight = null // <-- TODO: This is a temporary fix. + $refs.content.style.maxHeight = isNaN(maxHeight) ? maxHeight : `${maxHeight}px` + }, + + fixOffscreen () { + const { $refs, edgeDistance: edge } = this const { vert } = this.direction - if (this.offsetY && this.dimensions.content.height > edge[vert]) { + + // If not auto, reduce height to the max vertical distance to a screen edge. + if (!this.auto && this.dimensions.content.height > edge[vert]) { $refs.content.style.maxHeight = `${edge.maxVert}px` this.dimensions.content.height = $refs.content.getBoundingClientRect().height } - - this.updateScroll() - this.sneakPeekOff() }, updateScroll () { @@ -247,23 +249,28 @@ // Utils // ==================== - rect (el, selector, getParent = false) { + measure (el, selector, getParent = false) { el = selector ? el.querySelector(selector) : el el = el && getParent ? el.parentElement : el if (!el) return null + const { top, bottom, right, left, width, height } = el.getBoundingClientRect() - return { top, bottom, right, left, width, height, offsetTop: el.offsetTop } - }, + const cssTop = parseInt(el.style.top) || 0 + const cssLeft = parseInt(el.style.left) || 0 + const offsetTop = el.offsetTop - sneakPeek () { - this.$refs.content.style.opacity = 0 - this.$refs.content.style.display = 'inline-block' + return { cssTop, cssLeft, top, bottom, right, left, width, height, offsetTop } }, - sneakPeekOff () { - this.$refs.content.style.display = 'none' - this.$refs.content.style.opacity = null + sneakPeek (on = true) { + if (on) { + this.$refs.content.style.opacity = 0 + this.$refs.content.style.display = 'inline-block' + } else { + this.$refs.content.style.display = 'none' + this.$refs.content.style.opacity = null + } } } } From 3624d4130a890455d18e0ae39e4a4ae3be53b46d Mon Sep 17 00:00:00 2001 From: David Graham Date: Tue, 14 Feb 2017 22:21:27 -0600 Subject: [PATCH 014/172] remove log --- src/components/menus/Menu.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 1c2322e6cf4..3e4671cfe1a 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -184,7 +184,6 @@ methods: { activate () { - console.log(this.auto) // Get measurements before transitions mess with them. this.updateDimensions() From 15743ba01f4e9ea6fc31657135c451c621b66c28 Mon Sep 17 00:00:00 2001 From: John Leider Date: Wed, 15 Feb 2017 18:55:09 -0500 Subject: [PATCH 015/172] added error prop --- src/components/forms/TextInput.js | 233 ++++++++++++++------ src/stylus/components/_button-dropdown.styl | 4 + src/stylus/components/_forms.styl | 37 +++- src/stylus/tools/_forms.styl | 3 + 4 files changed, 199 insertions(+), 78 deletions(-) diff --git a/src/components/forms/TextInput.js b/src/components/forms/TextInput.js index 395701ee281..0e759e9fdac 100755 --- a/src/components/forms/TextInput.js +++ b/src/components/forms/TextInput.js @@ -3,6 +3,7 @@ export default { data () { return { + error: false, focused: false, inputValue: this.value ? this.value.toString() : null } @@ -21,12 +22,20 @@ export default { 'input-group--error': this.error, 'input-group--append-icon': this.appendIcon, 'input-group--prepend-icon': this.prependIcon, - 'input-group--multi-line': this.multiLine + 'input-group--multi-line': this.multiLine, + 'input-group--required': this.required } }, count () { - return `${(this.inputValue || '').length} / ${this.max}` + let inputLength = (this.inputValue || '').length + let min = inputLength + + if (this.min !== 0 && inputLength < this.min) { + min = this.min + } + + return `${min} / ${this.max}` } }, @@ -35,8 +44,14 @@ export default { counter: Boolean, dark: Boolean, disabled: Boolean, - error: String, + errors: { + type: Array, + default: () => [] + }, + hint: String, + hintOnFocus: Boolean, label: String, + lazy: Boolean, light: { type: Boolean, default: true @@ -53,9 +68,9 @@ export default { menu: Boolean, multiLine: Boolean, name: String, - placeholder: String, prependIcon: String, required: Boolean, + rules: Array, singleLine: Boolean, type: { default: 'text' @@ -71,17 +86,24 @@ export default { }, inputValue () { - this.$emit('input', this.inputValue) + if (!this.lazy) { + this.$emit('input', this.inputValue) + } }, focused () { this.$emit('focused', this.focused) + + if (!this.focused) { + this.$emit('input', this.inputValue) + } } }, methods: { blur () { - this.focused = false + this.validate() + this.$nextTick(() => this.focused = false) }, focus () { @@ -90,69 +112,153 @@ export default { updateValue (e) { this.inputValue = e.target.value + }, + + /** Generators */ + genCounter (h) { + return h('div', { + 'class': { + 'input-group__counter': true, + 'input-group__counter--error': !this.counterIsValid() + } + }, this.count) + }, + + genHint (h) { + return h('div', { + 'class': { + 'input-group__hint': true + }, + directives: [ + { + name: 'show', + value: (!this.hintOnFocus || (this.hintOnFocus && this.focused)) && !this.errors.length + } + ], + domProps: { + innerHTML: this.hint + }, + key: 'hint' + }) + }, + + genError(h, error) { + return h( + 'div', + { + domProps: { + className: 'input-group__error' + }, + key: error + }, + error + ) + }, + + genIcon (h, type) { + return h('v-icon', { + 'class': { ['input-group__' + type + '-icon']: true }, + domProps: { + innerText: this[`${type}Icon`] + } + }) + }, + + genInput (h) { + const tag = this.multiLine ? 'textarea' : 'input' + + const inputData = { + domProps: { + disabled: this.disabled, + id: this.id || this.name || this._uid, + name: this.name, + required: this.required, + value: this.inputValue + }, + on: { + blur: this.blur, + input: this.updateValue, + focus: this.focus + } + } + + if (this.multiLine) { + inputData.domProps.rows = 5 + } else { + inputData.domProps.type = this.type + } + + return h(tag, inputData) + }, + + genLabel (h) { + return h('label', { + domProps: { + for: this.id || this.name, + innerHTML: this.label + } + }) + }, + + genMessages (h) { + const messages = [this.genHint(h)] + + this.errors.forEach(i => { + messages.push(this.genError(h, i)) + }) + + return h( + 'transition-group', + { + 'class': { + 'input-group__messages': true + }, + props: { + tag: 'div', + name: 'slide-y-transition' + } + }, + messages + ) + }, + + /** Validators */ + counterIsValid () { + return (!this.counter || + !this.inputValue || + (this.inputValue.length >= this.min && this.inputValue.length <= this.max) + ) + }, + + validateIsValid () { + return (!this.required || this.required && + (this.inputValue || '').length !== 0) + }, + + validate () { + this.error = ( + !this.validateIsValid() + ) } }, render (h) { - const tag = this.multiLine ? 'textarea' : 'input' const children = [] const wrapperChildren = [] const detailsChildren = [] if (this.label) { - children.push( - h('label', { - domProps: { - for: this.id || this.name, - innerHTML: this.label - } - }) - ) - } - - const inputData = { - domProps: { - disabled: this.disabled, - id: this.id || this.name, - name: this.name, - required: this.required, - value: this.inputValue - }, - on: { - blur: this.blur, - input: this.updateValue, - focus: this.focus - } + children.push(this.genLabel(h)) } - if (this.multiLine) { - inputData.domProps.rows = 5 - } else { - inputData.domProps.type = this.type - } - - wrapperChildren.push(h(tag, inputData)) + wrapperChildren.push(this.genInput(h)) if (this.prependIcon) { - wrapperChildren.unshift( - h('v-icon', { - 'class': { 'input-group__prepend-icon': true }, - domProps: { - innerText: this.prependIcon - } - }) - ) + wrapperChildren.unshift(this.genIcon(h, 'prepend')) } if (this.appendIcon) { - wrapperChildren.push( - h('v-icon', { - 'class': { 'input-group__append-icon': true }, - domProps: { - innerText: this.appendIcon - } - }) - ) + wrapperChildren.push(this.genIcon(h, 'append')) } children.push( @@ -161,27 +267,10 @@ export default { }, wrapperChildren) ) - detailsChildren.push( - h('div', { - 'class': { 'input-group__hint': true }, - domProps: { - innerText: this.error || '' - } - }) - ) + detailsChildren.push(this.genMessages(h)) if (this.counter) { - detailsChildren.push( - h('div', { - 'class': { - 'input-group__counter': true, - 'input-group__counter--error': (this.inputValue || '').length > this.max - }, - domProps: { - innerText: this.count - } - }) - ) + detailsChildren.push(this.genCounter(h)) } children.push( diff --git a/src/stylus/components/_button-dropdown.styl b/src/stylus/components/_button-dropdown.styl index 1509850c797..f19da892fcb 100755 --- a/src/stylus/components/_button-dropdown.styl +++ b/src/stylus/components/_button-dropdown.styl @@ -4,6 +4,10 @@ input text-align: left + + &:focus + + .icon + transform: rotate(-180deg) .menu, .menu__activator width: 100% diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_forms.styl index 8df4519dbc4..484723ca912 100755 --- a/src/stylus/components/_forms.styl +++ b/src/stylus/components/_forms.styl @@ -37,9 +37,6 @@ &:focus outline: none - + .icon - transform: rotate(-180deg) - &:disabled pointer-events: none @@ -55,7 +52,6 @@ /** Details */ .input-group &__details - color: $theme.error display: flex flex: 1 0 100% font-size: 12px @@ -88,12 +84,23 @@ .input-group &__hint flex: 1 0 + transition: .3s $transition.fast-out-fast-out +/** Error */ +.input-group + &__error + flex: 1 0 + transition: .3s $transition.fast-out-fast-out + color: $theme.error + /** Counter */ .input-group - &__counter--error - color: inherit !important + &__counter + margin-left: auto + + &--error + color: $theme.error !important /** Themes */ @@ -131,6 +138,9 @@ &--error .input-group__details:after background-color: $theme.error + + .input-group__append-icon + color: $theme.error !important &--prepend-icon .input-group__prepend-icon @@ -162,6 +172,21 @@ &.input-group--dirty label display: none + + &--required + label:after + content: '*' + + &.input-group--focused + label:after + color: $theme.error + + &--error + label + color: $theme.error + + .input-group__details:before, .input-group__details:after + background-color: $theme.error &__wrapper display: flex diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_forms.styl index 1d532ff3671..060b761e1e7 100755 --- a/src/stylus/tools/_forms.styl +++ b/src/stylus/tools/_forms.styl @@ -33,4 +33,7 @@ input-group-theme(color, offset, dirty, background) color: dirty .input-group__counter + color: color + + .input-group__details color: color \ No newline at end of file From bd93aca6d1bcb7fae46c28e144f19a5fac3b15f1 Mon Sep 17 00:00:00 2001 From: David Graham Date: Wed, 15 Feb 2017 17:56:03 -0600 Subject: [PATCH 016/172] fix default direction ternary --- src/components/menus/Menu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 3e4671cfe1a..48a84123b29 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -91,7 +91,7 @@ const { edgeDistance: edge } = this const { content: c } = this.dimensions let vert = this.top && !this.auto ? 'top' : 'bottom' - let horiz = this.left && !this.auto ? 'left' : 'left' + let horiz = this.left && !this.auto ? 'left' : 'right' // Flip direction, if needed, to where there's more room from the screen edge. vert = !this.auto && c.height > edge[vert] ? edge.maxVertDir : vert From 0de09cd021309d9d89634fe7700c1223732a2452 Mon Sep 17 00:00:00 2001 From: John Leider Date: Wed, 15 Feb 2017 20:44:06 -0500 Subject: [PATCH 017/172] tweaks --- src/components/forms/TextInput.js | 10 +++++----- src/stylus/tools/_forms.styl | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/forms/TextInput.js b/src/components/forms/TextInput.js index 0e759e9fdac..74200434775 100755 --- a/src/components/forms/TextInput.js +++ b/src/components/forms/TextInput.js @@ -19,7 +19,7 @@ export default { 'input-group--light': this.light && !this.dark, 'input-group--dark': this.dark, 'input-group--single-line': this.singleLine, - 'input-group--error': this.error, + 'input-group--error': this.error || this.errors.length > 0, 'input-group--append-icon': this.appendIcon, 'input-group--prepend-icon': this.prependIcon, 'input-group--multi-line': this.multiLine, @@ -28,7 +28,7 @@ export default { }, count () { - let inputLength = (this.inputValue || '').length + const inputLength = (this.inputValue || '').length let min = inputLength if (this.min !== 0 && inputLength < this.min) { @@ -103,7 +103,7 @@ export default { methods: { blur () { this.validate() - this.$nextTick(() => this.focused = false) + this.$nextTick(() => (this.focused = false)) }, focus () { @@ -142,7 +142,7 @@ export default { }) }, - genError(h, error) { + genError (h, error) { return h( 'div', { @@ -208,7 +208,7 @@ export default { }) return h( - 'transition-group', + 'transition-group', { 'class': { 'input-group__messages': true diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_forms.styl index 060b761e1e7..261285d6bd4 100755 --- a/src/stylus/tools/_forms.styl +++ b/src/stylus/tools/_forms.styl @@ -18,7 +18,7 @@ input-group-theme(color, offset, dirty, background) input, textarea color: color !important - .input-group__hint:before + .input-group__details:before background-image: linear-gradient(to right, rgba(offset,0.38) 0, rgba(offset,0.38) 33%, transparent 0) &.input-group--single-line&.input-group--focused From 51241197b8fa1172e520587ae813b471fa535f20 Mon Sep 17 00:00:00 2001 From: David Graham Date: Wed, 15 Feb 2017 20:00:20 -0600 Subject: [PATCH 018/172] adjust nudge and merge in dev --- src/components/menus/Menu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 48a84123b29..031894892b2 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -49,7 +49,7 @@ selected: null }, minWidth: 'auto', - autoNudgeX: -8, + autoNudgeX: -16, autoNudgeY: -8 } }, From 70b8df8aab29af69beb595a1cbd679a513767537 Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 16 Feb 2017 19:43:19 -0500 Subject: [PATCH 019/172] renamed text-input to text-field --- src/components/buttons/ButtonDropdown.vue | 2 +- src/components/forms/{TextInput.js => TextField.js} | 2 +- src/components/forms/index.js | 4 ++-- src/stylus/components/{_forms.styl => _text-fields.styl} | 0 src/stylus/main.styl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename src/components/forms/{TextInput.js => TextField.js} (99%) rename src/stylus/components/{_forms.styl => _text-fields.styl} (100%) diff --git a/src/components/buttons/ButtonDropdown.vue b/src/components/buttons/ButtonDropdown.vue index f738b03bb97..3a692bbfca6 100755 --- a/src/components/buttons/ButtonDropdown.vue +++ b/src/components/buttons/ButtonDropdown.vue @@ -11,7 +11,7 @@ v-model="isActive" bottom ) - v-text-input( + v-text-field( ref="input" v-bind:type="editable ? 'text' : 'button'" v-bind:label="label" diff --git a/src/components/forms/TextInput.js b/src/components/forms/TextField.js similarity index 99% rename from src/components/forms/TextInput.js rename to src/components/forms/TextField.js index 74200434775..43e5af14b38 100755 --- a/src/components/forms/TextInput.js +++ b/src/components/forms/TextField.js @@ -1,5 +1,5 @@ export default { - name: 'text-input', + name: 'text-field', data () { return { diff --git a/src/components/forms/index.js b/src/components/forms/index.js index 35545e50a82..50228eb0b65 100755 --- a/src/components/forms/index.js +++ b/src/components/forms/index.js @@ -1,11 +1,11 @@ import Checkbox from './Checkbox.vue' import Radio from './Radio.vue' import Select from './Select.vue' -import TextInput from './TextInput' +import TextField from './TextField' export default { Checkbox, Radio, Select, - TextInput + TextField } diff --git a/src/stylus/components/_forms.styl b/src/stylus/components/_text-fields.styl similarity index 100% rename from src/stylus/components/_forms.styl rename to src/stylus/components/_text-fields.styl diff --git a/src/stylus/main.styl b/src/stylus/main.styl index 0955af6d970..b9859df6e35 100755 --- a/src/stylus/main.styl +++ b/src/stylus/main.styl @@ -24,7 +24,6 @@ @import './components/_expansion-panel' @import './components/_icons' @import './components/_footer' -@import './components/_forms' @import './components/_lists' @import './components/_menus' @import './components/_modals' @@ -38,6 +37,7 @@ @import './components/_sidebar' @import './components/_tables' @import './components/_tabs' +@import './components/_text-fields' @import './components/_toasts' @import './components/_tooltips' @import './trumps/_app' From 792c4726951504f5ec85347c859593cf448827d1 Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 16 Feb 2017 20:05:21 -0500 Subject: [PATCH 020/172] updated mixins for new text field name --- src/stylus/tools/_mixins.styl | 2 +- src/stylus/tools/{_forms.styl => _text-fields.styl} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/stylus/tools/{_forms.styl => _text-fields.styl} (100%) diff --git a/src/stylus/tools/_mixins.styl b/src/stylus/tools/_mixins.styl index 9e5a0db8541..cb389d4c2ba 100755 --- a/src/stylus/tools/_mixins.styl +++ b/src/stylus/tools/_mixins.styl @@ -1,6 +1,6 @@ @import './_alerts' @import './_button-dropdown' @import './_colors' -@import './_forms' +@import './_text-fields' @import './_lists' @import './_progress-linear' \ No newline at end of file diff --git a/src/stylus/tools/_forms.styl b/src/stylus/tools/_text-fields.styl similarity index 100% rename from src/stylus/tools/_forms.styl rename to src/stylus/tools/_text-fields.styl From 85580bd4ff4b2e61e780e5a5e70800a531883cc6 Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 16 Feb 2017 20:08:04 -0500 Subject: [PATCH 021/172] updated to not conflict with other input types --- src/components/forms/TextField.js | 1 + src/stylus/components/_text-fields.styl | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/forms/TextField.js b/src/components/forms/TextField.js index 43e5af14b38..8ee22c0e31b 100755 --- a/src/components/forms/TextField.js +++ b/src/components/forms/TextField.js @@ -13,6 +13,7 @@ export default { classes () { return { 'input-group': true, + 'input-group--text-field': true, 'input-group--focused': this.focused, 'input-group--dirty': this.inputValue, 'input-group--disabled': this.disabled, diff --git a/src/stylus/components/_text-fields.styl b/src/stylus/components/_text-fields.styl index 484723ca912..dec1a559de8 100755 --- a/src/stylus/components/_text-fields.styl +++ b/src/stylus/components/_text-fields.styl @@ -1,5 +1,5 @@ /** Base Spec */ -.input-group +.input-group--text-field display: flex flex-wrap: wrap margin: $input-group-margin @@ -7,7 +7,7 @@ width: 100% /** Label */ -.input-group label +.input-group--text-field label display: flex align-items: center font-size $input-font-size @@ -18,12 +18,12 @@ transform-origin: top left transition: .4s $transition.fast-in-fast-out -.input-group.input-group--multi-line:not(.input-group--focused):not(.input-group--dirty) label +.input-group--text-field.input-group--multi-line:not(.input-group--focused):not(.input-group--dirty) label transform: translate3d(0,0,0) /** Input */ -.input-group input +.input-group--text-field input font-size: $input-font-size flex: 1 margin: 0 @@ -41,7 +41,7 @@ pointer-events: none /** Textarea */ -.input-group textarea +.input-group--text-field textarea font-size: $input-font-size width: 100% From ef4c5f6edb06bed934fd8fd58becf95860317291 Mon Sep 17 00:00:00 2001 From: David Graham Date: Thu, 16 Feb 2017 20:13:37 -0600 Subject: [PATCH 022/172] menu cleanup --- src/components/menus/Menu.vue | 151 ++++++++++++++++------------------ 1 file changed, 71 insertions(+), 80 deletions(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 031894892b2..a82245f8b6a 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -18,7 +18,6 @@ div( ref="content" class="menu__content" - v-on:click="isActive = false" v-show="isActive" v-bind:style="styles" ) @@ -39,37 +38,37 @@ dimensions: { activator: { cssTop: 0, cssLeft: 0, - top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 + top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, offsetTop: 0 }, content: { cssTop: 0, cssLeft: 0, - top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 + top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, offsetTop: 0 }, list: null, selected: null }, minWidth: 'auto', - autoNudgeX: -16, - autoNudgeY: -8 + nudgeX: -16, + nudgeY: -16 } }, props: { - auto: Boolean, + top: Boolean, left: Boolean, bottom: Boolean, right: Boolean, + auto: Boolean, + offsetX: Boolean, + offsetY: Boolean, maxHeight: { type: [String, Number], default: 'auto' }, - offsetX: Boolean, - offsetY: Boolean, origin: { type: String, default: 'top left' }, - top: Boolean, transition: { type: String, default: 'v-menu-transition' @@ -78,9 +77,7 @@ watch: { isActive () { - if (this.isActive) { - this.activate() - } + if (this.isActive) this.updateDimensions() this.$emit('input', this.isActive) } @@ -88,110 +85,103 @@ computed: { direction () { - const { edgeDistance: edge } = this + const { left, top, auto, screenDistance } = this const { content: c } = this.dimensions - let vert = this.top && !this.auto ? 'top' : 'bottom' - let horiz = this.left && !this.auto ? 'left' : 'right' + let horiz = left && !auto ? 'left' : 'right' + let vert = top && !auto ? 'top' : 'bottom' - // Flip direction, if needed, to where there's more room from the screen edge. - vert = !this.auto && c.height > edge[vert] ? edge.maxVertDir : vert - horiz = !this.auto && c.width > edge[horiz] ? edge.maxHorizDir : horiz + // Flip direction, if needed, to where there's more room from the window edge. + horiz = !auto && c.width > screenDistance[horiz] ? screenDistance.horizMaxDir : horiz + vert = !auto && c.height > screenDistance[vert] ? screenDistance.vertMaxDir : vert - return { vert, horiz } + return { horiz, vert } }, offset () { const { activator: a, content: c } = this.dimensions - const y = a.top - c.top // <-- Start with the diff between content and activator to - const x = a.left - c.left // <-- shift content to activator's position. + const { direction, offsetX, offsetY, offsetAuto } = this + const x = a.left - c.left // <-- Start with the diff between content and activator + const y = a.top - c.top // <-- to shift content to activator's position. return { - 'top': this.offsetY ? y - c.height : y + a.height - c.height, - 'left': this.offsetX ? x - c.width : x + a.width - c.width, - 'bottom': this.offsetY ? y + a.height : y, - 'right': this.offsetX ? x + a.width : x + horiz: direction.horiz === 'left' + ? offsetX ? x - c.width : x + a.width - c.width + offsetAuto.horiz // left + : offsetX ? x + a.width : x + offsetAuto.horiz, // right + vert: direction.vert === 'top' + ? offsetY ? y - c.height : y + a.height - c.height + offsetAuto.vert // top + : offsetY ? y + a.height : y + offsetAuto.vert // bottom } }, - autoOffsetY () { - if (!this.auto || !this.dimensions.selected) return this.auto ? this.autoNudgeY - 8 : 0 + offsetAuto () { + if (!this.auto) return { horiz: 0, vert: 0 } + if (!this.dimensions.selected) return { horiz: this.nudgeX, vert: this.nudgeY } const { activator: a, content: c, selected: s, list } = this.dimensions const offsetBottom = list.height - s.height - s.offsetTop const scrollMiddle = (c.height - s.height) / 2 - let auto = (a.height - c.height) / 2 + this.autoNudgeY + const horiz = this.nudgeX + let vert = (a.height - c.height + this.nudgeY) / 2 - if (s.offsetTop < scrollMiddle) auto += scrollMiddle - s.offsetTop - if (offsetBottom < scrollMiddle) auto += offsetBottom - scrollMiddle - - return auto - }, + vert += s.offsetTop < scrollMiddle ? scrollMiddle - s.offsetTop : 0 + vert += offsetBottom < scrollMiddle ? offsetBottom - scrollMiddle : 0 - autoOffsetX () { - return this.auto ? this.autoNudgeX : 0 + return { horiz, vert } }, - edgeDistance () { + screenDistance () { const { activator: a } = this.dimensions const { innerHeight: innerH, innerWidth: innerW } = this.window - let edge = {} + const x = this.offsetX ? a.right : a.left // <-- Determine which edge of the + const y = this.offsetY ? a.bottom : a.top // <-- activator to measure distance from. + let distance = {} - edge = { top: a.top, left: a.left, bottom: innerH - a.bottom, right: innerW - a.right } - edge.maxVert = edge.top > edge.bottom ? edge.top : edge.bottom - edge.maxHoriz = edge.left > edge.right ? edge.left : edge.right - edge.maxVertDir = edge.top > edge.bottom ? 'top' : 'bottom' - edge.maxHorizDir = edge.left > edge.right ? 'left' : 'right' + distance = { top: y, left: x, bottom: innerH - y, right: innerW - x } + distance.horizMax = distance.left > distance.right ? distance.left : distance.right + distance.horizMaxDir = distance.left > distance.right ? 'left' : 'right' + distance.vertMax = distance.top > distance.bottom ? distance.top : distance.bottom + distance.vertMaxDir = distance.top > distance.bottom ? 'top' : 'bottom' - return edge + return distance }, - offscreen () { + screenOverflow () { const { content: c } = this.dimensions - const top = c.top + this.offset[this.direction.vert] + this.autoOffsetY - const left = c.left + this.offset[this.direction.horiz] + this.autoOffsetX + const left = c.left + this.offset.horiz + const top = c.top + this.offset.vert return { - 'vert': this.auto && top + c.height > this.window.innerHeight - ? this.window.innerHeight - (top + c.height) - : this.auto && top < 0 - ? -top - : 0, 'horiz': this.auto && left + c.width > this.window.innerWidth - ? this.window.innerWidth - (left + c.width) + ? (left + c.width) - this.window.innerWidth : this.auto && left < 0 - ? -left + ? left + : 0, + 'vert': this.auto && top + c.height > this.window.innerHeight + ? (top + c.height) - this.window.innerHeight + : this.auto && top < 0 + ? top : 0 } }, position () { - const { vert, horiz } = this.direction const { content: c } = this.dimensions return { - top: c.cssTop + this.offset[vert] + this.autoOffsetY + this.offscreen.vert, - left: c.cssLeft + this.offset[horiz] + this.autoOffsetX + this.offscreen.horiz + left: c.cssLeft + this.offset.horiz - this.screenOverflow.horiz, + top: c.cssTop + this.offset.vert - this.screenOverflow.vert } }, styles () { return { - top: `${this.position.top}px`, - left: `${this.position.left}px` + left: `${this.position.left}px`, + top: `${this.position.top}px` } } }, methods: { - activate () { - // Get measurements before transitions mess with them. - this.updateDimensions() - - this.$nextTick(() => { - this.isActive = true - }) - }, - updateDimensions () { this.sneakPeek() this.updateMaxMin() @@ -213,36 +203,37 @@ }, updateMaxMin () { - const { $el, $refs, maxHeight, auto, autoNudgeX } = this + const { $el, $refs, maxHeight, auto, nudgeX } = this - $refs.content.style.minWidth = `${$el.clientWidth + Math.abs(auto ? autoNudgeX : 0)}px` + $refs.content.style.minWidth = `${$el.clientWidth + Math.abs(auto ? nudgeX : 0)}px` $refs.content.style.maxHeight = null // <-- TODO: This is a temporary fix. $refs.content.style.maxHeight = isNaN(maxHeight) ? maxHeight : `${maxHeight}px` }, fixOffscreen () { - const { $refs, edgeDistance: edge } = this + const { $refs, screenDistance } = this const { vert } = this.direction - // If not auto, reduce height to the max vertical distance to a screen edge. - if (!this.auto && this.dimensions.content.height > edge[vert]) { - $refs.content.style.maxHeight = `${edge.maxVert}px` + // If not auto, reduce height to the max vertical distance to a window edge. + if (!this.auto && this.dimensions.content.height > screenDistance[vert]) { + $refs.content.style.maxHeight = `${screenDistance.vertMax}px` this.dimensions.content.height = $refs.content.getBoundingClientRect().height } }, updateScroll () { - if (!(this.auto && this.dimensions.selected)) return + if (!this.auto || !this.dimensions.selected) return const { content: c, selected: s, list: l } = this.dimensions const scrollMiddle = (c.height - s.height) / 2 const scrollMax = l.height - c.height let offsetTop = s.offsetTop - scrollMiddle - if (this.offscreen.vert && offsetTop > scrollMax) offsetTop = scrollMax - if (this.offscreen.vert && offsetTop < 0) offsetTop = 0 + offsetTop = this.screenOverflow.vert && offsetTop > scrollMax ? scrollMax : offsetTop + offsetTop = this.screenOverflow.vert && offsetTop < 0 ? 0 : offsetTop + offsetTop -= this.screenOverflow.vert - this.$refs.content.scrollTop = offsetTop + this.offscreen.vert + this.$refs.content.scrollTop = offsetTop }, // Utils @@ -254,12 +245,12 @@ if (!el) return null - const { top, bottom, right, left, width, height } = el.getBoundingClientRect() - const cssTop = parseInt(el.style.top) || 0 + const { top, left, bottom, right, width, height } = el.getBoundingClientRect() const cssLeft = parseInt(el.style.left) || 0 + const cssTop = parseInt(el.style.top) || 0 const offsetTop = el.offsetTop - return { cssTop, cssLeft, top, bottom, right, left, width, height, offsetTop } + return { cssTop, cssLeft, top, left, bottom, right, width, height, offsetTop } }, sneakPeek (on = true) { From b231befba5c5c6083fa91e21cbc9baae09685db3 Mon Sep 17 00:00:00 2001 From: David Graham Date: Thu, 16 Feb 2017 20:24:10 -0600 Subject: [PATCH 023/172] more cleanup --- src/components/menus/Menu.vue | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index a82245f8b6a..2a831319e5f 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -103,14 +103,14 @@ const x = a.left - c.left // <-- Start with the diff between content and activator const y = a.top - c.top // <-- to shift content to activator's position. - return { - horiz: direction.horiz === 'left' + const horiz = direction.horiz === 'left' ? offsetX ? x - c.width : x + a.width - c.width + offsetAuto.horiz // left - : offsetX ? x + a.width : x + offsetAuto.horiz, // right - vert: direction.vert === 'top' + : offsetX ? x + a.width : x + offsetAuto.horiz // right + const vert = direction.vert === 'top' ? offsetY ? y - c.height : y + a.height - c.height + offsetAuto.vert // top : offsetY ? y + a.height : y + offsetAuto.vert // bottom - } + + return { horiz, vert } }, offsetAuto () { @@ -150,18 +150,18 @@ const left = c.left + this.offset.horiz const top = c.top + this.offset.vert - return { - 'horiz': this.auto && left + c.width > this.window.innerWidth + const horiz = this.auto && left + c.width > this.window.innerWidth ? (left + c.width) - this.window.innerWidth : this.auto && left < 0 ? left - : 0, - 'vert': this.auto && top + c.height > this.window.innerHeight + : 0 + const vert = this.auto && top + c.height > this.window.innerHeight ? (top + c.height) - this.window.innerHeight : this.auto && top < 0 ? top : 0 - } + + return { horiz, vert } }, position () { From 1b2dfef910f44fb451f6365b3547866571c36790 Mon Sep 17 00:00:00 2001 From: John Leider Date: Fri, 17 Feb 2017 00:00:26 -0500 Subject: [PATCH 024/172] added checkbox styles --- src/components/forms/Checkbox.js | 131 ++++++++++++++++++ src/components/forms/Checkbox.vue | 112 --------------- src/components/forms/index.js | 2 +- src/directives/ripple.js | 16 +-- .../components/_selection-controls.styl | 37 +++++ src/stylus/components/_text-fields.styl | 3 +- src/stylus/main.styl | 1 + 7 files changed, 180 insertions(+), 122 deletions(-) create mode 100755 src/components/forms/Checkbox.js delete mode 100755 src/components/forms/Checkbox.vue create mode 100755 src/stylus/components/_selection-controls.styl diff --git a/src/components/forms/Checkbox.js b/src/components/forms/Checkbox.js new file mode 100755 index 00000000000..01a7d4104d3 --- /dev/null +++ b/src/components/forms/Checkbox.js @@ -0,0 +1,131 @@ +import Contextualable from '../../mixins/contextualable' + +export default { + name: 'checkbox', + + render (h) { + const icon = h('v-icon', { + 'class': { + 'icon--checkbox': this.icon === 'check_box' + } + }, this.icon) + + const transition = h('v-fade-transition', {}, [icon]) + const ripple = h('div', { + 'class': 'input-group--selection-controls__ripple', + on: { + click: this.toggle + }, + directives: [ + { + name: 'ripple', + value: { center: true } + } + ] + }) + + const container = h('div', { + 'class': this.classes + }, [transition, ripple]) + + const label = h('label', { + on: { + click: this.toggle + } + }, this.label) + + return h('div', { + 'class': 'input-group input-group--selection-controls' + }, [container, label]) + }, + + mixins: [Contextualable], + + data () { + return { + focused: false, + inputValue: typeof this.value !== undefined ? this.value : false, + inputDeterminate: this.indeterminate + } + }, + + props: { + disabled: Boolean, + filled: Boolean, + gap: Boolean, + id: { + type: String, + default: '' + }, + indeterminate: Boolean, + label: { + type: String, + default: '' + }, + name: { + type: String, + default: '' + }, + value: { + required: false + }, + valueV: { + required: false + } + }, + + watch: { + inputValue () { + if (this.indeterminate) { + this.inputDeterminate = false + } + + const input = this.inputValue + if (Array.isArray(this.inputValue)) { + const i = this.inputValue.indexOf(this.valueV) + + if (i === -1) { + input.push(this.valueV) + } else { + input.splice(i, 1) + } + } + + this.$emit('input', input) + }, + + value () { + this.inputValue = this.value + } + }, + + computed: { + classes () { + return { + 'input-group--selection-controls__container': true, + 'primary--text': this.primary, + 'secondary--text': this.secondary, + 'error--text': this.error, + 'success--text': this.success, + 'info--text': this.info, + 'warning--text': this.warning + } + }, + + icon () { + if (this.inputDeterminate) { + return 'indeterminate_check_box' + } else if (this.inputValue) { + return 'check_box' + } else { + return 'check_box_outline_blank' + } + } + }, + + methods: { + toggle () { + this.inputValue = !this.inputValue + } + } +} diff --git a/src/components/forms/Checkbox.vue b/src/components/forms/Checkbox.vue deleted file mode 100755 index a3ebc4e6258..00000000000 --- a/src/components/forms/Checkbox.vue +++ /dev/null @@ -1,112 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/forms/index.js b/src/components/forms/index.js index 50228eb0b65..9ea1bd9938d 100755 --- a/src/components/forms/index.js +++ b/src/components/forms/index.js @@ -1,4 +1,4 @@ -import Checkbox from './Checkbox.vue' +import Checkbox from './Checkbox' import Radio from './Radio.vue' import Select from './Select.vue' import TextField from './TextField' diff --git a/src/directives/ripple.js b/src/directives/ripple.js index af09b7bfef8..82180a2bcc0 100755 --- a/src/directives/ripple.js +++ b/src/directives/ripple.js @@ -8,36 +8,36 @@ function style (el, value) { } const ripple = { - show: (e, el, binding) => { + show: (e, el, { value = {}}) => { var container = document.createElement('span') var animation = document.createElement('span') container.appendChild(animation) container.className = 'ripple__container' - if ((binding.value || {}).class) { - container.classList.add(binding.value.class) + if (value.class) { + container.classList.add(value.class) } const size = el.clientWidth > el.clientHeight ? el.clientWidth : el.clientHeight animation.className = 'ripple__animation' - animation.style.width = `${size * 2}px` + animation.style.width = `${size * (value.center ? 1 : 2)}px` animation.style.height = animation.style.width el.appendChild(container) const offset = el.getBoundingClientRect() - const x = e.clientX - offset.left - const y = e.clientY - offset.top + const x = value.center ? '50%' : `${e.clientX - offset.left}px` + const y = value.center ? '50%' : `${e.clientY - offset.top}px` animation.classList.add('ripple__animation--enter') animation.classList.add('ripple__animation--visible') - style(animation, `translate(-50%, -50%) translate(${x}px, ${y}px) scale(.001)`) + style(animation, `translate(-50%, -50%) translate(${x}, ${y}) scale3d(0.01,0.01,0.01)`) animation.dataset.activated = Date.now() setTimeout(() => { animation.classList.remove('ripple__animation--enter') - style(animation, `translate(-50%, -50%) translate(${x}px, ${y}px)`) + style(animation, `translate(-50%, -50%) translate(${x}, ${y}) scale3d(0.99,0.99,0.99)`) }, 0) }, diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl new file mode 100755 index 00000000000..7604d858a9f --- /dev/null +++ b/src/stylus/components/_selection-controls.styl @@ -0,0 +1,37 @@ +/** Input */ +.input-group.input-group--selection-controls + display: flex + align-items: center + + .icon + color: $grey.darken-1 + cursor: pointer + position: absolute + left: 0 + user-select: none + transition: .3s $transition.ease-in-out + + &--checkbox + color: inherit + +/** Label */ +.input-group--selection-controls label + cursor: pointer + padding-left: 12px + +.input-group--selection-controls__container + color: inherit + position: relative + width: 24px + height: 24px + +.input-group--selection-controls__ripple + border-radius: 50% + height: 48px + width: 48px + cursor: pointer + position: absolute + transform: translate3d(-12px, -12px, 0) + transform-origin: center center + top: 0 + left: 0 \ No newline at end of file diff --git a/src/stylus/components/_text-fields.styl b/src/stylus/components/_text-fields.styl index dec1a559de8..088d3154ea0 100755 --- a/src/stylus/components/_text-fields.styl +++ b/src/stylus/components/_text-fields.styl @@ -1,5 +1,6 @@ /** Base Spec */ -.input-group--text-field +/** TODO: Move this out */ +.input-group display: flex flex-wrap: wrap margin: $input-group-margin diff --git a/src/stylus/main.styl b/src/stylus/main.styl index b9859df6e35..d9fb89f8b59 100755 --- a/src/stylus/main.styl +++ b/src/stylus/main.styl @@ -34,6 +34,7 @@ @import './components/_progress-circular' @import './components/_progress-linear' @import './components/_ripple' +@import './components/_selection-controls' @import './components/_sidebar' @import './components/_tables' @import './components/_tabs' From 84c26a1330f1941a2b31e0c142112b890ba99eec Mon Sep 17 00:00:00 2001 From: Marius Date: Fri, 17 Feb 2017 15:31:49 +0200 Subject: [PATCH 025/172] Fix for #145 Option to disable route watcher in Sidebar component. (#146) --- src/components/sidebar/Sidebar.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/sidebar/Sidebar.js b/src/components/sidebar/Sidebar.js index c1ed4597563..ce4a3ab880f 100755 --- a/src/components/sidebar/Sidebar.js +++ b/src/components/sidebar/Sidebar.js @@ -16,7 +16,7 @@ export default { fixed: Boolean, right: Boolean, - + height: String, mobile: { @@ -27,7 +27,9 @@ export default { mobileBreakPoint: { type: Number, default: 992 - } + }, + + disableRouteWatcher: Boolean }, computed: { @@ -60,7 +62,8 @@ export default { watch: { '$route' () { - this.isActive = !this.routeChanged() + if (!this.disableRouteWatcher) + this.isActive = !this.routeChanged() } }, From c913441016d1f0e5363bb81c5f9c7e7e521b6a0a Mon Sep 17 00:00:00 2001 From: John Leider Date: Fri, 17 Feb 2017 22:26:20 -0500 Subject: [PATCH 026/172] updated selection controls --- src/components/forms/Checkbox.js | 105 +++++++-------- src/components/forms/Radio.js | 94 +++++++++++++ src/components/forms/Radio.vue | 63 --------- src/components/forms/Switch.js | 127 ++++++++++++++++++ src/components/forms/index.js | 4 +- .../components/_selection-controls.styl | 116 +++++++++++++++- src/stylus/components/_toolbar.styl | 4 + 7 files changed, 387 insertions(+), 126 deletions(-) create mode 100755 src/components/forms/Radio.js delete mode 100755 src/components/forms/Radio.vue create mode 100755 src/components/forms/Switch.js diff --git a/src/components/forms/Checkbox.js b/src/components/forms/Checkbox.js index 01a7d4104d3..e0a71b68e9f 100755 --- a/src/components/forms/Checkbox.js +++ b/src/components/forms/Checkbox.js @@ -3,69 +3,22 @@ import Contextualable from '../../mixins/contextualable' export default { name: 'checkbox', - render (h) { - const icon = h('v-icon', { - 'class': { - 'icon--checkbox': this.icon === 'check_box' - } - }, this.icon) - - const transition = h('v-fade-transition', {}, [icon]) - const ripple = h('div', { - 'class': 'input-group--selection-controls__ripple', - on: { - click: this.toggle - }, - directives: [ - { - name: 'ripple', - value: { center: true } - } - ] - }) - - const container = h('div', { - 'class': this.classes - }, [transition, ripple]) - - const label = h('label', { - on: { - click: this.toggle - } - }, this.label) - - return h('div', { - 'class': 'input-group input-group--selection-controls' - }, [container, label]) - }, - mixins: [Contextualable], data () { return { focused: false, - inputValue: typeof this.value !== undefined ? this.value : false, + inputValue: this.value, inputDeterminate: this.indeterminate } }, props: { + dark: Boolean, disabled: Boolean, - filled: Boolean, - gap: Boolean, - id: { - type: String, - default: '' - }, indeterminate: Boolean, - label: { - type: String, - default: '' - }, - name: { - type: String, - default: '' - }, + label: String, + light: Boolean, value: { required: false }, @@ -79,7 +32,6 @@ export default { if (this.indeterminate) { this.inputDeterminate = false } - const input = this.inputValue if (Array.isArray(this.inputValue)) { const i = this.inputValue.indexOf(this.valueV) @@ -93,9 +45,10 @@ export default { this.$emit('input', input) }, - value () { - this.inputValue = this.value + if (!this.disabled) { + this.inputValue = this.value + } } }, @@ -103,6 +56,10 @@ export default { classes () { return { 'input-group--selection-controls__container': true, + 'input-group--selection-controls__container--active': this.isActive, + 'input-group--selection-controls__container--light': this.light, + 'input-group--selection-controls__container--dark': this.dark, + 'input-group--selection-controls__container--disabled': this.disabled, 'primary--text': this.primary, 'secondary--text': this.secondary, 'error--text': this.error, @@ -111,7 +68,6 @@ export default { 'warning--text': this.warning } }, - icon () { if (this.inputDeterminate) { return 'indeterminate_check_box' @@ -120,12 +76,49 @@ export default { } else { return 'check_box_outline_blank' } + }, + isActive () { + return ( + (Array.isArray(this.inputValue) && + this.inputValue.indexOf(this.valueV) !== -1) || + this.inputValue + ) } }, methods: { toggle () { - this.inputValue = !this.inputValue + if (!this.disabled) { + this.inputValue = !this.inputValue + } } + }, + render (h) { + const transition = h('v-fade-transition', {}, [ + h('v-icon', { + 'class': { + 'icon--checkbox': this.icon === 'check_box' + }, + key: this.icon + }, this.icon) + ]) + + const ripple = h('div', { + 'class': 'input-group--selection-controls__ripple', + on: { click: this.toggle }, + directives: [ + { + name: 'ripple', + value: { center: true } + } + ] + }) + + return h('div', { + 'class': 'input-group input-group--selection-controls' + }, [ + h('div', { 'class': this.classes }, [transition, ripple]), + h('label', { on: { click: this.toggle }}, this.label) + ]) } } diff --git a/src/components/forms/Radio.js b/src/components/forms/Radio.js new file mode 100755 index 00000000000..f740d8a11fc --- /dev/null +++ b/src/components/forms/Radio.js @@ -0,0 +1,94 @@ +import Contextualable from '../../mixins/contextualable' + +export default { + name: 'radio', + + mixins: [Contextualable], + + data () { + return { + focused: false, + inputValue: this.value === this.valueV + } + }, + + props: { + dark: Boolean, + disabled: Boolean, + label: String, + light: Boolean, + value: { + required: false + }, + valueV: { + required: false + } + }, + + watch: { + value () { + if (!this.disabled) { + this.inputValue = this.value === this.valueV + } + } + }, + + computed: { + classes () { + return { + 'input-group--selection-controls__container': true, + 'input-group--selection-controls__container--active': this.inputValue, + 'input-group--selection-controls__container--light': this.light, + 'input-group--selection-controls__container--dark': this.dark, + 'input-group--selection-controls__container--disabled': this.disabled, + 'primary--text': this.primary, + 'secondary--text': this.secondary, + 'error--text': this.error, + 'success--text': this.success, + 'info--text': this.info, + 'warning--text': this.warning + } + }, + + icon () { + return this.inputValue ? 'radio_button_checked' : 'radio_button_unchecked' + } + }, + + methods: { + toggle () { + if (!this.disabled) { + this.$emit('input', this.valueV) + } + } + }, + + render (h) { + const transition = h('v-fade-transition', {}, [ + h('v-icon', { + 'class': { + 'icon--radio': this.inputValue + }, + key: this.icon + }, this.icon) + ]) + + const ripple = h('div', { + 'class': 'input-group--selection-controls__ripple', + on: { click: this.toggle }, + directives: [ + { + name: 'ripple', + value: { center: true } + } + ] + }) + + return h('div', { + 'class': 'input-group input-group--selection-controls' + }, [ + h('div', { 'class': this.classes }, [transition, ripple]), + h('label', { on: { click: this.toggle }}, this.label) + ]) + } +} diff --git a/src/components/forms/Radio.vue b/src/components/forms/Radio.vue deleted file mode 100755 index 4062dcd889f..00000000000 --- a/src/components/forms/Radio.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - \ No newline at end of file diff --git a/src/components/forms/Switch.js b/src/components/forms/Switch.js new file mode 100755 index 00000000000..17336937086 --- /dev/null +++ b/src/components/forms/Switch.js @@ -0,0 +1,127 @@ +import Contextualable from '../../mixins/contextualable' + +export default { + name: 'switch', + + mixins: [Contextualable], + + data () { + return { + focused: false, + inputValue: this.value + } + }, + + props: { + dark: Boolean, + disabled: Boolean, + indeterminate: Boolean, + label: String, + light: Boolean, + value: { + required: false + }, + valueV: { + required: false + } + }, + + watch: { + inputValue () { + const input = this.inputValue + if (Array.isArray(this.inputValue)) { + const i = this.inputValue.indexOf(this.valueV) + + if (i === -1) { + input.push(this.valueV) + } else { + input.splice(i, 1) + } + } + + this.$emit('input', input) + }, + + value () { + if (!this.disabled) { + this.inputValue = this.value + } + } + }, + + computed: { + classes () { + return { + 'input-group input-group--selection-controls switch': true + } + }, + rippleClasses () { + return { + 'input-group--selection-controls__ripple': true, + 'input-group--selection-controls__ripple--active': this.isActive + } + }, + containerClasses () { + return { + 'input-group--selection-controls__container': true, + 'input-group--selection-controls__container--light': this.light, + 'input-group--selection-controls__container--dark': this.dark, + 'input-group--selection-controls__container--disabled': this.disabled, + 'primary--text': this.primary, + 'secondary--text': this.secondary, + 'error--text': this.error, + 'success--text': this.success, + 'info--text': this.info, + 'warning--text': this.warning + } + }, + toggleClasses () { + return { + 'input-group--selection-controls__toggle': true, + 'input-group--selection-controls__toggle--active': this.inputValue + } + }, + isActive () { + return ( + (Array.isArray(this.inputValue) && + this.inputValue.indexOf(this.valueV) !== -1) || + this.inputValue + ) + } + }, + + methods: { + toggle () { + if (!this.disabled) { + this.inputValue = !this.inputValue + } + } + }, + + render (h) { + const ripple = h('div', { + 'class': this.rippleClasses, + on: { click: this.toggle }, + directives: [ + { + name: 'ripple', + value: { center: true } + } + ] + }) + + const container = h('div', { + 'class': this.containerClasses + }, [ + h('div', { 'class': this.toggleClasses }), + ripple + ]) + + return h('div', { + 'class': this.classes + }, [ + container, + h('label', { on: { click: this.toggle }}, this.label) + ]) + } +} diff --git a/src/components/forms/index.js b/src/components/forms/index.js index 9ea1bd9938d..4cb0b97327a 100755 --- a/src/components/forms/index.js +++ b/src/components/forms/index.js @@ -1,11 +1,13 @@ import Checkbox from './Checkbox' -import Radio from './Radio.vue' +import Radio from './Radio' import Select from './Select.vue' +import Switch from './Switch' import TextField from './TextField' export default { Checkbox, Radio, Select, + Switch, TextField } diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index 7604d858a9f..5c158c363ee 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -4,27 +4,43 @@ align-items: center .icon - color: $grey.darken-1 cursor: pointer position: absolute left: 0 user-select: none transition: .3s $transition.ease-in-out - &--checkbox - color: inherit - /** Label */ .input-group--selection-controls label cursor: pointer padding-left: 12px .input-group--selection-controls__container - color: inherit position: relative width: 24px height: 24px + &--light + .input-group--selection-controls__ripple + color: rgba(#000, .54) + + .icon + color: rgba(#000, .54) + + &.input-group--selection-controls__container--active + .input-group--selection-controls__ripple + color: inherit + + .icon + color: inherit + + &.input-group--selection-controls__container--disabled + .input-group--selection-controls__ripple + color: rgba(#000, .26) + + .icon + color: rgba(#000, .26) + .input-group--selection-controls__ripple border-radius: 50% height: 48px @@ -34,4 +50,92 @@ transform: translate3d(-12px, -12px, 0) transform-origin: center center top: 0 - left: 0 \ No newline at end of file + left: 0 + +/** Switch */ +.input-group.input-group--selection-controls + &.switch + .input-group--selection-controls__container + position: relative + + &--light + &.input-group--selection-controls__container--disabled + .input-group--selection-controls__toggle + background: rgba(#000, .12) + + .input-group--selection-controls__ripple + color: rgba(#000, .12) + + &:after + background: #bdbdbd + + .input-group--selection-controls__toggle + background: rgba(#000, .38) + + .input-group--selection-controls__ripple + color: rgba(#000, .38) + + &:after + background: #fafafa + + &--dark + &.input-group--selection-controls__container--disabled + .input-group--selection-controls__toggle + background: rgba(#fff, .10) + + .input-group--selection-controls__ripple + color: rgba(#fff, .10) + + &:after + background: #424242 + + .input-group--selection-controls__toggle + background: rgba(#fff, .30) + + .input-group--selection-controls__ripple + color: rgba(#fff, .30) + + &:after + background: #bdbdbd + + .input-group--selection-controls__toggle + color: inherit + position: absolute + height: 14px + top: 50% + left: 0 + width: 34px + border-radius: 8px + transform: translateY(-50%) + + &--active + background: currentColor !important + opacity: .5 + + .input-group--selection-controls__ripple + transform: translate3d(-15px, -12px, 0) + transition: .3s $transition.fast-in-fast-out + + &:after + content: '' + background: #fafafa + position: absolute + display: inline-block + cursor: pointer + width: 20px + border-radius: 50% + top: 50% + left: 50% + transform: translate3d(-50%, -50%, 0) + height: 20px + @extend .z-depth-1 + + &--active + color: inherit !important + transform: translate3d(2px, -12px, 0) + + &:after + background: currentColor !important + + label + padding-left: 24px \ No newline at end of file diff --git a/src/stylus/components/_toolbar.styl b/src/stylus/components/_toolbar.styl index 267cf3f338d..e020918d052 100755 --- a/src/stylus/components/_toolbar.styl +++ b/src/stylus/components/_toolbar.styl @@ -89,6 +89,10 @@ &:hover, &--active background: rgba(#000,0.1) + &--disabled + opacity: .5 + pointer-events: none + &__group position: relative background-color: inherit From c1955e1e9c56e1e69d295159c8027af3e1e7c1b2 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 18 Feb 2017 20:17:52 -0500 Subject: [PATCH 027/172] selection control tweaks --- src/components/forms/Checkbox.js | 59 +++++++++---------- src/components/forms/Switch.js | 51 +++++++--------- .../components/_selection-controls.styl | 42 ++++++++++--- 3 files changed, 83 insertions(+), 69 deletions(-) diff --git a/src/components/forms/Checkbox.js b/src/components/forms/Checkbox.js index e0a71b68e9f..a8cc32b98e9 100755 --- a/src/components/forms/Checkbox.js +++ b/src/components/forms/Checkbox.js @@ -20,38 +20,13 @@ export default { label: String, light: Boolean, value: { - required: false + required: true }, valueV: { required: false } }, - watch: { - inputValue () { - if (this.indeterminate) { - this.inputDeterminate = false - } - const input = this.inputValue - if (Array.isArray(this.inputValue)) { - const i = this.inputValue.indexOf(this.valueV) - - if (i === -1) { - input.push(this.valueV) - } else { - input.splice(i, 1) - } - } - - this.$emit('input', input) - }, - value () { - if (!this.disabled) { - this.inputValue = this.value - } - } - }, - computed: { classes () { return { @@ -71,7 +46,7 @@ export default { icon () { if (this.inputDeterminate) { return 'indeterminate_check_box' - } else if (this.inputValue) { + } else if (this.isActive) { return 'check_box' } else { return 'check_box_outline_blank' @@ -79,18 +54,38 @@ export default { }, isActive () { return ( - (Array.isArray(this.inputValue) && - this.inputValue.indexOf(this.valueV) !== -1) || - this.inputValue + (Array.isArray(this.value) && + this.value.indexOf(this.valueV) !== -1) || + (!Array.isArray(this.value) && + this.value) ) } }, methods: { toggle () { - if (!this.disabled) { - this.inputValue = !this.inputValue + if (this.disabled) { + return + } + + if (this.indeterminate) { + this.inputDeterminate = false + } + + let input = this.value + if (Array.isArray(input)) { + const i = input.indexOf(this.valueV) + + if (i === -1) { + input.push(this.valueV) + } else { + input.splice(i, 1) + } + } else { + input = !input } + + this.$emit('input', input) } }, render (h) { diff --git a/src/components/forms/Switch.js b/src/components/forms/Switch.js index 17336937086..657b8a0ec4d 100755 --- a/src/components/forms/Switch.js +++ b/src/components/forms/Switch.js @@ -26,29 +26,6 @@ export default { } }, - watch: { - inputValue () { - const input = this.inputValue - if (Array.isArray(this.inputValue)) { - const i = this.inputValue.indexOf(this.valueV) - - if (i === -1) { - input.push(this.valueV) - } else { - input.splice(i, 1) - } - } - - this.$emit('input', input) - }, - - value () { - if (!this.disabled) { - this.inputValue = this.value - } - } - }, - computed: { classes () { return { @@ -78,23 +55,39 @@ export default { toggleClasses () { return { 'input-group--selection-controls__toggle': true, - 'input-group--selection-controls__toggle--active': this.inputValue + 'input-group--selection-controls__toggle--active': this.isActive } }, isActive () { return ( - (Array.isArray(this.inputValue) && - this.inputValue.indexOf(this.valueV) !== -1) || - this.inputValue + (Array.isArray(this.value) && + this.value.indexOf(this.valueV) !== -1) || + (!Array.isArray(this.value) && + this.value) ) } }, methods: { toggle () { - if (!this.disabled) { - this.inputValue = !this.inputValue + if (this.disabled) { + return + } + + let input = this.value + if (Array.isArray(input)) { + const i = input.indexOf(this.valueV) + + if (i === -1) { + input.push(this.valueV) + } else { + input.splice(i, 1) + } + } else { + input = !input } + + this.$emit('input', input) } }, diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index 5c158c363ee..dd5ae2b09a1 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -21,6 +21,9 @@ height: 24px &--light + + label + color: #000 + .input-group--selection-controls__ripple color: rgba(#000, .54) @@ -41,6 +44,30 @@ .icon color: rgba(#000, .26) + &--dark + + label + color: #fff + + .input-group--selection-controls__ripple + color: rgba(#fff, .70) + + .icon + color: rgba(#fff, .70) + + &.input-group--selection-controls__container--active + .input-group--selection-controls__ripple + color: inherit + + .icon + color: inherit + + &.input-group--selection-controls__container--disabled + .input-group--selection-controls__ripple + color: rgba(#fff, .30) + + .icon + color: rgba(#fff, .30) + .input-group--selection-controls__ripple border-radius: 50% height: 48px @@ -61,16 +88,16 @@ &--light &.input-group--selection-controls__container--disabled .input-group--selection-controls__toggle - background: rgba(#000, .12) + background: rgba(#000, .12) !important .input-group--selection-controls__ripple - color: rgba(#000, .12) + color: rgba(#000, .12) !important &:after - background: #bdbdbd + background: #bdbdbd !important .input-group--selection-controls__toggle - background: rgba(#000, .38) + background: rgba(#000, .38) .input-group--selection-controls__ripple color: rgba(#000, .38) @@ -81,13 +108,13 @@ &--dark &.input-group--selection-controls__container--disabled .input-group--selection-controls__toggle - background: rgba(#fff, .10) + background: rgba(#fff, .10) !important .input-group--selection-controls__ripple - color: rgba(#fff, .10) + color: rgba(#fff, .10) !important &:after - background: #424242 + background: #424242 !important .input-group--selection-controls__toggle background: rgba(#fff, .30) @@ -118,7 +145,6 @@ &:after content: '' - background: #fafafa position: absolute display: inline-block cursor: pointer From 87df813e15b53fedf2783c79b70c85b2043ce93c Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 15:35:46 -0500 Subject: [PATCH 028/172] updated target for css --- src/stylus/components/_toolbar.styl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stylus/components/_toolbar.styl b/src/stylus/components/_toolbar.styl index e020918d052..328fb9750da 100755 --- a/src/stylus/components/_toolbar.styl +++ b/src/stylus/components/_toolbar.styl @@ -18,7 +18,7 @@ i font-size: 24px - .menu, .menu > div + .menu, .menu__activator height: 100% .btn:not(.toolbar__side-icon) From 31e32e85d2803b4902dba3455cb61d82ab1cd719 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 16:29:34 -0500 Subject: [PATCH 029/172] selection control tweaks --- src/components/forms/Checkbox.js | 52 +------- src/components/forms/Radio.js | 2 +- src/components/forms/Switch.js | 56 +------- src/mixins/checkbox.js | 59 +++++++++ .../components/_selection-controls.styl | 124 +++++------------- src/stylus/settings/_variables.styl | 21 +++ src/stylus/tools/_mixins.styl | 3 +- src/stylus/tools/_selection-controls.styl | 43 ++++++ 8 files changed, 168 insertions(+), 192 deletions(-) create mode 100755 src/mixins/checkbox.js create mode 100755 src/stylus/tools/_selection-controls.styl diff --git a/src/components/forms/Checkbox.js b/src/components/forms/Checkbox.js index a8cc32b98e9..201f30132db 100755 --- a/src/components/forms/Checkbox.js +++ b/src/components/forms/Checkbox.js @@ -1,30 +1,18 @@ -import Contextualable from '../../mixins/contextualable' +import Checkbox from '../../mixins/checkbox' export default { name: 'checkbox', - mixins: [Contextualable], + mixins: [Checkbox], data () { return { - focused: false, - inputValue: this.value, inputDeterminate: this.indeterminate } }, props: { - dark: Boolean, - disabled: Boolean, - indeterminate: Boolean, - label: String, - light: Boolean, - value: { - required: true - }, - valueV: { - required: false - } + indeterminate: Boolean }, computed: { @@ -51,43 +39,17 @@ export default { } else { return 'check_box_outline_blank' } - }, - isActive () { - return ( - (Array.isArray(this.value) && - this.value.indexOf(this.valueV) !== -1) || - (!Array.isArray(this.value) && - this.value) - ) } }, - methods: { - toggle () { - if (this.disabled) { - return - } - + watch: { + value () { if (this.indeterminate) { this.inputDeterminate = false } - - let input = this.value - if (Array.isArray(input)) { - const i = input.indexOf(this.valueV) - - if (i === -1) { - input.push(this.valueV) - } else { - input.splice(i, 1) - } - } else { - input = !input - } - - this.$emit('input', input) } }, + render (h) { const transition = h('v-fade-transition', {}, [ h('v-icon', { @@ -110,7 +72,7 @@ export default { }) return h('div', { - 'class': 'input-group input-group--selection-controls' + 'class': 'input-group input-group--selection-controls checkbox' }, [ h('div', { 'class': this.classes }, [transition, ripple]), h('label', { on: { click: this.toggle }}, this.label) diff --git a/src/components/forms/Radio.js b/src/components/forms/Radio.js index f740d8a11fc..a982ca36722 100755 --- a/src/components/forms/Radio.js +++ b/src/components/forms/Radio.js @@ -85,7 +85,7 @@ export default { }) return h('div', { - 'class': 'input-group input-group--selection-controls' + 'class': 'input-group input-group--selection-controls radio' }, [ h('div', { 'class': this.classes }, [transition, ripple]), h('label', { on: { click: this.toggle }}, this.label) diff --git a/src/components/forms/Switch.js b/src/components/forms/Switch.js index 657b8a0ec4d..086533becbe 100755 --- a/src/components/forms/Switch.js +++ b/src/components/forms/Switch.js @@ -1,30 +1,9 @@ -import Contextualable from '../../mixins/contextualable' +import Checkbox from '../../mixins/checkbox' export default { name: 'switch', - mixins: [Contextualable], - - data () { - return { - focused: false, - inputValue: this.value - } - }, - - props: { - dark: Boolean, - disabled: Boolean, - indeterminate: Boolean, - label: String, - light: Boolean, - value: { - required: false - }, - valueV: { - required: false - } - }, + mixins: [Checkbox], computed: { classes () { @@ -57,37 +36,6 @@ export default { 'input-group--selection-controls__toggle': true, 'input-group--selection-controls__toggle--active': this.isActive } - }, - isActive () { - return ( - (Array.isArray(this.value) && - this.value.indexOf(this.valueV) !== -1) || - (!Array.isArray(this.value) && - this.value) - ) - } - }, - - methods: { - toggle () { - if (this.disabled) { - return - } - - let input = this.value - if (Array.isArray(input)) { - const i = input.indexOf(this.valueV) - - if (i === -1) { - input.push(this.valueV) - } else { - input.splice(i, 1) - } - } else { - input = !input - } - - this.$emit('input', input) } }, diff --git a/src/mixins/checkbox.js b/src/mixins/checkbox.js new file mode 100755 index 00000000000..52f0cb30ee7 --- /dev/null +++ b/src/mixins/checkbox.js @@ -0,0 +1,59 @@ +import Contextualable from './contextualable' + +export default { + mixins: [Contextualable], + + data () { + return { + focused: false, + inputValue: this.value + } + }, + + props: { + dark: Boolean, + disabled: Boolean, + label: String, + light: Boolean, + value: { + required: false + }, + valueV: { + required: false + } + }, + + computed: { + isActive () { + return ( + (Array.isArray(this.value) && + this.value.indexOf(this.valueV) !== -1) || + (!Array.isArray(this.value) && + this.value) + ) + } + }, + + methods: { + toggle () { + if (this.disabled) { + return + } + + let input = this.value + if (Array.isArray(input)) { + const i = input.indexOf(this.valueV) + + if (i === -1) { + input.push(this.valueV) + } else { + input.splice(i, 1) + } + } else { + input = !input + } + + this.$emit('input', input) + } + } +} diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index dd5ae2b09a1..04652458558 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -9,7 +9,8 @@ left: 0 user-select: none transition: .3s $transition.ease-in-out - + + /** Label */ .input-group--selection-controls label cursor: pointer @@ -20,54 +21,6 @@ width: 24px height: 24px - &--light - + label - color: #000 - - .input-group--selection-controls__ripple - color: rgba(#000, .54) - - .icon - color: rgba(#000, .54) - - &.input-group--selection-controls__container--active - .input-group--selection-controls__ripple - color: inherit - - .icon - color: inherit - - &.input-group--selection-controls__container--disabled - .input-group--selection-controls__ripple - color: rgba(#000, .26) - - .icon - color: rgba(#000, .26) - - &--dark - + label - color: #fff - - .input-group--selection-controls__ripple - color: rgba(#fff, .70) - - .icon - color: rgba(#fff, .70) - - &.input-group--selection-controls__container--active - .input-group--selection-controls__ripple - color: inherit - - .icon - color: inherit - - &.input-group--selection-controls__container--disabled - .input-group--selection-controls__ripple - color: rgba(#fff, .30) - - .icon - color: rgba(#fff, .30) - .input-group--selection-controls__ripple border-radius: 50% height: 48px @@ -78,52 +31,13 @@ transform-origin: center center top: 0 left: 0 - + + /** Switch */ .input-group.input-group--selection-controls &.switch .input-group--selection-controls__container position: relative - - &--light - &.input-group--selection-controls__container--disabled - .input-group--selection-controls__toggle - background: rgba(#000, .12) !important - - .input-group--selection-controls__ripple - color: rgba(#000, .12) !important - - &:after - background: #bdbdbd !important - - .input-group--selection-controls__toggle - background: rgba(#000, .38) - - .input-group--selection-controls__ripple - color: rgba(#000, .38) - - &:after - background: #fafafa - - &--dark - &.input-group--selection-controls__container--disabled - .input-group--selection-controls__toggle - background: rgba(#fff, .10) !important - - .input-group--selection-controls__ripple - color: rgba(#fff, .10) !important - - &:after - background: #424242 !important - - .input-group--selection-controls__toggle - background: rgba(#fff, .30) - - .input-group--selection-controls__ripple - color: rgba(#fff, .30) - - &:after - background: #bdbdbd .input-group--selection-controls__toggle color: inherit @@ -164,4 +78,32 @@ background: currentColor !important label - padding-left: 24px \ No newline at end of file + padding-left: 24px + +/* Theme */ +.input-group--selection-controls + &.switch + .input-group--selection-controls__container + &--light + selection-controls-switch-theme($selection-switch-light-color, + $selection-switch-light-background, + $selection-switch-light-disabled-color, + $selection-switch-light-disabled-background) + &--dark + selection-controls-switch-theme($selection-switch-dark-color, + $selection-switch-dark-background, + $selection-switch-dark-disabled-color, + $selection-switch-dark-disabled-background) + + &.checkbox, &.radio + .input-group--selection-controls__container + &--light + selection-controls-checkbox-theme($selection-controls-light-color, + $selection-controls-light-label-color, + $selection-controls-light-disabled-color) + + &--dark + selection-controls-checkbox-theme($selection-controls-dark-color, + $selection-controls-dark-label-color, + $selection-controls-dark-disabled-color) + \ No newline at end of file diff --git a/src/stylus/settings/_variables.styl b/src/stylus/settings/_variables.styl index 0ef85737bc8..1d5cc27ab3e 100755 --- a/src/stylus/settings/_variables.styl +++ b/src/stylus/settings/_variables.styl @@ -291,6 +291,27 @@ $process-circular-intermediate-svg-transition := all .2s ease-in-out $progress-circular-underlay-stroke := rgba(#000, 0.1) $progress-circular-overlay-transition := all .6s ease-in-out + +/* Selection Controls */ +$selection-switch-light-color := rgba(#000, .38) +$selection-switch-light-background := #fafafa +$selection-switch-light-disabled-color := rgba(#000, .12) +$selection-switch-light-disabled-background := #bdbdbd + +$selection-switch-dark-color := rgba(#fff, .30) +$selection-switch-dark-background := #bdbdbd +$selection-switch-dark-disabled-color := rgba(#fff, .10) +$selection-switch-dark-disabled-background := #424242 + +$selection-controls-light-color := rgba(#000, .54) +$selection-controls-light-disabled-color := rgba(#000, .26) +$selection-controls-light-label-color := #000 + +$selection-controls-dark-color := rgba(#fff, .70) +$selection-controls-dark-disabled-color := rgba(#fff, .30) +$selection-controls-dark-label-color := #fff + + /* Sidebar */ $sidebar-height := 100vh diff --git a/src/stylus/tools/_mixins.styl b/src/stylus/tools/_mixins.styl index cb389d4c2ba..daf41c61c29 100755 --- a/src/stylus/tools/_mixins.styl +++ b/src/stylus/tools/_mixins.styl @@ -3,4 +3,5 @@ @import './_colors' @import './_text-fields' @import './_lists' -@import './_progress-linear' \ No newline at end of file +@import './_progress-linear' +@import './_selection-controls' \ No newline at end of file diff --git a/src/stylus/tools/_selection-controls.styl b/src/stylus/tools/_selection-controls.styl new file mode 100755 index 00000000000..3ec73d33a12 --- /dev/null +++ b/src/stylus/tools/_selection-controls.styl @@ -0,0 +1,43 @@ +selection-controls-switch-theme(color, background, disabledColor, disabledBackground) + .input-group--selection-controls__toggle + background: color + + .input-group--selection-controls__ripple + color: color + + &:after + background: background + + &.input-group--selection-controls__container--disabled + .input-group--selection-controls__toggle + background: disabledColor + + .input-group--selection-controls__ripple + color: disabledColor + + &:after + background: disabledBackground + +selection-controls-checkbox-theme(color, labelColor, disabledColor) + + label + color: labelColor + + .input-group--selection-controls__ripple + color: color + + .icon + color: color + + &.input-group--selection-controls__container--active + .input-group--selection-controls__ripple + color: inherit + + .icon + color: inherit + + &.input-group--selection-controls__container--disabled + .input-group--selection-controls__ripple + color: disabledColor + + .icon + color: disabledColor \ No newline at end of file From 422e015f11362ab5b5ba36a415311949e5af006d Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 17:05:04 -0500 Subject: [PATCH 030/172] added autocomplete prop --- src/components/forms/TextField.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/forms/TextField.js b/src/components/forms/TextField.js index 8ee22c0e31b..32b1a72baff 100755 --- a/src/components/forms/TextField.js +++ b/src/components/forms/TextField.js @@ -42,6 +42,7 @@ export default { props: { appendIcon: String, + autocomplete: Boolean, counter: Boolean, dark: Boolean, disabled: Boolean, @@ -170,6 +171,7 @@ export default { const inputData = { domProps: { + autocomplete: this.autocomplete, disabled: this.disabled, id: this.id || this.name || this._uid, name: this.name, From 366da8fbb2154aad90d57dc8d9719c20fbbf06a7 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 17:06:50 -0500 Subject: [PATCH 031/172] fix for #142 --- src/stylus/components/_buttons.styl | 2 +- src/stylus/settings/_variables.styl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stylus/components/_buttons.styl b/src/stylus/components/_buttons.styl index ebea7461b6f..3e5966ce09e 100755 --- a/src/stylus/components/_buttons.styl +++ b/src/stylus/components/_buttons.styl @@ -13,7 +13,7 @@ min-width: $button-min-width outline: 0 padding: $button-padding - text-transform: uppercase + text-transform: $button-text-transform text-decoration: none transition: $primary-transition position: relative diff --git a/src/stylus/settings/_variables.styl b/src/stylus/settings/_variables.styl index 1d5cc27ab3e..1e1965e07e0 100755 --- a/src/stylus/settings/_variables.styl +++ b/src/stylus/settings/_variables.styl @@ -170,6 +170,7 @@ $button-font-weight := 500 $button-margin := 6px $button-min-width := 88px $button-padding := 0 16px +$button-text-transform := uppercase $button-dark-overlay := rgba(#fff, 0.12) $button-dark-disabled-color := rgba(#fff, 0.3) From de278f437efc43efc15823d263b96401114af786 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 17:11:08 -0500 Subject: [PATCH 032/172] fix for #142 --- src/stylus/components/_tooltips.styl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/stylus/components/_tooltips.styl b/src/stylus/components/_tooltips.styl index 50600fce6ea..4614ac89a1b 100755 --- a/src/stylus/components/_tooltips.styl +++ b/src/stylus/components/_tooltips.styl @@ -1,7 +1,7 @@ [data-tooltip] position: relative - &:after + &:before background: $theme.secondary border-radius: .2rem color: #FFFFFF @@ -20,48 +20,48 @@ @extend .z-depth-1 &:hover - &:after + &:before opacity: 1 visibility: visible &[data-tooltip-location='bottom'] - &:after + &:before top: 100% left: 50% transform: translate(-50%, -10px) scale(0.1) transform-origin: center top &:hover - &:after + &:before transform: translate(-50%, 10px) &[data-tooltip-location='top'] - &:after + &:before top: -100% left: 50% transform: translate(-50%, 10px) scale(0.1) transform-origin: center bottom &:hover - &:after + &:before transform: translate(-50%, -10px) &[data-tooltip-location='left'] - &:after + &:before left: -100% transform: translate(10px, 0%) scale(0.1) transform-origin: center right &:hover - &:after + &:before transform: translate(-10px, 0) &[data-tooltip-location='right'] - &:after + &:before left: 100% transform: translate(-10px, 0%) scale(0.1) transform-origin: center left &:hover - &:after + &:before transform: translate(10px, 0) \ No newline at end of file From b428a12b78c7dc04ec5d3c01587fd5e47d7c9b26 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 17:13:12 -0500 Subject: [PATCH 033/172] removed max height --- src/stylus/components/_modals.styl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/stylus/components/_modals.styl b/src/stylus/components/_modals.styl index 0933d9be3cd..1524c5dd664 100755 --- a/src/stylus/components/_modals.styl +++ b/src/stylus/components/_modals.styl @@ -3,11 +3,9 @@ position: relative min-width: 280px max-width: 80% - max-height: 80% margin: auto z-index: 1001 transition: .3s ease-in-out - max-height: 55% overflow: hidden @extend .z-depth-3 From 0ef04c371bd060c7133f88a9667d4af5601add9c Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 17:29:18 -0500 Subject: [PATCH 034/172] added persistent prop for #143 --- src/components/modal/Modal.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/modal/Modal.vue b/src/components/modal/Modal.vue index e7163544f3e..b2366b25a87 100755 --- a/src/components/modal/Modal.vue +++ b/src/components/modal/Modal.vue @@ -38,12 +38,11 @@ props: { bottom: Boolean, - origin: { type: String, default: 'center center' }, - + persistent: Boolean, transition: { type: String, default: 'v-modal-transition' @@ -83,6 +82,10 @@ methods: { closeConditional (e) { + if (this.persistent) { + return false + } + return this.$refs.modal !== e.target && !this.$refs.modal.contains(e.target) && this.$refs.activator !== e.target && From 673a796d265b10e7766339574733af060301bc1d Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 18:13:41 -0500 Subject: [PATCH 035/172] updates for #141 --- src/components/lists/ListTile.js | 53 +++++---------------------- src/components/tabs/TabItem.js | 44 +++++----------------- src/components/toolbar/ToolbarItem.js | 49 ++++--------------------- src/mixins/route-link.js | 46 +++++++++++++++++++++++ 4 files changed, 72 insertions(+), 120 deletions(-) create mode 100755 src/mixins/route-link.js diff --git a/src/components/lists/ListTile.js b/src/components/lists/ListTile.js index 027d0f64318..a28bced5cb1 100755 --- a/src/components/lists/ListTile.js +++ b/src/components/lists/ListTile.js @@ -1,8 +1,11 @@ import { closestParentTag } from '../../util/helpers' +import GenerateRouteLink from '../../mixins/route-link' export default { name: 'list-tile', + mixins: [GenerateRouteLink], + data () { return { active: false @@ -10,17 +13,11 @@ export default { }, props: { - avatar: Boolean, - - disabled: Boolean, - - href: String, - - ripple: Boolean, - - router: Boolean, - - tag: String + activeClass: { + type: String, + default: 'list__tile--active' + }, + avatar: Boolean }, computed: { @@ -44,39 +41,7 @@ export default { }, render (createElement) { - let tag - - const data = { - attrs: {}, - class: this.classes, - props: {}, - directives: [ - { - name: 'ripple', - value: this.ripple || false - } - ] - } - - if (this.tag) { - tag = this.tag - } else if (this.href && this.router) { - tag = 'router-link' - data.props.to = this.href - data.props.exact = this.href === '/' - data.props.activeClass = 'list__tile--active' - - if (this.click) { - data.nativeOn = { click: this.click } - } - } else { - tag = 'a' - data.attrs.href = this.href || 'javascript:;' - - if (this.click) { - data.on = { click: this.click } - } - } + const { tag, data } = this.generateRouteLink() return createElement(tag, data, [this.$slots.default]) } diff --git a/src/components/tabs/TabItem.js b/src/components/tabs/TabItem.js index 21bcb4c8505..fdf3d6958a2 100755 --- a/src/components/tabs/TabItem.js +++ b/src/components/tabs/TabItem.js @@ -1,25 +1,23 @@ import { closestParentTag } from '../../util/helpers' +import GenerateRouteLink from '../../mixins/route-link' export default { name: 'tab-item', + mixins: [GenerateRouteLink], + data () { return { - isActive: false + isActive: false, + defaultActiveClass: 'tab__item--active' } }, props: { - disabled: Boolean, - - href: { + activeClass: { type: String, - required: true - }, - - ripple: Boolean, - - router: Boolean + default: 'tab__item--active' + } }, computed: { @@ -53,31 +51,7 @@ export default { }, render (h) { - const data = { - attrs: {}, - class: this.classes, - props: {}, - directives: [ - { - name: 'ripple', - value: this.ripple || false - } - ] - } - - let tag - - if (this.href && this.router) { - tag = 'router-link' - data.props.to = this.href - data.props.exact = this.href === '/' - data.props.activeClass = 'tab__item--active' - data.nativeOn = { click: this.click } - } else { - tag = 'a' - data.attrs.href = this.href || 'javascript:;' - data.on = { click: this.click } - } + const { tag, data } = this.generateRouteLink() const tab = h(tag, data, [this.$slots.default]) diff --git a/src/components/toolbar/ToolbarItem.js b/src/components/toolbar/ToolbarItem.js index 1544c1abcd0..9a9efecd1c9 100755 --- a/src/components/toolbar/ToolbarItem.js +++ b/src/components/toolbar/ToolbarItem.js @@ -1,18 +1,16 @@ import { closestParentTag } from '../../util/helpers' +import GenerateRouteLink from '../../mixins/route-link' export default { name: 'toolbar-item', - props: { - disabled: Boolean, - - href: String, - - ripple: Boolean, - - router: Boolean, + mixins: [GenerateRouteLink], - tag: String + props: { + activeClass: { + type: String, + default: 'toolbar__item--active' + } }, computed: { @@ -35,39 +33,8 @@ export default { }, render (h) { - let tag + const { tag, data } = this.generateRouteLink() - const data = { - attrs: {}, - class: this.classes, - props: {}, - directives: [ - { - name: 'ripple', - value: this.ripple || false - } - ] - } - - if (this.tag) { - tag = this.tag - } else if (this.href && this.router) { - tag = 'router-link' - data.props.to = this.href - data.props.exact = this.href === '/' - data.props.activeClass = 'toolbar__item--active' - - if (this.click) { - data.nativeOn = { click: this.click } - } - } else { - tag = 'a' - data.attrs.href = this.href || 'javascript:;' - - if (this.click) { - data.on = { click: this.click } - } - } const item = h(tag, data, [this.$slots.default]) return h('li', {}, [item]) diff --git a/src/mixins/route-link.js b/src/mixins/route-link.js new file mode 100755 index 00000000000..7c1b378ae39 --- /dev/null +++ b/src/mixins/route-link.js @@ -0,0 +1,46 @@ +export default { + props: { + append: Boolean, + disabled: Boolean, + href: [String, Object], + nuxt: Boolean, + replace: Boolean, + ripple: Boolean, + router: Boolean, + tag: String + }, + + methods: { + generateRouteLink () { + let tag + + const data = { + attrs: {}, + class: this.classes, + props: {}, + directives: [ + { + name: 'ripple', + value: this.ripple || false + } + ] + } + + if (this.href && this.router) { + tag = this.nuxt ? 'nuxt-link' : 'router-link' + data.props.to = this.href + data.props.exact = this.href === '/' + data.props.activeClass = this.activeClass + data.props.append = this.append + data.props.replace = this.replace + data.nativeOn = { click: this.click } + } else { + tag = this.tag || 'a' + data.attrs.href = this.href || 'javascript:;' + data.on = { click: this.click } + } + + return { tag, data } + } + } +} From ceb1235773e576bc7a2b9e904efd490ec2efcd15 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 19:04:27 -0500 Subject: [PATCH 036/172] fixed bug where e-panel was not animating close --- src/components/expansion-panel/ExpansionPanelContent.vue | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/expansion-panel/ExpansionPanelContent.vue b/src/components/expansion-panel/ExpansionPanelContent.vue index 905d2233808..22461d94a9a 100755 --- a/src/components/expansion-panel/ExpansionPanelContent.vue +++ b/src/components/expansion-panel/ExpansionPanelContent.vue @@ -85,7 +85,9 @@ }, leave (el, done) { - el.style.height = 0 + el.style.height = `${el.clientHeight}px` + + setTimeout(() => el.style.height = 0, 0) addOnceEventListener(el, 'transitionend', done) }, From 2b63d1f9ac69f80f0081a4e9f86d01285eb5efb8 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 19:05:53 -0500 Subject: [PATCH 037/172] qol change for #152 --- src/components/menus/Menu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 2a831319e5f..c23fbbd2787 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -5,7 +5,7 @@ div( class="menu__activator" - v-on:click="isActive = true" + v-on:click="isActive = !isActive" ref="activator" v-click-outside ) From 0096fd313f46032cfb33117dc50736e3c4be7cb9 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 19:50:39 -0500 Subject: [PATCH 038/172] updated labels for switch --- src/stylus/components/_selection-controls.styl | 6 ++++-- src/stylus/settings/_variables.styl | 2 ++ src/stylus/tools/_selection-controls.styl | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index 04652458558..d5667599239 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -86,12 +86,14 @@ .input-group--selection-controls__container &--light selection-controls-switch-theme($selection-switch-light-color, - $selection-switch-light-background, + $selection-switch-light-background, + $selection-switch-light-label-color, $selection-switch-light-disabled-color, $selection-switch-light-disabled-background) &--dark selection-controls-switch-theme($selection-switch-dark-color, - $selection-switch-dark-background, + $selection-switch-dark-background, + $selection-switch-dark-label-color, $selection-switch-dark-disabled-color, $selection-switch-dark-disabled-background) diff --git a/src/stylus/settings/_variables.styl b/src/stylus/settings/_variables.styl index 1e1965e07e0..02b9b90141b 100755 --- a/src/stylus/settings/_variables.styl +++ b/src/stylus/settings/_variables.styl @@ -296,11 +296,13 @@ $progress-circular-overlay-transition := all .6s ease-in-out /* Selection Controls */ $selection-switch-light-color := rgba(#000, .38) $selection-switch-light-background := #fafafa +$selection-switch-light-label-color := #424242 $selection-switch-light-disabled-color := rgba(#000, .12) $selection-switch-light-disabled-background := #bdbdbd $selection-switch-dark-color := rgba(#fff, .30) $selection-switch-dark-background := #bdbdbd +$selection-switch-dark-label-color := #fff $selection-switch-dark-disabled-color := rgba(#fff, .10) $selection-switch-dark-disabled-background := #424242 diff --git a/src/stylus/tools/_selection-controls.styl b/src/stylus/tools/_selection-controls.styl index 3ec73d33a12..3b4c42f8495 100755 --- a/src/stylus/tools/_selection-controls.styl +++ b/src/stylus/tools/_selection-controls.styl @@ -1,4 +1,7 @@ -selection-controls-switch-theme(color, background, disabledColor, disabledBackground) +selection-controls-switch-theme(color, background, labelColor, disabledColor, disabledBackground) + + label + color: labelColor + .input-group--selection-controls__toggle background: color From 4715a811b7e0d73480fb708b79f18555460b5a73 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 19 Feb 2017 20:13:41 -0500 Subject: [PATCH 039/172] renamed class --- src/components/carousel/Carousel.vue | 14 +++++++------- src/components/carousel/CarouselItem.vue | 2 +- src/stylus/components/_carousel.styl | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/carousel/Carousel.vue b/src/components/carousel/Carousel.vue index 8fb401605e3..fd962fee7a7 100755 --- a/src/components/carousel/Carousel.vue +++ b/src/components/carousel/Carousel.vue @@ -1,18 +1,18 @@ + \ No newline at end of file diff --git a/src/stylus/components/_menus.styl b/src/stylus/components/_menus.styl index 8e2e5f0f69e..de0636507b1 100755 --- a/src/stylus/components/_menus.styl +++ b/src/stylus/components/_menus.styl @@ -14,7 +14,7 @@ border-radius: 2px overflow-y: auto overflow-x: hidden - z-index: 3 + z-index: 100 @extend .z-depth-2 &-transition @@ -55,5 +55,5 @@ opacity: 1 &-enter-active, &-leave-active - transition: all .3s $transition.ease-in-out, top 1ms, left 1ms + transition: all .3s $transition.ease-in-out, top 1ms, left 1ms, bottom 1ms, right 1ms \ No newline at end of file From bdd21ca6a7359e5e76f5e2c53bfed88a62ad1d1a Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 2 Mar 2017 19:53:15 -0500 Subject: [PATCH 083/172] updated css for sidebar to work better without fixed --- src/stylus/components/_sidebar.styl | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/stylus/components/_sidebar.styl b/src/stylus/components/_sidebar.styl index 5baa292c2ad..31f906c99a5 100755 --- a/src/stylus/components/_sidebar.styl +++ b/src/stylus/components/_sidebar.styl @@ -2,7 +2,8 @@ background-color: $theme.secondary overflow-y: auto padding: 0 0 100px - transition: transform .3s cubic-bezier(0,0,.2,1) + transition: transform .3s $transition.ease-in-out, + margin .3s $transition.ease-in-out width: $sidebar-width z-index: 3 @extend .z-depth-2 @@ -30,10 +31,6 @@ &--drawer--right transform: translateX($sidebar-width + 25) - &--open - transform: translateX(0) !important - width: $sidebar-width - &--close transform: translateX(-($sidebar-width + 25)) @@ -47,6 +44,18 @@ &.sidebar--fixed-right transform: translateX($sidebar-width + 25) + &--open + transform: translateX(0) + width: $sidebar-width + + &:not(.sidebar--fixed) + @media screen and (max-width: $grid-breakpoints.lg) + margin-left: -300px + transform: none + + &.sidebar--open + transform: translateX(300px) + .list__tile color: $sidebar-item-color transition: $primary-transition From 461b5993240e1773efa0b50cf4e7ab0235baeace Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 2 Mar 2017 20:54:14 -0500 Subject: [PATCH 084/172] improved non-fixed sidebar mobile --- src/stylus/components/_sidebar.styl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/stylus/components/_sidebar.styl b/src/stylus/components/_sidebar.styl index 31f906c99a5..5ac021d3172 100755 --- a/src/stylus/components/_sidebar.styl +++ b/src/stylus/components/_sidebar.styl @@ -47,14 +47,22 @@ &--open transform: translateX(0) width: $sidebar-width - - &:not(.sidebar--fixed) + + &:not(.sidebar--fixed):not(.sidebar--right) @media screen and (max-width: $grid-breakpoints.lg) margin-left: -300px transform: none &.sidebar--open transform: translateX(300px) + + &:not(.sidebar--fixed):not(.sidebar--right) + @media screen and (max-width: $grid-breakpoints.lg) + margin-right: -300px + transform: none + + &.sidebar--open + transform: translateX(-300px) .list__tile color: $sidebar-item-color From 9a6ee5aa7732912c083bd8a05c7679816b8e1873 Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 2 Mar 2017 20:54:22 -0500 Subject: [PATCH 085/172] text-field improvements --- src/components/forms/TextField.js | 4 +--- src/mixins/input.js | 26 ++++++++++++------------ src/stylus/components/_input-groups.styl | 6 +++++- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/components/forms/TextField.js b/src/components/forms/TextField.js index 6e66ad5a8f2..046328ac134 100755 --- a/src/components/forms/TextField.js +++ b/src/components/forms/TextField.js @@ -19,13 +19,11 @@ export default { 'input-group--multi-line': this.multiLine } }, - hasError () { return this.errors.length !== 0 || !this.counterIsValid() || !this.validateIsValid() }, - count () { const inputLength = (this.inputValue || '').length let min = inputLength @@ -36,7 +34,6 @@ export default { return `${min} / ${this.max}` }, - inputValue: { get () { return this.value @@ -83,6 +80,7 @@ export default { }, value () { this.lazyValue = this.value + this.validate() } }, diff --git a/src/mixins/input.js b/src/mixins/input.js index d81323c6d63..385f2a5488a 100755 --- a/src/mixins/input.js +++ b/src/mixins/input.js @@ -59,7 +59,16 @@ export default { return h('label', {}, this.label) }, genMessages (h) { - const messages = [this.genHint(h)] + const messages = [] + + if ((this.hint && + this.focused || + this.hint && + this.persistentHint) && + this.errors.length === 0 + ) { + messages.push(this.genHint(h)) + } this.errors.forEach(i => { messages.push(this.genError(h, i)) @@ -84,13 +93,7 @@ export default { 'class': { 'input-group__hint': true }, - directives: [ - { - name: 'show', - value: (this.persistentHint || (!this.persistentHint && this.focused)) && !this.errors.length - } - ], - key: 'hint' + key: this.hint }, this.hint) }, genError (h, error) { @@ -105,11 +108,8 @@ export default { }, genIcon (h, type) { return h('v-icon', { - 'class': 'input-group__' + type + '-icon', - domProps: { - innerText: this[`${type}Icon`] - } - }) + 'class': 'input-group__' + type + '-icon' + }, this[`${type}Icon`]) }, genInputGroup (h, input, data = {}) { const children = [] diff --git a/src/stylus/components/_input-groups.styl b/src/stylus/components/_input-groups.styl index 22f2d23044e..7f62f4547bb 100755 --- a/src/stylus/components/_input-groups.styl +++ b/src/stylus/components/_input-groups.styl @@ -68,12 +68,16 @@ /** Details */ .input-group + .slide-y-transition-leave, + .slide-y-transition-leave-to + position: absolute + &__details display: flex padding-top: 4px flex: 1 0 100% font-size: 12px - min-height: 20px + min-height: 22px position: relative width: 100% From 996c2812125aa8d46c1d49d04ac5a9d5d186a2b2 Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 2 Mar 2017 22:46:15 -0500 Subject: [PATCH 086/172] select functionality tweaks --- src/components/forms/Select.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/components/forms/Select.js diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js old mode 100644 new mode 100755 index 9388221f96e..2f7727c4a82 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -19,6 +19,8 @@ export default { classes () { return { 'input-group--text-field': true, + 'input-group--select': true, + 'input-group--autocomplete': this.autocomplete, 'input-group--single-line': this.singleLine, 'input-group--multi-line': this.multiLine } @@ -32,11 +34,11 @@ export default { props: { value: { type: [Object, Array], - default: () => { return [] } + default: () => [] }, items: { type: Array, - default: () => { return [] } + default: () => [] }, itemText: { type: String, @@ -48,6 +50,7 @@ export default { }, multiple: Boolean, autocomplete: Boolean, + singleLine: Boolean, chips: Boolean, debounce: { type: Number, @@ -70,6 +73,9 @@ export default { }, methods: { + isDirty () { + return this.selected.length + }, filterItems () { const { items, searchText, itemText } = this From c22a0200f5b552c180bbee9c100f8daec44c975e Mon Sep 17 00:00:00 2001 From: John Leider Date: Thu, 2 Mar 2017 22:46:31 -0500 Subject: [PATCH 087/172] tweaks for select, added stylus file --- src/mixins/input.js | 5 ++++- src/stylus/components/_input-groups.styl | 3 --- src/stylus/components/_select.styl | 3 +++ src/stylus/components/_text-fields.styl | 3 --- src/stylus/main.styl | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) create mode 100755 src/stylus/components/_select.styl diff --git a/src/mixins/input.js b/src/mixins/input.js index 385f2a5488a..eab9f294b1f 100755 --- a/src/mixins/input.js +++ b/src/mixins/input.js @@ -38,7 +38,7 @@ export default { return Object.assign({}, { 'input-group': true, 'input-group--focused': this.focused, - 'input-group--dirty': this.inputValue, + 'input-group--dirty': this.isDirty(), 'input-group--disabled': this.disabled, 'input-group--light': this.light && !this.dark, 'input-group--dark': this.dark, @@ -55,6 +55,9 @@ export default { }, methods: { + isDirty () { + return this.inputValue + }, genLabel (h) { return h('label', {}, this.label) }, diff --git a/src/stylus/components/_input-groups.styl b/src/stylus/components/_input-groups.styl index 7f62f4547bb..c96c30681d1 100755 --- a/src/stylus/components/_input-groups.styl +++ b/src/stylus/components/_input-groups.styl @@ -54,9 +54,6 @@ .input-group__details:after background-color: $theme.error - .input-group__append-icon - color: $theme.error - &--light .input-group__details:before background-color: $material-twelve-percent-dark diff --git a/src/stylus/components/_select.styl b/src/stylus/components/_select.styl new file mode 100755 index 00000000000..c146e4bd47d --- /dev/null +++ b/src/stylus/components/_select.styl @@ -0,0 +1,3 @@ +.input-group--select + input + cursor: pointer \ No newline at end of file diff --git a/src/stylus/components/_text-fields.styl b/src/stylus/components/_text-fields.styl index d9da9fc17a5..9c2069adfe7 100755 --- a/src/stylus/components/_text-fields.styl +++ b/src/stylus/components/_text-fields.styl @@ -90,9 +90,6 @@ &.input-group--error .input-group__details:after background-color: $theme.error - - .input-group__append-icon - color: $theme.error !important &.input-group--prepend-icon .input-group__prepend-icon diff --git a/src/stylus/main.styl b/src/stylus/main.styl index 938aafdf50b..2e7f4f3eb12 100755 --- a/src/stylus/main.styl +++ b/src/stylus/main.styl @@ -35,6 +35,7 @@ @import './components/_progress-circular' @import './components/_progress-linear' @import './components/_ripple' +@import './components/_select' @import './components/_selection-controls' @import './components/_sidebar' @import './components/_sliders' From d6623988646970e990b6afc047168bc5a2bfb081 Mon Sep 17 00:00:00 2001 From: David Graham Date: Fri, 3 Mar 2017 04:07:37 -0600 Subject: [PATCH 088/172] fixed select vmodel, menu position, scopedSlots, misc --- src/components/forms/Select.js | 52 +++++------ src/components/menus/Menu.vue | 159 +++++++++++++++++++++------------ 2 files changed, 123 insertions(+), 88 deletions(-) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index 2f7727c4a82..f7fc3db78c7 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -8,9 +8,9 @@ export default { data () { return { - selected: Array.isArray(this.value || []) ? this.value : [this.value], + selected: this.multiple ? this.value : [this.value], filtered: null, - searchText: '', + searchText: this.multiple ? '' : this.value[this.itemText], menuActive: false } }, @@ -24,17 +24,13 @@ export default { 'input-group--single-line': this.singleLine, 'input-group--multi-line': this.multiLine } - }, - - single () { - return !this.multiple } }, props: { value: { type: [Object, Array], - default: () => [] + default: () => {} }, items: { type: Array, @@ -68,6 +64,7 @@ export default { }, selected (val) { + this.searchText = this.multiple ? '' : this.selected[0][this.itemText] this.$emit('input', this.multiple ? this.selected : this.selected[0]) } }, @@ -82,7 +79,6 @@ export default { this.filtered = searchText ? items.filter(item => item[itemText].includes(searchText)) : null - this.$refs.menu.updateDimensions() }, isSelected (item) { @@ -90,16 +86,8 @@ export default { }, addSelected (item) { - if (this.single) { - this.searchText = item[this.itemText] - this.selected = [item] - } - - if (this.multiple) { - this.searchText = '' - this.filtered = null - this.selected.push(item) - } + this.selected = this.multiple ? this.selected.push(item) : [item] + this.filtered = null }, removeSelected (item) { @@ -115,8 +103,10 @@ export default { props: { offsetY: this.autocomplete, auto: !this.autocomplete, - closeOnClick: this.single, - value: this.menuActive + closeOnClick: !this.multiple, + value: this.menuActive, + nudgeBottom: -20, + nudgeTop: -5 }, on: { input: (val) => { this.menuActive = val } @@ -159,14 +149,18 @@ export default { }, genSlotSelection (h, item) { - return this.$scopedSlots.selection({ item }) + return this.$scopedSlots.selection({ parent: this, item: item }) }, genChipSelection (h, item) { const data = { props: { close: true }, - on: { input: val => { if (val === false) this.removeSelected(item) } }, - nativeOn: { click: e => { e.stopPropagation() } } + on: { + input: val => { if (val === false) this.removeSelected(item) } + }, + nativeOn: { + click: e => { e.stopPropagation() } + } } return h('v-chip', data, item[this.itemText]) @@ -204,10 +198,7 @@ export default { }, genList (h) { - const list = this.$scopedSlots.item - ? (this.filtered || this.items).map(item => this.$scopedSlots.default({ item })) - : (this.filtered || this.items).map(item => this.genListItem(h, item)) - + const list = (this.filtered || this.items).map(item => this.genListItem(h, item)) return h('v-list', list) }, @@ -230,14 +221,15 @@ export default { } } - return h('v-list-tile', data, [this.genAction(h, item), this.genContent(h, item)]) + return this.$scopedSlots.item + ? h('v-list-tile', data, this.$scopedSlots.item({ parent: this, item: item })) + : h('v-list-tile', data, [this.genAction(h, item), this.genContent(h, item)]) }, genAction (h, item) { - if (this.single) return null + if (!this.multiple) return null const checkbox = h('v-checkbox', { props: { 'inputValue': this.isSelected(item) }}) - return h('v-list-tile-action', [checkbox]) }, diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index dc6b0075bcb..7e6fa6bc5d2 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -20,7 +20,6 @@ ref="content" class="menu__content" v-show="isActive" - v-bind:style="styles" v-on:click="isActive = !closeOnClick" ) slot @@ -39,19 +38,17 @@ window: {}, dimensions: { activator: { - cssTop: 0, cssLeft: 0, top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, offsetTop: 0 }, content: { - cssTop: 0, cssLeft: 0, top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, offsetTop: 0 }, list: null, selected: null }, - minWidth: 'auto', - nudgeX: -16, - nudgeY: -16 + direction: { vert: '', horiz: '' }, + position: { left: '0px', top: '0px', right: 'auto', bottom: 'auto' }, + minWidth: 'auto' } }, @@ -63,6 +60,30 @@ auto: Boolean, offsetX: Boolean, offsetY: Boolean, + nudgeXAuto: { + type: Number, + default: -16 + }, + nudgeYAuto: { + type: Number, + default: -16 + }, + nudgeTop: { + type: Number, + default: 0 + }, + nudgeLeft: { + type: Number, + default: 0 + }, + nudgeBottom: { + type: Number, + default: 0 + }, + nudgeRight: { + type: Number, + default: 0 + }, closeOnClick: { type: Boolean, default: true @@ -83,51 +104,37 @@ watch: { isActive () { - if (this.isActive) this.updateDimensions() + if (this.isActive) this.activate() this.$emit('input', this.isActive) } }, computed: { - direction () { - const { left, top, auto, screenDistance } = this - const { content: c } = this.dimensions - let horiz = left && !auto ? 'left' : 'right' - let vert = top && !auto ? 'top' : 'bottom' - - // Flip direction, if needed, to where there's more room from the window edge. - horiz = !auto && c.width > screenDistance[horiz] ? screenDistance.horizMaxDir : horiz - vert = !auto && c.height > screenDistance[vert] ? screenDistance.vertMaxDir : vert - - return { horiz, vert } - }, - offset () { const { activator: a, content: c } = this.dimensions - const { direction, offsetX, offsetY, offsetAuto } = this - const x = a.left - c.left // <-- Start with the diff between content and activator - const y = a.top - c.top // <-- to shift content to activator's position. + const { direction, offsetX, offsetY, offsetAuto: auto } = this + const { nudgeLeft: nl, nudgeTop: nt, nudgeRight: nr, nudgeBottom: nb } = this const horiz = direction.horiz === 'left' - ? offsetX ? x - c.width : x + a.width - c.width + offsetAuto.horiz // left - : offsetX ? x + a.width : x + offsetAuto.horiz // right + ? offsetX ? a.left - c.right + nl : a.right - c.right + nl + auto.horiz + : offsetX ? a.right - c.left + nr : a.left - c.left + nr + auto.horiz const vert = direction.vert === 'top' - ? offsetY ? y - c.height : y + a.height - c.height + offsetAuto.vert // top - : offsetY ? y + a.height : y + offsetAuto.vert // bottom + ? offsetY ? a.top - c.bottom + nt : a.bottom - c.bottom + nt + auto.vert + : offsetY ? a.bottom - c.top + nb : a.top - c.top + nb + auto.vert return { horiz, vert } }, offsetAuto () { if (!this.auto) return { horiz: 0, vert: 0 } - if (!this.dimensions.selected) return { horiz: this.nudgeX, vert: this.nudgeY } + if (!this.dimensions.selected) return { horiz: this.nudgeXAuto, vert: this.nudgeYAuto } const { activator: a, content: c, selected: s, list } = this.dimensions const offsetBottom = list.height - s.height - s.offsetTop const scrollMiddle = (c.height - s.height) / 2 - const horiz = this.nudgeX - let vert = (a.height - c.height + this.nudgeY) / 2 + const horiz = this.nudgeXAuto + let vert = (a.height - c.height + this.nudgeYAuto) / 2 vert += s.offsetTop < scrollMiddle ? scrollMiddle - s.offsetTop : 0 vert += offsetBottom < scrollMiddle ? offsetBottom - scrollMiddle : 0 @@ -169,39 +176,80 @@ : 0 return { horiz, vert } + } + }, + + methods: { + activate () { + this.window = window + this.setDirection() + this.updatePosition() }, - position () { + updatePosition () { + this.updateDimensions() + + const { horiz, vert } = this.direction + const { offset, screenOverflow } = this + + const left = horiz === 'left' ? 'auto' : `${offset.horiz - screenOverflow.horiz}px` + const top = vert === 'top' ? 'auto' : `${offset.vert - screenOverflow.vert}px` + const right = horiz === 'right' ? 'auto' : `${-offset.horiz - screenOverflow.horiz}px` + const bottom = vert === 'bottom' ? 'auto' : `${-offset.vert - screenOverflow.vert}px` + + this.setContentPosition({ left, top, right, bottom }) + this.flipFix() + }, + + setContentPosition (position) { + this.$refs.content.style.top = position.top + this.$refs.content.style.left = position.left + this.$refs.content.style.bottom = position.bottom + this.$refs.content.style.right = position.right + }, + + flipFix () { + const { auto, screenDistance } = this const { content: c } = this.dimensions + let { horiz, vert } = this.direction - return { - left: c.cssLeft + this.offset.horiz - this.screenOverflow.horiz, - top: c.cssTop + this.offset.vert - this.screenOverflow.vert - } + // Flip direction, if needed, to where there's more room from the window edge. + horiz = !auto && c.width > screenDistance[horiz] ? screenDistance.horizMaxDir : horiz + vert = !auto && c.height > screenDistance[vert] ? screenDistance.vertMaxDir : vert + + if (horiz === this.direction.horiz && vert === this.direction.vert) return + + this.setDirection(horiz, vert) + this.updatePosition(false) }, - styles () { - return { - left: `${this.position.left}px`, - top: `${this.position.top}px` + setDirection (horiz = '', vert = '') { + this.direction = { + horiz: horiz || (this.left && !this.auto ? 'left' : 'right'), + vert: vert || (this.top && !this.auto ? 'top' : 'bottom') } - } - }, - methods: { + // On every direction change, we must reset/reorientate position. + const top = this.direction.vert === 'top' ? 'auto' : '0px' + const left = this.direction.vert === 'left' ? 'auto' : '0px' + const bottom = this.direction.vert === 'bottom' ? 'auto' : '0px' + const right = this.direction.vert === 'right' ? 'auto' : '0px' + + this.setContentPosition({ left, top, right, bottom }) + }, + updateDimensions () { this.sneakPeek() this.updateMaxMin() + const { activator: a, content: c } = this.$refs + // Let the DOM compute dimensions. - this.window = window this.dimensions = { - 'activator': this.$refs.activator.children - ? this.measure(this.$refs.activator.children[0]) - : this.measure(this.$refs.activator), - 'content': this.measure(this.$refs.content), - 'list': this.measure(this.$refs.content, '.list'), - 'selected': this.measure(this.$refs.content, '.list__tile--active', 'parent') + 'activator': a.children ? this.measure(a.children[0]) : this.measure(a), + 'content': this.measure(c), + 'list': this.measure(c, '.list'), + 'selected': this.measure(c, '.list__tile--active', 'parent') } this.fixOffscreen() @@ -210,7 +258,7 @@ }, updateMaxMin () { - const { $el, $refs, maxHeight, auto, nudgeX } = this + const { $el, $refs, maxHeight, auto, nudgeXAuto: nudgeX } = this $refs.content.style.minWidth = `${$el.clientWidth + Math.abs(auto ? nudgeX : 0)}px` $refs.content.style.maxHeight = null // <-- TODO: This is a temporary fix. @@ -251,23 +299,18 @@ el = el && getParent ? el.parentElement : el if (!el) return null - const { top, left, bottom, right, width, height } = el.getBoundingClientRect() - const cssLeft = parseInt(el.style.left) || 0 - const cssTop = parseInt(el.style.top) || 0 - const offsetTop = el.offsetTop - - return { cssTop, cssLeft, top, left, bottom, right, width, height, offsetTop } + return { top, left, bottom, right, width, height, offsetTop: el.offsetTop } }, sneakPeek (on = true) { - const original = this.$refs.content.style.display + const originalDisplay = this.$refs.content.style.display if (on) { this.$refs.content.style.opacity = 0 this.$refs.content.style.display = 'inline-block' } else { - this.$refs.content.style.display = original + this.$refs.content.style.display = originalDisplay this.$refs.content.style.opacity = null } } From 2f4539cc0b0c63f3032a9f8fa044ae786a090f7c Mon Sep 17 00:00:00 2001 From: John Leider Date: Fri, 3 Mar 2017 16:34:30 -0500 Subject: [PATCH 089/172] added support for v-model modifiers --- src/components/forms/TextField.js | 26 +++++++++++++++++++------- src/mixins/input.js | 22 ++++++++++++++++++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/components/forms/TextField.js b/src/components/forms/TextField.js index 046328ac134..83e00a5e221 100755 --- a/src/components/forms/TextField.js +++ b/src/components/forms/TextField.js @@ -25,7 +25,7 @@ export default { !this.validateIsValid() }, count () { - const inputLength = (this.inputValue || '').length + const inputLength = (this.inputValue.toString() || '').length let min = inputLength if (this.min !== 0 && inputLength < this.min) { @@ -39,7 +39,15 @@ export default { return this.value }, set (val) { - if (!this.lazy) { + if (this.modifiers.trim) { + val = val.trim() + } + + if (this.modifiers.number) { + val = Number(val) + } + + if (!this.modifiers.lazy) { this.$emit('input', val) } @@ -75,7 +83,7 @@ export default { this.hasFocused = true if (!this.focused) { - this.$emit('input', this.lazyValue) + this.$emit('change', this.lazyValue) } }, value () { @@ -85,6 +93,9 @@ export default { }, methods: { + isDirty () { + return this.lazyValue + }, blur () { this.validate() this.$nextTick(() => (this.focused = false)) @@ -107,7 +118,7 @@ export default { id: this.id || this.name || this._uid, name: this.name, required: this.required, - value: this.inputValue + value: this.lazyValue }, on: { blur: this.blur, @@ -125,10 +136,11 @@ export default { return h(tag, inputData) }, - counterIsValid () { + counterIsValid: function counterIsValid () { + const val = this.inputValue.toString() return (!this.counter || - !this.inputValue || - (this.inputValue.length >= this.min && this.inputValue.length <= this.max) + !this.inputValue.toString() || + (val.length >= this.min && val.length <= this.max) ) }, validateIsValid () { diff --git a/src/mixins/input.js b/src/mixins/input.js index eab9f294b1f..19b4f806a91 100755 --- a/src/mixins/input.js +++ b/src/mixins/input.js @@ -14,7 +14,6 @@ export default { hint: String, persistentHint: Boolean, label: String, - lazy: Boolean, light: { type: Boolean, default: true @@ -35,7 +34,7 @@ export default { return this.errors.length !== 0 }, inputGroupClasses () { - return Object.assign({}, { + return Object.assign({ 'input-group': true, 'input-group--focused': this.focused, 'input-group--dirty': this.isDirty(), @@ -47,6 +46,25 @@ export default { 'input-group--prepend-icon': this.prependIcon, 'input-group--required': this.required }, this.classes) + }, + modifiers () { + const modifiers = { + lazy: false, + number: false, + trim: false + } + + if (!this.$vnode.data.directives) { + return modifiers + } + + const model = this.$vnode.data.directives.find(i => i.name === 'model') + + if (!model) { + return modifiers + } + + return Object.assign(modifiers, model.modifiers) } }, From abc3e663074d0891a781f7c27e748eeb16dff235 Mon Sep 17 00:00:00 2001 From: John Leider Date: Fri, 3 Mar 2017 22:09:37 -0500 Subject: [PATCH 090/172] added new options --- src/components/forms/TextField.js | 8 +++++--- src/stylus/components/_text-fields.styl | 10 ++++++++-- src/stylus/tools/_text-fields.styl | 13 ++++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/components/forms/TextField.js b/src/components/forms/TextField.js index 83e00a5e221..873aaece631 100755 --- a/src/components/forms/TextField.js +++ b/src/components/forms/TextField.js @@ -16,7 +16,8 @@ export default { return { 'input-group--text-field': true, 'input-group--single-line': this.singleLine, - 'input-group--multi-line': this.multiLine + 'input-group--multi-line': this.multiLine, + 'input-group--full-width': this.fullWidth } }, hasError () { @@ -25,7 +26,7 @@ export default { !this.validateIsValid() }, count () { - const inputLength = (this.inputValue.toString() || '').length + const inputLength = (this.inputValue && this.inputValue.toString() || '').length let min = inputLength if (this.min !== 0 && inputLength < this.min) { @@ -60,6 +61,7 @@ export default { autocomplete: Boolean, counter: Boolean, id: String, + fullWidth: Boolean, min: { type: [Number, String], default: 0 @@ -137,7 +139,7 @@ export default { return h(tag, inputData) }, counterIsValid: function counterIsValid () { - const val = this.inputValue.toString() + const val = (this.inputValue && this.inputValue.toString() || '') return (!this.counter || !this.inputValue.toString() || (val.length >= this.min && val.length <= this.max) diff --git a/src/stylus/components/_text-fields.styl b/src/stylus/components/_text-fields.styl index 9c2069adfe7..a16970c02af 100755 --- a/src/stylus/components/_text-fields.styl +++ b/src/stylus/components/_text-fields.styl @@ -86,7 +86,7 @@ /** Types */ -.input-group +.input-group--text-field &.input-group--error .input-group__details:after background-color: $theme.error @@ -135,4 +135,10 @@ color: $theme.error .input-group__details:before, .input-group__details:after - background-color: $theme.error \ No newline at end of file + background-color: $theme.error + + &.input-group--full-width + padding: 0 16px + + .input-group__details:before, .input-group__details:after + display: none \ No newline at end of file diff --git a/src/stylus/tools/_text-fields.styl b/src/stylus/tools/_text-fields.styl index 14e01b18ebd..11f1be4bdfc 100755 --- a/src/stylus/tools/_text-fields.styl +++ b/src/stylus/tools/_text-fields.styl @@ -10,10 +10,6 @@ input-group-theme(color, offset, dirty) label color: color - - &.input-group--disabled - input, textarea - color: color !important &.input-group--single-line&.input-group--focused label @@ -30,4 +26,11 @@ input-group-theme(color, offset, dirty) color: color .input-group__details - color: color \ No newline at end of file + color: color + + &.input-group--disabled + input, textarea + color: color + + .input-group__details:before + background-color: transparent \ No newline at end of file From 9352192653de3f1de72420d3ea5806723a8b7bc6 Mon Sep 17 00:00:00 2001 From: John Leider Date: Fri, 3 Mar 2017 22:09:43 -0500 Subject: [PATCH 091/172] updated styles --- src/stylus/components/_buttons.styl | 4 +--- src/stylus/components/_chips.styl | 1 + src/stylus/components/_toolbar.styl | 7 +++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/stylus/components/_buttons.styl b/src/stylus/components/_buttons.styl index 3e5966ce09e..7a1a48a2d37 100755 --- a/src/stylus/components/_buttons.styl +++ b/src/stylus/components/_buttons.styl @@ -22,9 +22,6 @@ /** Psuedo */ .btn - &:hover:after - background: $button-dark-overlay - &:after bottom: 0 content: '' @@ -100,6 +97,7 @@ &:after border-radius: 50% + opacity: .12 &:hover border-radius: 50% diff --git a/src/stylus/components/_chips.styl b/src/stylus/components/_chips.styl index 148670a7597..70a775ca4fc 100755 --- a/src/stylus/components/_chips.styl +++ b/src/stylus/components/_chips.styl @@ -8,6 +8,7 @@ justify-content: space-between font-size: $chip-font-size padding: $chip-padding + margin: 8px height: $chip-height transition: .3s $transition.ease-in-out vertical-align: middle diff --git a/src/stylus/components/_toolbar.styl b/src/stylus/components/_toolbar.styl index e645ef447fd..b09047eb0cf 100755 --- a/src/stylus/components/_toolbar.styl +++ b/src/stylus/components/_toolbar.styl @@ -25,7 +25,7 @@ margin: 0 6px &:first-child - margin-left: 0 + margin-left: -6px &:last-child margin-right: 0 @@ -59,7 +59,10 @@ color: #fff font-size: $headings.h6.size flex: 1; - padding: 0 2rem + padding: 0 16px + + &:first-child + padding-left: 2px &__items list-style-type: none From 30f10afbaf0a27b5f9f7483e6261a02debae3510 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 21:52:43 -0500 Subject: [PATCH 092/172] Feature/snackbar (#179) * adding snackbars * positioning classes * Single slot for text and action button * add toggle able mixing and 'timeout' prop * Add 'timeout' option and resizing hack * added better comparisons for non array model with value * added new transition for bottom * added new transition * updated styles for label * improved block styles * updated snackbars --- src/components/_index.js | 4 +- src/components/modal/Modal.vue | 2 +- src/components/snackbars/Snackbar.js | 57 ++++++++++++++++++++++ src/components/snackbars/index.js | 5 ++ src/components/transitions/_index.js | 2 + src/index.js | 4 +- src/mixins/checkbox.js | 8 +++- src/stylus/components/_buttons.styl | 1 + src/stylus/components/_sliders.styl | 10 ++-- src/stylus/components/_snackbars.styl | 69 +++++++++++++++++++++++++++ src/stylus/generic/_transitions.styl | 8 ++++ src/stylus/main.styl | 3 +- src/stylus/settings/_variables.styl | 23 +++++---- 13 files changed, 175 insertions(+), 21 deletions(-) create mode 100755 src/components/snackbars/Snackbar.js create mode 100755 src/components/snackbars/index.js create mode 100755 src/stylus/components/_snackbars.styl diff --git a/src/components/_index.js b/src/components/_index.js index ace727f9156..3e9b61264ed 100755 --- a/src/components/_index.js +++ b/src/components/_index.js @@ -25,6 +25,7 @@ import Subheader from './subheaders/index' import Tables from './tables/index' import Tabs from './tabs/index' import Transitions from './transitions/_index' +import Snackbar from './snackbars/index' export default Object.assign({}, Alerts, @@ -53,5 +54,6 @@ export default Object.assign({}, Subheader, Tables, Tabs, - Transitions + Transitions, + Snackbar ) diff --git a/src/components/modal/Modal.vue b/src/components/modal/Modal.vue index beeb8c41fe4..5aa7593cdde 100755 --- a/src/components/modal/Modal.vue +++ b/src/components/modal/Modal.vue @@ -70,7 +70,7 @@ return this.transition } - return this.bottom ? 'v-slide-y-transition' : this.transition + return this.bottom ? 'v-slide-y-reverse-transition' : this.transition }, overlayClasses () { diff --git a/src/components/snackbars/Snackbar.js b/src/components/snackbars/Snackbar.js new file mode 100755 index 00000000000..e318d55cd2f --- /dev/null +++ b/src/components/snackbars/Snackbar.js @@ -0,0 +1,57 @@ +import Toggleable from '../../mixins/toggleable' + +export default { + name: 'snackbar', + + mixins: [Toggleable], + + props: { + bottom: Boolean, + left: Boolean, + multiLine: Boolean, + right: Boolean, + top: Boolean, + timeout: { + type: Number, + default: 6000 + } + }, + + computed: { + classes () { + return { + 'snack': true, + 'snack--bottom': this.bottom || !this.top, + 'snack--left': this.left, + 'snack--right': this.right, + 'snack--top': this.top, + 'snack--multi-line': this.multiLine + } + }, + computedTransition () { + return this.top ? 'v-slide-y-transition' : 'v-slide-y-reverse-transition' + } + }, + + watch: { + isActive () { + if (this.isActive) { + setTimeout(() => (this.isActive = false), this.timeout) + } + } + }, + + render (h) { + const content = h('div', { + 'class': 'snack__content', + directives: [{ + name: 'show', + value: this.isActive + }] + }, [this.$slots.default]) + + return h('div', { + 'class': this.classes + }, [h(this.computedTransition, {}, [content])]) + } +} diff --git a/src/components/snackbars/index.js b/src/components/snackbars/index.js new file mode 100755 index 00000000000..d18fc510a22 --- /dev/null +++ b/src/components/snackbars/index.js @@ -0,0 +1,5 @@ +import Snackbar from './Snackbar' + +export default { + Snackbar +} diff --git a/src/components/transitions/_index.js b/src/components/transitions/_index.js index 032d4dd6a42..2c1b5ba1c67 100755 --- a/src/components/transitions/_index.js +++ b/src/components/transitions/_index.js @@ -2,6 +2,7 @@ import { createSimpleTransition } from '../../util/helpers' const SlideXTransition = createSimpleTransition('slide-x-transition') const SlideYTransition = createSimpleTransition('slide-y-transition') +const SlideYReverseTransition = createSimpleTransition('slide-y-reverse-transition') const ScaleTransition = createSimpleTransition('scale-transition') const TabTransition = createSimpleTransition('tab-transition') const TabReverseTransition = createSimpleTransition('tab-reverse-transition') @@ -15,6 +16,7 @@ const MenuTransition = createSimpleTransition('menu-transition') export default { SlideXTransition, SlideYTransition, + SlideYReverseTransition, ScaleTransition, FadeTransition, TabTransition, diff --git a/src/index.js b/src/index.js index ca2f89e31cf..89be336b99e 100755 --- a/src/index.js +++ b/src/index.js @@ -3,7 +3,6 @@ require('./stylus/main.styl') import Components from './components/_index' import Directives from './directives/_index' import Load from './util/load' -import Toast from './functions/toast' const defaults = { componentPrefix: 'V', @@ -22,8 +21,7 @@ function plugin (Vue, options) { }) Vue.prototype.$vuetify = { - load: Load, - toast: Toast + load: Load } } diff --git a/src/mixins/checkbox.js b/src/mixins/checkbox.js index d6562e114b5..ed8be2b452a 100755 --- a/src/mixins/checkbox.js +++ b/src/mixins/checkbox.js @@ -23,7 +23,9 @@ export default { } if (!this.trueValue || !this.falseValue) { - return Boolean(this.inputValue) + return this.value + ? this.value === this.inputValue + : Boolean(this.inputValue) } return this.inputValue === this.trueValue @@ -50,6 +52,10 @@ export default { } } else if (this.trueValue || this.falseValue) { input = input === this.trueValue ? this.falseValue : this.trueValue + } else if (this.value) { + input = this.value === this.inputValue + ? null + : this.value } else { input = !input } diff --git a/src/stylus/components/_buttons.styl b/src/stylus/components/_buttons.styl index 7a1a48a2d37..8c71b4ae37f 100755 --- a/src/stylus/components/_buttons.styl +++ b/src/stylus/components/_buttons.styl @@ -220,6 +220,7 @@ &--block display: flex flex: 1 + margin: $button-margin 0 width: 100% &--round diff --git a/src/stylus/components/_sliders.styl b/src/stylus/components/_sliders.styl index c7c9a66571f..d52e4f82ef4 100755 --- a/src/stylus/components/_sliders.styl +++ b/src/stylus/components/_sliders.styl @@ -18,16 +18,16 @@ /** Input Group */ .input-group--slider + flex-direction: row + flex-wrap: wrap + .input-group__details:before, .input-group__details:after display: none - label - position: absolute - left: 0 - top: 0 + label + .input-group__input - margin-left: 56px + margin-left: 16px &.input-group--active .slider__thumb diff --git a/src/stylus/components/_snackbars.styl b/src/stylus/components/_snackbars.styl new file mode 100755 index 00000000000..c144bc6603c --- /dev/null +++ b/src/stylus/components/_snackbars.styl @@ -0,0 +1,69 @@ +.snack + position: fixed + display: flex + height: 48px + z-index: 1000 + visibility: visible + + &--multi-line + min-height: 48px + height: auto + + &--top + top: 0 + left: 50% + transform: translate3d(-50%, 0, 0) translateZ(0) + + &--bottom + bottom: 0 + left: 50% + transform: translate3d(-50%, 0, 0) translateZ(0) + + &--left + left: 8px + right: initial + transform: none + + &.snack--top + top: 8px + + &.snack--bottom + bottom: 8px + + &--right + left: initial + right: 8px + transform: none + + &.snack--top + top: 8px + + &.snack--bottom + top: initial + bottom: 8px + + &__content + background-color: $snackbar-background-color + padding: 14px 24px + border-radius: 2px + max-width: 568px + min-width: 288px + align-items: center + color: #fff + display: flex + font-size: 14px + justify-content: space-between + transition: .4s $transition.swing + + .btn + margin: 0 -16px 0 24px + min-width: 0 + +@media $display-breakpoints.md-and-down + .snack + width: 100% + + .snack__content + border-radius: 0 + max-width: 100% + width: 100% \ No newline at end of file diff --git a/src/stylus/generic/_transitions.styl b/src/stylus/generic/_transitions.styl index f3f5ea8564f..acc02ecaaf8 100755 --- a/src/stylus/generic/_transitions.styl +++ b/src/stylus/generic/_transitions.styl @@ -68,6 +68,14 @@ opacity: 0 transform: translateY(-15px) +.slide-y-reverse-transition + &-enter-active, &-leave, &-leave-to + transition: $primary-transition + + &-enter, &-leave-to + opacity: 0 + transform: translateY(15px) + .slide-x-transition &-enter-active, &-leave, &-leave-to transition: $primary-transition diff --git a/src/stylus/main.styl b/src/stylus/main.styl index 2e7f4f3eb12..068b4fd020c 100755 --- a/src/stylus/main.styl +++ b/src/stylus/main.styl @@ -49,4 +49,5 @@ @import './trumps/_display' @import './trumps/_helpers' @import './trumps/_spacing' -@import './trumps/_text' \ No newline at end of file +@import './trumps/_text' +@import './components/_snackbars' diff --git a/src/stylus/settings/_variables.styl b/src/stylus/settings/_variables.styl index 5227d11ee7a..9fe7f005991 100755 --- a/src/stylus/settings/_variables.styl +++ b/src/stylus/settings/_variables.styl @@ -59,14 +59,14 @@ $grid-columns := 12 // Display // ============================================================ $display-breakpoints := { - sm-and-down: "only screen and (max-width: ($grid-breakpoints.md - 1))" - sm-and-up: "only screen and (min-width: ($grid-breakpoints.md))" - md-only: "only screen and (min-width: $grid-breakpoints.md) and (max-width: ($grid-breakpoints.lg - 1))" - md-and-down: "only screen and (max-width: $grid-breakpoints.lg - 1)" - md-and-up: "only screen and (min-width: ($grid-breakpoints.lg))" - lg-only: "only screen and (min-width: $grid-breakpoints.lg) and (max-width: ($grid-breakpoints.xl - 1))" - lg-and-down: "only screen and (max-width: ($grid-breakpoints.xl - 1))" - lg-and-up: "only screen and (min-width: $grid-breakpoints.xl)" + sm-and-down: "only screen and (max-width: %s)" % ($grid-breakpoints.md - 1) + sm-and-up: "only screen and (min-width: (%s))" % $grid-breakpoints.md + md-only: "only screen and (min-width: %s) and (max-width: %s)" % $grid-breakpoints.md ($grid-breakpoints.lg - 1) + md-and-down: "only screen and (max-width: %s )" % ($grid-breakpoints.lg - 1) + md-and-up: "only screen and (min-width: %s)" % $grid-breakpoints.lg + lg-only: "only screen and (min-width: %s) and (max-width: %s)" % $grid-breakpoints.lg ($grid-breakpoints.xl - 1) + lg-and-down: "only screen and (max-width: (%s - 1))" % $grid-breakpoints.xl + lg-and-up: "only screen and (min-width: %s)" % $grid-breakpoints.xl } @@ -125,7 +125,8 @@ $transition := { linear-out-slow-in: cubic-bezier(0.0, 0.0, 0.2, 1), fast-out-linear-in: cubic-bezier(0.4, 0.0, 1, 1), ease-in-out: cubic-bezier(0.4, 0.0, 0.6, 1), - fast-in-fast-out: cubic-bezier(.25,.8,.25,1) + fast-in-fast-out: cubic-bezier(.25,.8,.25,1), + swing: cubic-bezier(.25,.8,.25,1) } // Components @@ -355,6 +356,10 @@ $slider-dark-label := #fff $slider-dark-ticks := rgba(#fff, .6) +/** Snackbar */ +$snackbar-background-color := #323232 + + /* Text Input */ $input-group-height := 58px $input-group-margin := 18px 0 From e8805e28d3e1627db2ce9e187f7d19544efdd15e Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 22:25:39 -0500 Subject: [PATCH 093/172] updated mobile styles --- src/stylus/components/_snackbars.styl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/stylus/components/_snackbars.styl b/src/stylus/components/_snackbars.styl index c144bc6603c..2ae17a2b21f 100755 --- a/src/stylus/components/_snackbars.styl +++ b/src/stylus/components/_snackbars.styl @@ -62,6 +62,15 @@ @media $display-breakpoints.md-and-down .snack width: 100% + left: 0 + right: initial + + &--right, &--left + &.snack--top + top: 0 + + &.snack--bottom + bottom: 0 .snack__content border-radius: 0 From aaae366db48a75675cfca3ebdf1a9623359b46aa Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 22:34:10 -0500 Subject: [PATCH 094/172] fixed bug where label could not be clicked --- src/stylus/components/_selection-controls.styl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index 80f16a5d99d..d0117c9d167 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -28,6 +28,7 @@ padding-left: 32px position: absolute left: 0 + z-index: 1 .input-group--selection-controls__ripple border-radius: 50% @@ -43,6 +44,8 @@ /** Switch */ .input-group.input-group--selection-controls + z-index: 0 + &.switch .input-group--selection-controls__container position: relative From 82e36cbc5b78803fa431905d2d3fce49a56ce48e Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 22:57:02 -0500 Subject: [PATCH 095/172] mobile tweaks --- src/stylus/components/_snackbars.styl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stylus/components/_snackbars.styl b/src/stylus/components/_snackbars.styl index 2ae17a2b21f..f338534dcec 100755 --- a/src/stylus/components/_snackbars.styl +++ b/src/stylus/components/_snackbars.styl @@ -64,6 +64,7 @@ width: 100% left: 0 right: initial + transform: none &--right, &--left &.snack--top From aee528111505368a943d5feeb3d1db427e02fa03 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 22:57:09 -0500 Subject: [PATCH 096/172] fixed ripple bug --- src/stylus/components/_selection-controls.styl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index d0117c9d167..a344bd47792 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -25,7 +25,7 @@ /** Label */ .input-group--selection-controls label cursor: pointer - padding-left: 32px + margin-left: 32px position: absolute left: 0 z-index: 1 From d608373158813036c309aff2d71f3f260682fc10 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 23:03:40 -0500 Subject: [PATCH 097/172] fixed switch left padding --- src/stylus/components/_selection-controls.styl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index a344bd47792..dfaa0308cf7 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -90,7 +90,7 @@ background: currentColor !important label - padding-left: 44px + margin-left: 44px /* Theme */ .input-group--selection-controls From a10b7beeac60abf9bb8e679d1bcad859ff78018b Mon Sep 17 00:00:00 2001 From: John Leider Date: Sat, 4 Mar 2017 23:24:40 -0500 Subject: [PATCH 098/172] more slider style tweaks --- src/stylus/components/_sliders.styl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stylus/components/_sliders.styl b/src/stylus/components/_sliders.styl index d52e4f82ef4..93aa984fcde 100755 --- a/src/stylus/components/_sliders.styl +++ b/src/stylus/components/_sliders.styl @@ -24,10 +24,14 @@ .input-group__details:before, .input-group__details:after display: none + .input-group__input + flex: 1 1 100% + label + .input-group__input margin-left: 16px + flex: 1 1 auto &.input-group--active .slider__thumb From 3eb11ce95c74d99fe77276122d3e082c794b505a Mon Sep 17 00:00:00 2001 From: David Graham Date: Sun, 5 Mar 2017 06:24:16 -0600 Subject: [PATCH 099/172] added close prop, icon callbacks, esc key, fixed misc issues --- src/components/forms/Select.js | 115 +++++++++++++++++++++------------ src/mixins/input.js | 28 ++++++-- 2 files changed, 98 insertions(+), 45 deletions(-) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index f7fc3db78c7..f8f42eeb4ea 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -8,30 +8,15 @@ export default { data () { return { - selected: this.multiple ? this.value : [this.value], - filtered: null, - searchText: this.multiple ? '' : this.value[this.itemText], - menuActive: false - } - }, - - computed: { - classes () { - return { - 'input-group--text-field': true, - 'input-group--select': true, - 'input-group--autocomplete': this.autocomplete, - 'input-group--single-line': this.singleLine, - 'input-group--multi-line': this.multiLine - } + inputValue: this.multiple ? Array.from(this.value || []) : new Array(this.value || 0), + inputSearch: this.value ? this.value[this.itemText] : '', + filteredItems: null, + menuActive: false, + appendIconCbPrivate: this.removeAllSelected } }, props: { - value: { - type: [Object, Array], - default: () => {} - }, items: { type: Array, default: () => [] @@ -48,50 +33,94 @@ export default { autocomplete: Boolean, singleLine: Boolean, chips: Boolean, + close: Boolean, debounce: { type: Number, default: 300 } }, + computed: { + classes () { + return { + 'input-group--text-field': true, + 'input-group--select': true, + 'input-group--autocomplete': this.autocomplete, + 'input-group--single-line': this.singleLine, + 'input-group--multi-line': this.multiLine + } + } + }, + watch: { focused () { this.$emit('focused', this.focused) }, - value (val) { - this.selected = this.multiple ? val : [val] + this.inputValue = this.multiple ? val || [] : new Array(val) }, - - selected (val) { - this.searchText = this.multiple ? '' : this.selected[0][this.itemText] - this.$emit('input', this.multiple ? this.selected : this.selected[0]) + inputValue (val) { + this.$emit('input', this.multiple ? val : val[0]) + }, + menuActive (isActive) { + if (!isActive) this.$refs.searchField.blur() } }, methods: { isDirty () { - return this.selected.length + return this.inputValue.length + }, + + focus () { + this.focused = true + this.closeAction(true) + }, + + blur () { + this.$nextTick(() => (this.focused = false)) + this.closeAction(false) }, + + // TODO: Maybe this should be computed prop? filterItems () { - const { items, searchText, itemText } = this + const { items, inputSearch, itemText } = this - this.filtered = searchText - ? items.filter(item => item[itemText].includes(searchText)) + this.filteredItems = inputSearch && this.autocomplete + ? items.filter(item => item[itemText].includes(inputSearch)) : null }, isSelected (item) { - return this.selected.includes(item) + return this.inputValue.includes(item) }, addSelected (item) { - this.selected = this.multiple ? this.selected.push(item) : [item] - this.filtered = null + if (this.multiple) { + this.inputValue.push(item) + this.inputSearch = '' + } else { + this.inputValue = [item] + this.inputSearch = item[this.itemText] + } + this.filterItems() }, removeSelected (item) { - this.selected.splice(this.selected.findIndex(s => s === item), 1) + this.inputValue.splice(this.inputValue.findIndex(s => s === item), 1) + }, + + removeAllSelected (e) { + if (!this.appendIconAlt) return + + e.stopPropagation() + this.inputValue = [] + this.inputSearch = '' + this.closeAction(false) + }, + + closeAction (on = true) { + this.appendIconAlt = on && this.close && this.inputValue.length ? 'close' : '' }, genMenu (h) { @@ -110,6 +139,10 @@ export default { }, on: { input: (val) => { this.menuActive = val } + }, + nativeOn: { + '!mouseenter': () => { this.closeAction() }, + 'mouseleave': () => { this.closeAction(false) } } } @@ -141,7 +174,7 @@ export default { const slots = this.$scopedSlots.selection const comma = true // <-- default - return this.selected.map(item => { + return this.inputValue.map(item => { if (slots) return this.genSlotSelection(h, item) if (chips) return this.genChipSelection(h, item) if (comma) return this.genCommaSelection(h, item) @@ -183,13 +216,12 @@ export default { const data = { ref: 'searchField', domProps: { - value: this.searchText + value: this.inputSearch }, on: { - input: e => { this.searchText = e.target.value }, - click: e => { if (this.menuActive) e.stopPropagation() }, - focus: () => { this.focused = true }, - blur: () => this.$nextTick(() => (this.focused = false)), + input: e => { this.inputSearch = e.target.value }, + focus: () => { this.focus() }, + blur: () => { this.blur() }, keyup: debounce(this.filterItems, this.debounce) } } @@ -198,7 +230,7 @@ export default { }, genList (h) { - const list = (this.filtered || this.items).map(item => this.genListItem(h, item)) + const list = (this.filteredItems || this.items).map(item => this.genListItem(h, item)) return h('v-list', list) }, @@ -216,6 +248,7 @@ export default { this.multiple && this.isSelected(item) ? this.removeSelected(item) : this.addSelected(item) + this.$refs.searchField.focus() } } diff --git a/src/mixins/input.js b/src/mixins/input.js index 19b4f806a91..82339f18d17 100755 --- a/src/mixins/input.js +++ b/src/mixins/input.js @@ -3,12 +3,17 @@ export default { return { errors: [], focused: false, - lazyValue: this.value + lazyValue: this.value, + appendIconAlt: '', + prependIconAlt: '', + appendIconCbPrivate: null, + prependIconCbPrivate: null } }, props: { appendIcon: String, + appendIconCb: Function, dark: Boolean, disabled: Boolean, hint: String, @@ -19,6 +24,7 @@ export default { default: true }, prependIcon: String, + prependIconCb: Function, required: Boolean, rules: { type: Array, @@ -128,9 +134,23 @@ export default { ) }, genIcon (h, type) { - return h('v-icon', { - 'class': 'input-group__' + type + '-icon' - }, this[`${type}Icon`]) + const icon = this[`${type}IconAlt`] || this[`${type}Icon`] + const callback = this[`${type}IconCb`] + const callbackPrivate = this[`${type}IconCbPrivate`] + + return h( + 'v-icon', + { + 'class': 'input-group__' + type + '-icon', + 'nativeOn': { + 'click': e => { + if (typeof callbackPrivate === 'function') callbackPrivate(e) + if (typeof callback === 'function') callback(e) + } + } + }, + icon + ) }, genInputGroup (h, input, data = {}) { const children = [] From 7227dcc92130431d745019476993f4ec5a508655 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 Mar 2017 10:11:20 -0500 Subject: [PATCH 100/172] added relative positioning for menu --- src/stylus/components/_menus.styl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stylus/components/_menus.styl b/src/stylus/components/_menus.styl index de0636507b1..5507159c82a 100755 --- a/src/stylus/components/_menus.styl +++ b/src/stylus/components/_menus.styl @@ -1,5 +1,6 @@ .menu display: inline-block + position: relative &__activator /* display: inline-flex */ From 2fbdc9961ab1ca77e36dae064dfac1e203b046e4 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 Mar 2017 10:11:25 -0500 Subject: [PATCH 101/172] removed nudge --- src/components/forms/Select.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index f8f42eeb4ea..b2439fd2844 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -134,8 +134,8 @@ export default { auto: !this.autocomplete, closeOnClick: !this.multiple, value: this.menuActive, - nudgeBottom: -20, - nudgeTop: -5 + nudgeBottom: 0, + nudgeTop: 0 }, on: { input: (val) => { this.menuActive = val } From d6f5af65520d5468cc1019f85fd673a09228a3d2 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 Mar 2017 13:25:29 -0500 Subject: [PATCH 102/172] menu/select updates --- src/components/forms/Select.js | 53 +-- src/components/menus/Menu.vue | 308 +++++++----------- src/stylus/components/_menus.styl | 10 +- .../components/_selection-controls.styl | 7 +- 4 files changed, 149 insertions(+), 229 deletions(-) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index b2439fd2844..c6ec56b9c0e 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -69,7 +69,7 @@ export default { methods: { isDirty () { - return this.inputValue.length + return this.inputSearch || this.multiple && this.inputValue.length }, focus () { @@ -141,8 +141,8 @@ export default { input: (val) => { this.menuActive = val } }, nativeOn: { - '!mouseenter': () => { this.closeAction() }, - 'mouseleave': () => { this.closeAction(false) } + '!mouseenter': this.closeAction, + mouseleave: () => (this.closeAction(false)) } } @@ -174,10 +174,13 @@ export default { const slots = this.$scopedSlots.selection const comma = true // <-- default - return this.inputValue.map(item => { + return this.inputValue.map((item, index, array) => { if (slots) return this.genSlotSelection(h, item) if (chips) return this.genChipSelection(h, item) - if (comma) return this.genCommaSelection(h, item) + if (comma) { + const length = array.length + return this.genCommaSelection(h, item, length !== 1 && index !== length - 1) + } }) }, @@ -199,17 +202,16 @@ export default { return h('v-chip', data, item[this.itemText]) }, - genCommaSelection (h, item) { + genCommaSelection (h, item, hasComma) { const data = { style: { // TODO: Move this to stylus file somewhere. - 'font-size': '16px', - 'height': '30px', - 'padding-top': '4px', - 'padding-right': '4px' + fontSize: '16px', + height: '30px', + paddingTop: '4px', + paddingRight: '4px' } } - - return h('div', data, item[this.itemText] + ',') + return h('div', data, `${item[this.itemText]}${hasComma ? ',' : ''}`) }, genSearchField (h) { @@ -231,11 +233,11 @@ export default { genList (h) { const list = (this.filteredItems || this.items).map(item => this.genListItem(h, item)) - return h('v-list', list) + return h('v-list', {}, list) }, genListItem (h, item) { - return h('v-list-item', [this.genTile(h, item)]) + return h('v-list-item', {}, [this.genTile(h, item)]) }, genTile (h, item) { @@ -243,13 +245,26 @@ export default { 'class': { 'list__tile--active': this.isSelected(item) }, - 'nativeOn': { - click: () => { - this.multiple && this.isSelected(item) + nativeOn: { + click: e => { + if (!this.multiple) { + return + } + + e.stopPropagation() + e.preventDefault() + this.isSelected(item) ? this.removeSelected(item) : this.addSelected(item) this.$refs.searchField.focus() + }, + mousedown: e => { + if (this.multiple) { + return + } + this.addSelected(item) + this.$refs.searchField.focus() } } } @@ -263,11 +278,11 @@ export default { if (!this.multiple) return null const checkbox = h('v-checkbox', { props: { 'inputValue': this.isSelected(item) }}) - return h('v-list-tile-action', [checkbox]) + return h('v-list-tile-action', {}, [checkbox]) }, genContent (h, item) { - return h('v-list-tile-content', [h('v-list-tile-title', item[this.itemText])]) + return h('v-list-tile-content', {}, [h('v-list-tile-title', item[this.itemText])]) } }, diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 7e6fa6bc5d2..03135b20e21 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -1,14 +1,13 @@ @@ -35,67 +35,34 @@ data () { return { - window: {}, + autoAdjustment: 16, dimensions: { - activator: { - top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, offsetTop: 0 - }, - content: { - top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0, offsetTop: 0 - }, + activator: { top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 }, + content: { top: 0, left: 0, bottom: 0, right: 0, height: 0, width: 0, offsetTop: 0 }, list: null, selected: null }, - direction: { vert: '', horiz: '' }, - position: { left: '0px', top: '0px', right: 'auto', bottom: 'auto' }, - minWidth: 'auto' + minWidth: 'auto', + window: false } }, props: { - top: Boolean, + auto: Boolean, left: Boolean, bottom: Boolean, right: Boolean, - auto: Boolean, - offsetX: Boolean, - offsetY: Boolean, - nudgeXAuto: { - type: Number, - default: -16 - }, - nudgeYAuto: { - type: Number, - default: -16 - }, - nudgeTop: { - type: Number, - default: 0 - }, - nudgeLeft: { - type: Number, - default: 0 - }, - nudgeBottom: { - type: Number, - default: 0 - }, - nudgeRight: { - type: Number, - default: 0 - }, - closeOnClick: { - type: Boolean, - default: true - }, maxHeight: { type: [String, Number], default: 'auto' }, + offsetX: Boolean, + offsetY: Boolean, origin: { type: String, default: 'top left' }, + top: Boolean, transition: { type: String, default: 'v-menu-transition' @@ -104,216 +71,159 @@ watch: { isActive () { - if (this.isActive) this.activate() + if (this.isActive) { + this.activate() + } this.$emit('input', this.isActive) } }, computed: { + direction () { + return { + 'vert': (this.bottom || this.auto) ? 'bottom' : 'top', + 'horiz': (this.right || this.auto) ? 'right' : 'left' + } + }, + offset () { - const { activator: a, content: c } = this.dimensions - const { direction, offsetX, offsetY, offsetAuto: auto } = this - const { nudgeLeft: nl, nudgeTop: nt, nudgeRight: nr, nudgeBottom: nb } = this + if (!this.window) { + return {} + } - const horiz = direction.horiz === 'left' - ? offsetX ? a.left - c.right + nl : a.right - c.right + nl + auto.horiz - : offsetX ? a.right - c.left + nr : a.left - c.left + nr + auto.horiz - const vert = direction.vert === 'top' - ? offsetY ? a.top - c.bottom + nt : a.bottom - c.bottom + nt + auto.vert - : offsetY ? a.bottom - c.top + nb : a.top - c.top + nb + auto.vert + const { activator: a, content: c } = this.dimensions + const { pageYOffset: pageY, pageXOffset: pageX } = this.window - return { horiz, vert } + return { + 'top': this.offsetY ? -c.height + pageY : a.height - c.height + pageY, + 'left': this.offsetX ? -c.width + pageX : a.width - c.width + pageX, + 'bottom': this.offsetY ? a.height + pageY : pageY, + 'right': this.offsetX ? a.width + pageX : pageX + } }, - offsetAuto () { - if (!this.auto) return { horiz: 0, vert: 0 } - if (!this.dimensions.selected) return { horiz: this.nudgeXAuto, vert: this.nudgeYAuto } + autoOffset () { + if (!(this.auto && this.dimensions.selected)) return 0 const { activator: a, content: c, selected: s, list } = this.dimensions const offsetBottom = list.height - s.height - s.offsetTop const scrollMiddle = (c.height - s.height) / 2 - const horiz = this.nudgeXAuto - let vert = (a.height - c.height + this.nudgeYAuto) / 2 - vert += s.offsetTop < scrollMiddle ? scrollMiddle - s.offsetTop : 0 - vert += offsetBottom < scrollMiddle ? offsetBottom - scrollMiddle : 0 + let auto = (a.height - c.height) / 2 + if (s.offsetTop < scrollMiddle) auto += scrollMiddle - s.offsetTop + if (offsetBottom < scrollMiddle) auto += offsetBottom - scrollMiddle + + auto -= 10 - return { horiz, vert } + return auto }, - screenDistance () { - const { activator: a } = this.dimensions + offscreen () { + if (!this.window) { + return {} + } + + const { activator: a, content: c } = this.dimensions + const top = a.top + this.offset[this.direction.vert] + this.autoOffset + const left = a.left + this.offset[this.direction.horiz] + const { pageYOffset: pageY, pageXOffset: pageX } = this.window const { innerHeight: innerH, innerWidth: innerW } = this.window - const distance = {} - - distance.top = this.offsetY ? a.top : a.bottom - distance.left = this.offsetX ? a.left : a.right - distance.bottom = this.offsetY ? innerH - a.bottom : innerH - a.top - distance.right = this.offsetX ? innerW - a.right : innerW - a.left - distance.horizMax = distance.left > distance.right ? distance.left : distance.right - distance.horizMaxDir = distance.left > distance.right ? 'left' : 'right' - distance.vertMax = distance.top > distance.bottom ? distance.top : distance.bottom - distance.vertMaxDir = distance.top > distance.bottom ? 'top' : 'bottom' - - return distance + + return { + 'vert': top + c.height - pageY > innerH + ? innerH - (top + c.height - pageY) + : top - pageY < 0 + ? pageY - top + : 0, + 'horiz': left + c.width - pageX > innerW + ? innerW - (left + c.width - pageX) + : left - pageX < 0 + ? pageX - left + : 0 + } }, - screenOverflow () { - const { content: c } = this.dimensions - const left = c.left + this.offset.horiz - const top = c.top + this.offset.vert + position () { + const { vert, horiz } = this.direction + const a = this.dimensions.activator - const horiz = this.auto && left + c.width > this.window.innerWidth - ? (left + c.width) - this.window.innerWidth - : this.auto && left < 0 - ? left - : 0 - const vert = this.auto && top + c.height > this.window.innerHeight - ? (top + c.height) - this.window.innerHeight - : this.auto && top < 0 - ? top - : 0 + return { + top: a.top + this.offset[vert] + this.autoOffset + this.offscreen.vert, + left: a.left + this.offset[horiz] + this.offscreen.horiz - (this.auto ? this.autoAdjustment : 0) + } + }, - return { horiz, vert } + styles () { + return { + top: `${this.position.top}px`, + left: `${this.position.left}px` + } } }, + mounted () { + // Move content to beginning of the document (for more functionality). + document.body.appendChild(this.$refs.content) + this.window = window + }, + methods: { activate () { - this.window = window - this.setDirection() - this.updatePosition() - }, - - updatePosition () { + // Get measurements before transitions mess with them. this.updateDimensions() - const { horiz, vert } = this.direction - const { offset, screenOverflow } = this - - const left = horiz === 'left' ? 'auto' : `${offset.horiz - screenOverflow.horiz}px` - const top = vert === 'top' ? 'auto' : `${offset.vert - screenOverflow.vert}px` - const right = horiz === 'right' ? 'auto' : `${-offset.horiz - screenOverflow.horiz}px` - const bottom = vert === 'bottom' ? 'auto' : `${-offset.vert - screenOverflow.vert}px` - - this.setContentPosition({ left, top, right, bottom }) - this.flipFix() - }, - - setContentPosition (position) { - this.$refs.content.style.top = position.top - this.$refs.content.style.left = position.left - this.$refs.content.style.bottom = position.bottom - this.$refs.content.style.right = position.right - }, - - flipFix () { - const { auto, screenDistance } = this - const { content: c } = this.dimensions - let { horiz, vert } = this.direction - - // Flip direction, if needed, to where there's more room from the window edge. - horiz = !auto && c.width > screenDistance[horiz] ? screenDistance.horizMaxDir : horiz - vert = !auto && c.height > screenDistance[vert] ? screenDistance.vertMaxDir : vert - - if (horiz === this.direction.horiz && vert === this.direction.vert) return - - this.setDirection(horiz, vert) - this.updatePosition(false) - }, - - setDirection (horiz = '', vert = '') { - this.direction = { - horiz: horiz || (this.left && !this.auto ? 'left' : 'right'), - vert: vert || (this.top && !this.auto ? 'top' : 'bottom') - } - - // On every direction change, we must reset/reorientate position. - const top = this.direction.vert === 'top' ? 'auto' : '0px' - const left = this.direction.vert === 'left' ? 'auto' : '0px' - const bottom = this.direction.vert === 'bottom' ? 'auto' : '0px' - const right = this.direction.vert === 'right' ? 'auto' : '0px' - - this.setContentPosition({ left, top, right, bottom }) + this.$nextTick(() => { + this.isActive = true + }) }, updateDimensions () { this.sneakPeek() - this.updateMaxMin() - - const { activator: a, content: c } = this.$refs - // Let the DOM compute dimensions. + this.$refs.content.style.minWidth = `${this.$el.clientWidth + (this.auto ? this.autoAdjustment : 0)}px` + this.$refs.content.style.maxHeight = isNaN(this.maxHeight) ? this.maxHeight : `${this.maxHeight}px` this.dimensions = { - 'activator': a.children ? this.measure(a.children[0]) : this.measure(a), - 'content': this.measure(c), - 'list': this.measure(c, '.list'), - 'selected': this.measure(c, '.list__tile--active', 'parent') + 'activator': this.rect(this.$refs.activator), + 'content': this.rect(this.$refs.content), + 'list': this.rect(this.$refs.content, '.list'), + 'selected': this.rect(this.$refs.content, '.list__tile--active', 'parent') } - this.fixOffscreen() this.updateScroll() - this.sneakPeek(false) - }, - - updateMaxMin () { - const { $el, $refs, maxHeight, auto, nudgeXAuto: nudgeX } = this - - $refs.content.style.minWidth = `${$el.clientWidth + Math.abs(auto ? nudgeX : 0)}px` - $refs.content.style.maxHeight = null // <-- TODO: This is a temporary fix. - $refs.content.style.maxHeight = isNaN(maxHeight) ? maxHeight : `${maxHeight}px` - }, - - fixOffscreen () { - const { $refs, screenDistance } = this - const { vert } = this.direction - - // If not auto, reduce height to the max vertical distance to a window edge. - if (!this.auto && this.dimensions.content.height > screenDistance[vert]) { - $refs.content.style.maxHeight = `${screenDistance.vertMax}px` - this.dimensions.content.height = $refs.content.getBoundingClientRect().height - } + this.sneakPeekOff() }, updateScroll () { - if (!this.auto || !this.dimensions.selected) return + if (!(this.auto && this.dimensions.selected)) return - const { content: c, selected: s, list: l } = this.dimensions + const { content: c, selected: s } = this.dimensions const scrollMiddle = (c.height - s.height) / 2 - const scrollMax = l.height - c.height - let offsetTop = s.offsetTop - scrollMiddle - - offsetTop = this.screenOverflow.vert && offsetTop > scrollMax ? scrollMax : offsetTop - offsetTop = this.screenOverflow.vert && offsetTop < 0 ? 0 : offsetTop - offsetTop -= this.screenOverflow.vert - this.$refs.content.scrollTop = offsetTop + this.$refs.content.scrollTop = s.offsetTop - scrollMiddle + this.offscreen.vert }, // Utils // ==================== - measure (el, selector, getParent = false) { + rect (el, selector, getParent = false) { el = selector ? el.querySelector(selector) : el el = el && getParent ? el.parentElement : el - if (!el) return null - const { top, left, bottom, right, width, height } = el.getBoundingClientRect() - return { top, left, bottom, right, width, height, offsetTop: el.offsetTop } + return el + ? Object.assign(el.getBoundingClientRect(), { 'offsetTop': el.offsetTop }) + : null }, - sneakPeek (on = true) { - const originalDisplay = this.$refs.content.style.display + sneakPeek () { + this.$refs.content.style.opacity = 0 + this.$refs.content.style.display = 'inline-block' + }, - if (on) { - this.$refs.content.style.opacity = 0 - this.$refs.content.style.display = 'inline-block' - } else { - this.$refs.content.style.display = originalDisplay - this.$refs.content.style.opacity = null - } + sneakPeekOff () { + this.$refs.content.style.display = 'none' + this.$refs.content.style.opacity = null } } } - \ No newline at end of file + diff --git a/src/stylus/components/_menus.styl b/src/stylus/components/_menus.styl index 5507159c82a..2439afaf944 100755 --- a/src/stylus/components/_menus.styl +++ b/src/stylus/components/_menus.styl @@ -20,24 +20,22 @@ &-transition &-enter - max-width: 50px !important - min-width: 0 + opacity: 0 .list__tile min-width: 0 transition-delay: .1s opacity: 0 transform: translateY(-15px) + pointer-events: none .list__tile--active opacity: 1 !important transform: translateY(0) !important + pointer-events: auto &-enter-to - margin-top: initial - max-height: initial - pointer-events: auto - max-width: 300px + opacity: 1 .list__tile pointer-events: auto diff --git a/src/stylus/components/_selection-controls.styl b/src/stylus/components/_selection-controls.styl index dfaa0308cf7..7e8764b5b86 100755 --- a/src/stylus/components/_selection-controls.styl +++ b/src/stylus/components/_selection-controls.styl @@ -15,12 +15,9 @@ .input-group__input height: $input-height - width: 100%; - align-items: center; + width: 100% + align-items: center position: relative - -.list__tile__action .input-group.input-group--selection-controls .icon - top: 10px /** Label */ .input-group--selection-controls label From 702290d6223063fc80d1e90f1f1c32645e4c631f Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 Mar 2017 13:35:16 -0500 Subject: [PATCH 103/172] added outside updating of inputSearch --- src/components/forms/Select.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index c6ec56b9c0e..8d3ed548809 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -58,6 +58,7 @@ export default { }, value (val) { this.inputValue = this.multiple ? val || [] : new Array(val) + this.inputSearch = this.multiple ? '' : val[this.itemText] }, inputValue (val) { this.$emit('input', this.multiple ? val : val[0]) From 819bc10691091cebc39069385b46e91a44e748a9 Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 Mar 2017 13:49:09 -0500 Subject: [PATCH 104/172] fixed styles and multiple emitting --- src/components/forms/Select.js | 23 +++++++---------------- src/stylus/components/_select.styl | 24 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index 8d3ed548809..537634c7dea 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -158,11 +158,7 @@ export default { genSelectionsAndSearch (h) { const data = { slot: 'activator', - style: { // TODO: Move this to stylus file somewhere. - 'display': 'flex', - 'flex-wrap': 'wrap', - 'width': '100%' - } + 'class': 'input-group__selections' } return this.multiple @@ -196,7 +192,7 @@ export default { input: val => { if (val === false) this.removeSelected(item) } }, nativeOn: { - click: e => { e.stopPropagation() } + click: e => e.stopPropagation() } } @@ -205,12 +201,7 @@ export default { genCommaSelection (h, item, hasComma) { const data = { - style: { // TODO: Move this to stylus file somewhere. - fontSize: '16px', - height: '30px', - paddingTop: '4px', - paddingRight: '4px' - } + 'class': 'input-group__selections__comma' } return h('div', data, `${item[this.itemText]}${hasComma ? ',' : ''}`) }, @@ -222,10 +213,10 @@ export default { value: this.inputSearch }, on: { - input: e => { this.inputSearch = e.target.value }, - focus: () => { this.focus() }, - blur: () => { this.blur() }, - keyup: debounce(this.filterItems, this.debounce) + input: e => (this.inputSearch = e.target.value), + focus: () => this.focus, + blur: () => this.blur, + keyup: () => debounce(this.filterItems, this.debounce) } } diff --git a/src/stylus/components/_select.styl b/src/stylus/components/_select.styl index c146e4bd47d..ff19e471c3a 100755 --- a/src/stylus/components/_select.styl +++ b/src/stylus/components/_select.styl @@ -1,3 +1,25 @@ .input-group--select input - cursor: pointer \ No newline at end of file + cursor: pointer + +.input-group--select + .input-group__selections + display: flex + flex-wrap: wrap + width: 100% + + &__comma + font-size: 16px + height: 30px + padding-top: 4px + padding-right: 4px + + +.input-group--select + &.input-group--light + .input-group__selections__comma + color: rgba(#000, .87) + + &.input-group--dark + .input-group__selections__comma + color: #fff \ No newline at end of file From a2ab89424f8335bd5d5afcf3be2e76ed5c22f6ea Mon Sep 17 00:00:00 2001 From: John Leider Date: Sun, 5 Mar 2017 13:59:53 -0500 Subject: [PATCH 105/172] added ability to disable menu --- src/components/forms/Select.js | 15 ++++++++------- src/components/menus/Menu.vue | 17 +++++++++++++++-- src/stylus/components/_menus.styl | 7 ++++++- src/stylus/components/_select.styl | 4 ++++ 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/components/forms/Select.js b/src/components/forms/Select.js index 537634c7dea..1cd795d36eb 100755 --- a/src/components/forms/Select.js +++ b/src/components/forms/Select.js @@ -131,15 +131,14 @@ export default { width: '100%' }, props: { - offsetY: this.autocomplete, auto: !this.autocomplete, closeOnClick: !this.multiple, - value: this.menuActive, - nudgeBottom: 0, - nudgeTop: 0 + disabled: this.disabled, + offsetY: this.autocomplete, + value: this.menuActive }, on: { - input: (val) => { this.menuActive = val } + input: (val) => (this.menuActive = val) }, nativeOn: { '!mouseenter': this.closeAction, @@ -151,8 +150,10 @@ export default { }, genActivator (h) { - const data = { slot: 'activator' } - return h('div', data, [this.genInputGroup(h, [this.genSelectionsAndSearch(h)])]) + const data = { + slot: 'activator' + } + return this.genInputGroup(h, [this.genSelectionsAndSearch(h)], data) }, genSelectionsAndSearch (h) { diff --git a/src/components/menus/Menu.vue b/src/components/menus/Menu.vue index 03135b20e21..0e0c5286a1e 100755 --- a/src/components/menus/Menu.vue +++ b/src/components/menus/Menu.vue @@ -1,11 +1,11 @@