Add ripple support
parent
17411a9659
commit
1ecdcf58b4
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-accordion p-component">
|
<div class="p-accordion p-component">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
<div v-for="(tab, i) of tabs" :key="tab.header || i" class="p-accordion-tab">
|
<div v-for="(tab, i) of tabs" :key="tab.header || i" :class="['p-accordion-tab', {'p-accordion-tab-active': tab.d_active}]">
|
||||||
<div :class="['p-accordion-header', {'p-highlight': tab.d_active, 'p-disabled': tab.disabled}]">
|
<div :class="['p-accordion-header', {'p-highlight': tab.d_active, 'p-disabled': tab.disabled}]">
|
||||||
<a role="tab" class="p-accordion-header-link" @click="onTabClick($event, tab)" @keydown="onTabKeydown($event, tab)" :tabindex="tab.disabled ? null : '0'"
|
<a role="tab" class="p-accordion-header-link" @click="onTabClick($event, tab)" @keydown="onTabKeydown($event, tab)" :tabindex="tab.disabled ? null : '0'"
|
||||||
:aria-expanded="tab.d_active" :id="ariaId + i + '_header'" :aria-controls="ariaId + i + '_content'">
|
:aria-expanded="tab.d_active" :id="ariaId + i + '_header'" :aria-controls="ariaId + i + '_content'">
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<transition name="p-input-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave">
|
<transition name="p-input-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave">
|
||||||
<div ref="overlay" class="p-autocomplete-panel p-component" :style="{'max-height': scrollHeight}" v-if="overlayVisible">
|
<div ref="overlay" class="p-autocomplete-panel p-component" :style="{'max-height': scrollHeight}" v-if="overlayVisible">
|
||||||
<ul :id="listId" class="p-autocomplete-items" role="listbox">
|
<ul :id="listId" class="p-autocomplete-items" role="listbox">
|
||||||
<li v-for="(item, i) of suggestions" class="p-autocomplete-item" :key="i" @click="selectItem($event, item)" role="option">
|
<li v-for="(item, i) of suggestions" class="p-autocomplete-item" :key="i" @click="selectItem($event, item)" role="option" v-ripple>
|
||||||
<slot name="item" :item="item" :index="i">
|
<slot name="item" :item="item" :index="i">
|
||||||
{{getItemContent(item)}}
|
{{getItemContent(item)}}
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -32,6 +32,7 @@ import ObjectUtils from '../utils/ObjectUtils';
|
||||||
import DomHandler from '../utils/DomHandler';
|
import DomHandler from '../utils/DomHandler';
|
||||||
import Button from '../button/Button';
|
import Button from '../button/Button';
|
||||||
import UniqueComponentId from '../utils/UniqueComponentId';
|
import UniqueComponentId from '../utils/UniqueComponentId';
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
|
@ -424,6 +425,9 @@ export default {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'Button': Button
|
'Button': Button
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -474,6 +478,8 @@ export default {
|
||||||
.p-autocomplete-item {
|
.p-autocomplete-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-autocomplete-multiple-container {
|
.p-autocomplete-multiple-container {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-button-text {
|
.p-button-text {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<button :class="buttonClass" v-on="$listeners" type="button">
|
<button :class="buttonClass" v-on="$listeners" type="button" v-ripple>
|
||||||
<span v-if="icon" :class="iconClass"></span>
|
<span v-if="icon" :class="iconClass"></span>
|
||||||
<span class="p-button-text">{{label||' '}}</span>
|
<span class="p-button-text">{{label||' '}}</span>
|
||||||
<span class="p-badge" v-if="badge" :class="badgeClass">{{badge}}</span>
|
<span class="p-badge" v-if="badge" :class="badgeClass">{{badge}}</span>
|
||||||
|
@ -7,6 +7,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
label: {
|
label: {
|
||||||
|
@ -48,6 +50,9 @@ export default {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-checkbox p-component" @click="onClick($event)">
|
<div :class="containerClass" @click="onClick($event)">
|
||||||
<div class="p-hidden-accessible">
|
<div class="p-hidden-accessible">
|
||||||
<input ref="input" type="checkbox" :checked="checked" :value="value" v-bind="$attrs" @focus="onFocus($event)" @blur="onBlur($event)">
|
<input ref="input" type="checkbox" :checked="checked" :value="value" v-bind="$attrs" @focus="onFocus($event)" @blur="onBlur($event)">
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,6 +61,9 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
checked() {
|
checked() {
|
||||||
return this.binary ? this.modelValue : ObjectUtils.contains(this.value, this.modelValue);
|
return this.binary ? this.modelValue : ObjectUtils.contains(this.value, this.modelValue);
|
||||||
|
},
|
||||||
|
containerClass() {
|
||||||
|
return ['p-checkbox p-component', {'p-checkbox-checked': this.checked, 'p-checkbox-disabled': this.$attrs.disabled, 'p-checkbox-focused': this.focused}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,4 +151,30 @@ button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 1px;
|
width: 1px;
|
||||||
word-wrap: normal !important;
|
word-wrap: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-ink {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
border-radius: 100%;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-ink-active {
|
||||||
|
animation: ripple 0.4s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes ripple {
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(2.5);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ripple {
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(2.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div ref="itemsWrapper" class="p-dropdown-items-wrapper" :style="{'max-height': scrollHeight}">
|
<div ref="itemsWrapper" class="p-dropdown-items-wrapper" :style="{'max-height': scrollHeight}">
|
||||||
<ul class="p-dropdown-items" role="listbox">
|
<ul class="p-dropdown-items" role="listbox">
|
||||||
<li v-for="(option, i) of visibleOptions" :class="['p-dropdown-item', {'p-highlight': isSelected(option), 'p-disabled': isOptionDisabled(option)}]"
|
<li v-for="(option, i) of visibleOptions" :class="['p-dropdown-item', {'p-highlight': isSelected(option), 'p-disabled': isOptionDisabled(option)}]" v-ripple
|
||||||
:aria-label="getOptionLabel(option)" :key="getOptionRenderKey(option)" @click="onOptionSelect($event, option)" role="option" :aria-selected="isSelected(option)">
|
:aria-label="getOptionLabel(option)" :key="getOptionRenderKey(option)" @click="onOptionSelect($event, option)" role="option" :aria-selected="isSelected(option)">
|
||||||
<slot name="option" :option="option" :index="i">
|
<slot name="option" :option="option" :index="i">
|
||||||
{{getOptionLabel(option)}}
|
{{getOptionLabel(option)}}
|
||||||
|
@ -41,6 +41,7 @@
|
||||||
<script>
|
<script>
|
||||||
import ObjectUtils from '../utils/ObjectUtils';
|
import ObjectUtils from '../utils/ObjectUtils';
|
||||||
import DomHandler from '../utils/DomHandler';
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
@ -451,6 +452,9 @@ export default {
|
||||||
equalityKey() {
|
equalityKey() {
|
||||||
return this.optionValue ? null : this.dataKey;
|
return this.optionValue ? null : this.dataKey;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -510,6 +514,8 @@ input.p-dropdown-label {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-dropdown-items {
|
.p-dropdown-items {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="p-listbox-list-wrapper" :style="listStyle">
|
<div class="p-listbox-list-wrapper" :style="listStyle">
|
||||||
<ul class="p-listbox-list" role="listbox" aria-multiselectable="multiple">
|
<ul class="p-listbox-list" role="listbox" aria-multiselectable="multiple">
|
||||||
<li v-for="(option, i) of visibleOptions" :tabindex="isOptionDisabled(option) ? null : '0'" :class="['p-listbox-item', {'p-highlight': isSelected(option), 'p-disabled': isOptionDisabled(option)}]"
|
<li v-for="(option, i) of visibleOptions" :tabindex="isOptionDisabled(option) ? null : '0'" :class="['p-listbox-item', {'p-highlight': isSelected(option), 'p-disabled': isOptionDisabled(option)}]" v-ripple
|
||||||
:aria-label="getOptionLabel(option)" :key="getOptionRenderKey(option)" @click="onOptionSelect($event, option)" @touchend="onOptionTouchEnd()" @keydown="onOptionKeyDown($event, option)" role="option" :aria-selected="isSelected(option)">
|
:aria-label="getOptionLabel(option)" :key="getOptionRenderKey(option)" @click="onOptionSelect($event, option)" @touchend="onOptionTouchEnd()" @keydown="onOptionKeyDown($event, option)" role="option" :aria-selected="isSelected(option)">
|
||||||
<slot name="option" :option="option" :index="i">
|
<slot name="option" :option="option" :index="i">
|
||||||
{{getOptionLabel(option)}}
|
{{getOptionLabel(option)}}
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
<script>
|
<script>
|
||||||
import ObjectUtils from '../utils/ObjectUtils';
|
import ObjectUtils from '../utils/ObjectUtils';
|
||||||
import DomHandler from '../utils/DomHandler';
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
@ -227,6 +228,9 @@ export default {
|
||||||
equalityKey() {
|
equalityKey() {
|
||||||
return this.optionValue ? null : this.dataKey;
|
return this.optionValue ? null : this.dataKey;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -244,6 +248,8 @@ export default {
|
||||||
|
|
||||||
.p-listbox-item {
|
.p-listbox-item {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-listbox-filter-container {
|
.p-listbox-filter-container {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<div ref="itemsWrapper" class="p-multiselect-items-wrapper" :style="{'max-height': scrollHeight}">
|
<div ref="itemsWrapper" class="p-multiselect-items-wrapper" :style="{'max-height': scrollHeight}">
|
||||||
<ul class="p-multiselect-items p-component" role="listbox" aria-multiselectable="true">
|
<ul class="p-multiselect-items p-component" role="listbox" aria-multiselectable="true">
|
||||||
<li v-for="(option, i) of visibleOptions" :class="['p-multiselect-item', {'p-highlight': isSelected(option), 'p-disabled': isOptionDisabled(option)}]" role="option" :aria-selected="isSelected(option)"
|
<li v-for="(option, i) of visibleOptions" :class="['p-multiselect-item', {'p-highlight': isSelected(option), 'p-disabled': isOptionDisabled(option)}]" role="option" :aria-selected="isSelected(option)"
|
||||||
:aria-label="getOptionLabel(option)" :key="getOptionRenderKey(option)" @click="onOptionSelect($event, option)" @keydown="onOptionKeyDown($event, option)" :tabindex="tabindex||'0'">
|
:aria-label="getOptionLabel(option)" :key="getOptionRenderKey(option)" @click="onOptionSelect($event, option)" @keydown="onOptionKeyDown($event, option)" :tabindex="tabindex||'0'" v-ripple>
|
||||||
<div class="p-checkbox p-component">
|
<div class="p-checkbox p-component">
|
||||||
<div :class="['p-checkbox-box p-component', {'p-highlight': isSelected(option)}]">
|
<div :class="['p-checkbox-box p-component', {'p-highlight': isSelected(option)}]">
|
||||||
<span :class="['p-checkbox-icon', {'pi pi-check': isSelected(option)}]"></span>
|
<span :class="['p-checkbox-icon', {'pi pi-check': isSelected(option)}]"></span>
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
<script>
|
<script>
|
||||||
import ObjectUtils from '../utils/ObjectUtils';
|
import ObjectUtils from '../utils/ObjectUtils';
|
||||||
import DomHandler from '../utils/DomHandler';
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
@ -406,6 +407,9 @@ export default {
|
||||||
equalityKey() {
|
equalityKey() {
|
||||||
return this.optionValue ? null : this.dataKey;
|
return this.optionValue ? null : this.dataKey;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -466,6 +470,8 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-multiselect-header {
|
.p-multiselect-header {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-radiobutton p-component" @click="onClick($event)">
|
<div :class="containerClass" @click="onClick($event)">
|
||||||
<div class="p-hidden-accessible">
|
<div class="p-hidden-accessible">
|
||||||
<input ref="input" type="radio" :checked="checked" :value="value" v-bind="$attrs" @focus="onFocus($event)" @blur="onBlur($event)">
|
<input ref="input" type="radio" :checked="checked" :value="value" v-bind="$attrs" @focus="onFocus($event)" @blur="onBlur($event)">
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,6 +51,9 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
checked() {
|
checked() {
|
||||||
return this.modelValue != null && ObjectUtils.equals(this.modelValue, this.value);
|
return this.modelValue != null && ObjectUtils.equals(this.modelValue, this.value);
|
||||||
|
},
|
||||||
|
containerClass() {
|
||||||
|
return ['p-radiobutton p-component', {'p-radiobutton-checked': this.checked, 'p-radiobutton-disabled': this.$attrs.disabled, 'p-radiobutton-focused': this.focused}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
|
||||||
|
function bindEvents(el) {
|
||||||
|
el.addEventListener('mousedown', onMouseDown);
|
||||||
|
el.addEventListener('mouseleave', onMouseLeave);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unbindEvents(el) {
|
||||||
|
el.removeEventListener('mousedown', onMouseDown);
|
||||||
|
el.removeEventListener('mouseleave', onMouseLeave);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create(el) {
|
||||||
|
let ink = document.createElement('span');
|
||||||
|
ink.className = 'p-ink';
|
||||||
|
el.appendChild(ink);
|
||||||
|
|
||||||
|
ink.addEventListener('animationend', onAnimationEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove(el) {
|
||||||
|
let ink = getInk(el);
|
||||||
|
if (ink) {
|
||||||
|
ink.removeEventListener('animationend', onAnimationEnd);
|
||||||
|
ink.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseDown(event) {
|
||||||
|
let target = event.currentTarget;
|
||||||
|
let ink = getInk(target);
|
||||||
|
|
||||||
|
if (ink) {
|
||||||
|
DomHandler.removeClass(ink, 'p-ink-active');
|
||||||
|
if (!DomHandler.getHeight(ink) && !DomHandler.getWidth(ink)) {
|
||||||
|
let d = Math.max(DomHandler.getOuterWidth(target), DomHandler.getOuterHeight(target));
|
||||||
|
ink.style.height = d + 'px';
|
||||||
|
ink.style.width = d + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
let offset = DomHandler.getOffset(target);
|
||||||
|
let x = event.pageX - offset.left + document.body.scrollTop - DomHandler.getWidth(ink) / 2;
|
||||||
|
let y = event.pageY - offset.top + document.body.scrollLeft - DomHandler.getHeight(ink) / 2;
|
||||||
|
|
||||||
|
ink.style.top = y + 'px';
|
||||||
|
ink.style.left = x + 'px';
|
||||||
|
DomHandler.addClass(ink, 'p-ink-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseLeave(event) {
|
||||||
|
resetInk(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetInk(event) {
|
||||||
|
let target = event.target;
|
||||||
|
let ink = getInk(target);
|
||||||
|
if (ink) {
|
||||||
|
DomHandler.removeClass(ink, 'p-ink-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAnimationEnd(event) {
|
||||||
|
DomHandler.removeClass(event.currentTarget, 'p-ink-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInk(el) {
|
||||||
|
for (let i = 0; i < el.children.length; i++) {
|
||||||
|
if (el.children[i].className.indexOf('p-ink') !== -1) {
|
||||||
|
return el.children[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ripple = {
|
||||||
|
inserted(el) {
|
||||||
|
create(el);
|
||||||
|
bindEvents(el);
|
||||||
|
},
|
||||||
|
unbind(el) {
|
||||||
|
remove(el);
|
||||||
|
unbindEvents(el);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ripple;
|
|
@ -1,23 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-tabmenu p-component">
|
<div class="p-tabmenu p-component">
|
||||||
<ul class="p-tabmenu-nav p-reset" role="tablist">
|
<ul ref="nav" class="p-tabmenu-nav p-reset" role="tablist">
|
||||||
<template v-for="(item,i) of model">
|
<template v-for="(item,i) of model">
|
||||||
<li :key="item.label + '_' + i" :class="getItemClass(item)" :style="item.style" v-if="visible(item)" role="tab" :aria-selected="isActive(item)" :aria-expanded="isActive(item)">
|
<li :key="item.label + '_' + i" :class="getItemClass(item)" :style="item.style" v-if="visible(item)" role="tab" :aria-selected="isActive(item)" :aria-expanded="isActive(item)">
|
||||||
<router-link v-if="item.to && !item.disabled" :to="item.to" class="p-menuitem-link" @click.native="onItemClick($event, item)" role="presentation">
|
<router-link v-if="item.to && !item.disabled" :to="item.to" class="p-menuitem-link" @click.native="onItemClick($event, item)" role="presentation" v-ripple>
|
||||||
<span :class="getItemIcon(item)" v-if="item.icon"></span>
|
<span :class="getItemIcon(item)" v-if="item.icon"></span>
|
||||||
<span class="p-menuitem-text">{{item.label}}</span>
|
<span class="p-menuitem-text">{{item.label}}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
<a v-else :href="item.url" class="p-menuitem-link" :target="item.target" @click="onItemClick($event, item)" role="presentation" :tabindex="item.disabled ? null : '0'">
|
<a v-else :href="item.url" class="p-menuitem-link" :target="item.target" @click="onItemClick($event, item)" role="presentation" :tabindex="item.disabled ? null : '0'" v-ripple>
|
||||||
<span :class="getItemIcon(item)" v-if="item.icon"></span>
|
<span :class="getItemIcon(item)" v-if="item.icon"></span>
|
||||||
<span class="p-menuitem-text">{{item.label}}</span>
|
<span class="p-menuitem-text">{{item.label}}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
<li ref="inkbar" class="p-tabmenu-ink-bar"></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
model: {
|
model: {
|
||||||
|
@ -25,6 +29,12 @@ export default {
|
||||||
default: null
|
default: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateInkBar();
|
||||||
|
},
|
||||||
|
updated() {
|
||||||
|
this.updateInkBar();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onItemClick(event, item) {
|
onItemClick(event, item) {
|
||||||
if (item.disabled) {
|
if (item.disabled) {
|
||||||
|
@ -53,12 +63,32 @@ export default {
|
||||||
},
|
},
|
||||||
visible(item) {
|
visible(item) {
|
||||||
return (typeof item.visible === 'function' ? item.visible() : item.visible !== false);
|
return (typeof item.visible === 'function' ? item.visible() : item.visible !== false);
|
||||||
|
},
|
||||||
|
findActiveTabIndex() {
|
||||||
|
if (this.model) {
|
||||||
|
for (let i = 0; i < this.model.length; i++) {
|
||||||
|
let item = this.model[i];
|
||||||
|
if (this.isActive(this.model[i])) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
updateInkBar() {
|
||||||
|
let tabHeader = this.$refs.nav.children[this.findActiveTabIndex()];
|
||||||
|
this.$refs.inkbar.style.width = DomHandler.getWidth(tabHeader) + 'px';
|
||||||
|
this.$refs.inkbar.style.left = tabHeader.offsetLeft + 'px';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
activeRoute() {
|
activeRoute() {
|
||||||
return this.$route.path;
|
return this.$route.path;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -79,6 +109,8 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
text-decoration: none;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-tabmenu-nav a:focus {
|
.p-tabmenu-nav a:focus {
|
||||||
|
@ -88,4 +120,8 @@ export default {
|
||||||
.p-tabmenu-nav .p-menuitem-text {
|
.p-tabmenu-nav .p-menuitem-text {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.p-tabmenu-ink-bar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="p-tabview p-component">
|
<div class="p-tabview p-component">
|
||||||
<ul class="p-tabview-nav" role="tablist">
|
<ul ref="nav" class="p-tabview-nav" role="tablist">
|
||||||
<li role="presentation" v-for="(tab, i) of tabs" :key="tab.header || i" :class="[{'p-highlight': (tab.d_active), 'p-disabled': tab.disabled}]">
|
<li role="presentation" v-for="(tab, i) of tabs" :key="tab.header || i" :class="[{'p-highlight': (tab.d_active), 'p-disabled': tab.disabled}]">
|
||||||
<a role="tab" class="p-tabview-nav-link" @click="onTabClick($event, tab)" @keydown="onTabKeydown($event, tab)" :tabindex="tab.disabled ? null : '0'" :aria-selected="tab.d_active">
|
<a role="tab" class="p-tabview-nav-link" @click="onTabClick($event, tab)" @keydown="onTabKeydown($event, tab)" :tabindex="tab.disabled ? null : '0'" :aria-selected="tab.d_active" v-ripple>
|
||||||
<span class="p-tabview-title" v-if="tab.header">{{tab.header}}</span>
|
<span class="p-tabview-title" v-if="tab.header">{{tab.header}}</span>
|
||||||
<TabPanelHeaderSlot :tab="tab" v-if="tab.$scopedSlots.header" />
|
<TabPanelHeaderSlot :tab="tab" v-if="tab.$scopedSlots.header" />
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li ref="inkbar" class="p-tabview-ink-bar"></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="p-tabview-panels">
|
<div class="p-tabview-panels">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -15,6 +16,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
import Ripple from '../ripple/Ripple';
|
||||||
|
|
||||||
const TabPanelHeaderSlot = {
|
const TabPanelHeaderSlot = {
|
||||||
functional: true,
|
functional: true,
|
||||||
props: {
|
props: {
|
||||||
|
@ -37,6 +41,13 @@ export default {
|
||||||
mounted() {
|
mounted() {
|
||||||
this.d_children = this.$children;
|
this.d_children = this.$children;
|
||||||
},
|
},
|
||||||
|
updated() {
|
||||||
|
let activeTab = this.tabs[this.findActiveTabIndex()];
|
||||||
|
if (!activeTab && this.tabs.length) {
|
||||||
|
this.tabs[0].d_active = true;
|
||||||
|
}
|
||||||
|
this.updateInkBar();
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onTabClick(event, tab) {
|
onTabClick(event, tab) {
|
||||||
if (!tab.disabled && !tab.d_active) {
|
if (!tab.disabled && !tab.d_active) {
|
||||||
|
@ -54,29 +65,28 @@ export default {
|
||||||
this.tabs[i].d_active = active;
|
this.tabs[i].d_active = active;
|
||||||
this.tabs[i].$emit('update:active', active);
|
this.tabs[i].$emit('update:active', active);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateInkBar();
|
||||||
},
|
},
|
||||||
onTabKeydown(event, tab) {
|
onTabKeydown(event, tab) {
|
||||||
if (event.which === 13) {
|
if (event.which === 13) {
|
||||||
this.onTabClick(event, tab);
|
this.onTabClick(event, tab);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
findActiveTab() {
|
findActiveTabIndex() {
|
||||||
let activeTab;
|
|
||||||
for (let i = 0; i < this.tabs.length; i++) {
|
for (let i = 0; i < this.tabs.length; i++) {
|
||||||
let tab = this.tabs[i];
|
let tab = this.tabs[i];
|
||||||
if (tab.d_active) {
|
if (tab.d_active) {
|
||||||
activeTab = tab;
|
return i;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return activeTab;
|
return null;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
updated() {
|
updateInkBar() {
|
||||||
let activeTab = this.findActiveTab();
|
let tabHeader = this.$refs.nav.children[this.findActiveTabIndex()];
|
||||||
if (!activeTab && this.tabs.length) {
|
this.$refs.inkbar.style.width = DomHandler.getWidth(tabHeader) + 'px';
|
||||||
this.tabs[0].d_active = true;
|
this.$refs.inkbar.style.left = tabHeader.offsetLeft + 'px';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -86,6 +96,9 @@ export default {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'TabPanelHeaderSlot': TabPanelHeaderSlot
|
'TabPanelHeaderSlot': TabPanelHeaderSlot
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
'ripple': Ripple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -106,6 +119,11 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-tabview-ink-bar {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.p-tabview-nav-link:focus {
|
.p-tabview-nav-link:focus {
|
||||||
|
|
|
@ -88,8 +88,8 @@ export default class DomHandler {
|
||||||
var rect = el.getBoundingClientRect();
|
var rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
top: rect.top + document.body.scrollTop,
|
top: rect.top + (window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0),
|
||||||
left: rect.left + document.body.scrollLeft
|
left: rect.left + (window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue