Update #3965 - For Dock

pull/4011/head
Tuğçe Küçükoğlu 2023-05-30 15:56:18 +03:00
parent 931edf0158
commit a8fd3ce6a8
4 changed files with 211 additions and 185 deletions

View File

@ -0,0 +1,185 @@
<script>
import BaseComponent from 'primevue/basecomponent';
import { useStyle } from 'primevue/usestyle';
const styles = `
.p-dock {
position: absolute;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
.p-dock-list-container {
display: flex;
pointer-events: auto;
}
.p-dock-list {
margin: 0;
padding: 0;
list-style: none;
display: flex;
align-items: center;
justify-content: center;
}
.p-dock-item {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
will-change: transform;
}
.p-dock-link {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
cursor: default;
}
.p-dock-item-second-prev,
.p-dock-item-second-next {
transform: scale(1.2);
}
.p-dock-item-prev,
.p-dock-item-next {
transform: scale(1.4);
}
.p-dock-item-current {
transform: scale(1.6);
z-index: 1;
}
/* Position */
/* top */
.p-dock-top {
left: 0;
top: 0;
width: 100%;
}
.p-dock-top .p-dock-item {
transform-origin: center top;
}
/* bottom */
.p-dock-bottom {
left: 0;
bottom: 0;
width: 100%;
}
.p-dock-bottom .p-dock-item {
transform-origin: center bottom;
}
/* right */
.p-dock-right {
right: 0;
top: 0;
height: 100%;
}
.p-dock-right .p-dock-item {
transform-origin: center right;
}
.p-dock-right .p-dock-list {
flex-direction: column;
}
/* left */
.p-dock-left {
left: 0;
top: 0;
height: 100%;
}
.p-dock-left .p-dock-item {
transform-origin: center left;
}
.p-dock-left .p-dock-list {
flex-direction: column;
}
`;
const classes = {
root: ({ props }) => ['p-dock p-component', `p-dock-${props.position}`, props.class],
container: 'p-dock-list-container',
menu: 'p-dock-list',
menuitem: ({ instance, processedItem, index, id }) => [
'p-dock-item',
{
'p-focus': instance.isItemActive(id),
'p-disabled': instance.disabled(processedItem),
'p-dock-item-second-prev': instance.currentIndex - 2 === index,
'p-dock-item-prev': instance.currentIndex - 1 === index,
'p-dock-item-current': instance.currentIndex === index,
'p-dock-item-next': instance.currentIndex + 1 === index,
'p-dock-item-second-next': instance.currentIndex + 2 === index
}
],
content: 'p-menuitem-content',
action: ({ props, isActive, isExactActive }) => [
'p-dock-link',
{
'router-link-active': isActive,
'router-link-active-exact': props.exact && isExactActive
}
],
icon: 'p-dock-icon'
};
const { load: loadStyle } = useStyle(styles, { id: 'primevue_dock_style', manual: true });
export default {
name: 'BaseDock',
extends: BaseComponent,
props: {
position: {
type: String,
default: 'bottom'
},
model: null,
class: null,
style: null,
tooltipOptions: null,
exact: {
type: Boolean,
default: true
},
menuId: {
type: String,
default: null
},
tabindex: {
type: Number,
default: 0
},
'aria-label': {
type: String,
default: null
},
'aria-labelledby': {
type: String,
default: null
}
},
css: {
classes,
loadStyle
},
provide() {
return {
$parentInstance: this
};
}
};
</script>

View File

@ -171,6 +171,11 @@ export interface DockProps {
* @type {DockPassThroughOptions} * @type {DockPassThroughOptions}
*/ */
pt?: DockPassThroughOptions; pt?: DockPassThroughOptions;
/**
* When enabled, it removes component related styles in the core.
* @defaultValue false
*/
unstyled?: boolean;
} }
/** /**

View File

@ -1,161 +1,18 @@
<template> <template>
<div :class="containerClass" :style="style" v-bind="ptm('root')"> <div :class="cx('root')" :style="style" v-bind="ptm('root')">
<DockSub :model="model" :templates="$slots" :exact="exact" :tooltipOptions="tooltipOptions" :position="position" :menuId="menuId" :aria-label="ariaLabel" :aria-labelledby="ariaLabelledby" :tabindex="tabindex" :pt="pt"></DockSub> <DockSub :model="model" :templates="$slots" :exact="exact" :tooltipOptions="tooltipOptions" :position="position" :menuId="menuId" :aria-label="ariaLabel" :aria-labelledby="ariaLabelledby" :tabindex="tabindex" :pt="pt"></DockSub>
</div> </div>
</template> </template>
<script> <script>
import BaseComponent from 'primevue/basecomponent'; import BaseDock from './BaseDock.vue';
import DockSub from './DockSub.vue'; import DockSub from './DockSub.vue';
export default { export default {
name: 'Dock', name: 'Dock',
extends: BaseComponent, extends: BaseDock,
props: {
position: {
type: String,
default: 'bottom'
},
model: null,
class: null,
style: null,
tooltipOptions: null,
exact: {
type: Boolean,
default: true
},
menuId: {
type: String,
default: null
},
tabindex: {
type: Number,
default: 0
},
'aria-label': {
type: String,
default: null
},
'aria-labelledby': {
type: String,
default: null
}
},
computed: {
containerClass() {
return ['p-dock p-component', `p-dock-${this.position}`, this.class];
}
},
components: { components: {
DockSub DockSub
} }
}; };
</script> </script>
<style>
.p-dock {
position: absolute;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
.p-dock-list-container {
display: flex;
pointer-events: auto;
}
.p-dock-list {
margin: 0;
padding: 0;
list-style: none;
display: flex;
align-items: center;
justify-content: center;
}
.p-dock-item {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
will-change: transform;
}
.p-dock-link {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
cursor: default;
}
.p-dock-item-second-prev,
.p-dock-item-second-next {
transform: scale(1.2);
}
.p-dock-item-prev,
.p-dock-item-next {
transform: scale(1.4);
}
.p-dock-item-current {
transform: scale(1.6);
z-index: 1;
}
/* Position */
/* top */
.p-dock-top {
left: 0;
top: 0;
width: 100%;
}
.p-dock-top .p-dock-item {
transform-origin: center top;
}
/* bottom */
.p-dock-bottom {
left: 0;
bottom: 0;
width: 100%;
}
.p-dock-bottom .p-dock-item {
transform-origin: center bottom;
}
/* right */
.p-dock-right {
right: 0;
top: 0;
height: 100%;
}
.p-dock-right .p-dock-item {
transform-origin: center right;
}
.p-dock-right .p-dock-list {
flex-direction: column;
}
/* left */
.p-dock-left {
left: 0;
top: 0;
height: 100%;
}
.p-dock-left .p-dock-item {
transform-origin: center left;
}
.p-dock-left .p-dock-list {
flex-direction: column;
}
</style>

View File

@ -1,9 +1,9 @@
<template> <template>
<div class="p-dock-list-container" v-bind="ptm('container')"> <div :class="cx('container')" v-bind="ptm('container')">
<ul <ul
ref="list" ref="list"
:id="id" :id="id"
class="p-dock-list" :class="cx('menu')"
role="menu" role="menu"
:aria-orientation="position === 'bottom' || position === 'top' ? 'horizontal' : 'vertical'" :aria-orientation="position === 'bottom' || position === 'top' ? 'horizontal' : 'vertical'"
:aria-activedescendant="focused ? focusedOptionId : undefined" :aria-activedescendant="focused ? focusedOptionId : undefined"
@ -19,21 +19,23 @@
<template v-for="(processedItem, index) of model" :key="index"> <template v-for="(processedItem, index) of model" :key="index">
<li <li
:id="getItemId(index)" :id="getItemId(index)"
:class="itemClass(processedItem, index, getItemId(index))" :class="cx('menuitem', { processedItem, index, id: getItemId(index) })"
role="menuitem" role="menuitem"
:aria-label="processedItem.label" :aria-label="processedItem.label"
:aria-disabled="disabled(processedItem)" :aria-disabled="disabled(processedItem)"
@click="onItemClick($event, processedItem)" @click="onItemClick($event, processedItem)"
@mouseenter="onItemMouseEnter(index)" @mouseenter="onItemMouseEnter(index)"
v-bind="getPTOptions(getItemId(index), 'menuitem')" v-bind="getPTOptions(getItemId(index), 'menuitem')"
:data-p-focused="isItemActive(getItemId(index))"
:data-p-disabled="disabled(processedItem) || false"
> >
<div class="p-menuitem-content" v-bind="getPTOptions(getItemId(index), 'content')"> <div :class="cx('content')" v-bind="getPTOptions(getItemId(index), 'content')">
<template v-if="!templates['item']"> <template v-if="!templates['item']">
<router-link v-if="processedItem.to && !disabled(processedItem)" v-slot="{ navigate, href, isActive, isExactActive }" :to="processedItem.to" custom> <router-link v-if="processedItem.to && !disabled(processedItem)" v-slot="{ navigate, href, isActive, isExactActive }" :to="processedItem.to" custom>
<a <a
v-tooltip:[tooltipOptions]="{ value: processedItem.label, disabled: !tooltipOptions }" v-tooltip:[tooltipOptions]="{ value: processedItem.label, disabled: !tooltipOptions }"
:href="href" :href="href"
:class="linkClass({ isActive, isExactActive })" :class="cx('action', { isActive, isExactActive })"
:target="processedItem.target" :target="processedItem.target"
tabindex="-1" tabindex="-1"
aria-hidden="true" aria-hidden="true"
@ -41,25 +43,25 @@
v-bind="getPTOptions(getItemId(index), 'action')" v-bind="getPTOptions(getItemId(index), 'action')"
> >
<template v-if="!templates['icon']"> <template v-if="!templates['icon']">
<span v-ripple :class="['p-dock-icon', processedItem.icon]" v-bind="getPTOptions(getItemId(index), 'icon')"></span> <span v-ripple :class="[cx('icon'), processedItem.icon]" v-bind="getPTOptions(getItemId(index), 'icon')"></span>
</template> </template>
<component v-else :is="templates['icon']" :item="processedItem"></component> <component v-else :is="templates['icon']" :item="processedItem" :class="cx('icon')"></component>
</a> </a>
</router-link> </router-link>
<a <a
v-else v-else
v-tooltip:[tooltipOptions]="{ value: processedItem.label, disabled: !tooltipOptions }" v-tooltip:[tooltipOptions]="{ value: processedItem.label, disabled: !tooltipOptions }"
:href="processedItem.url" :href="processedItem.url"
:class="linkClass()" :class="cx('action')"
:target="processedItem.target" :target="processedItem.target"
tabindex="-1" tabindex="-1"
aria-hidden="true" aria-hidden="true"
v-bind="getPTOptions(getItemId(index), 'action')" v-bind="getPTOptions(getItemId(index), 'action')"
> >
<template v-if="!templates['icon']"> <template v-if="!templates['icon']">
<span v-ripple :class="['p-dock-icon', processedItem.icon]" v-bind="getPTOptions(getItemId(index), 'icon')"></span> <span v-ripple :class="[cx('icon'), processedItem.icon]" v-bind="getPTOptions(getItemId(index), 'icon')"></span>
</template> </template>
<component v-else :is="templates['icon']" :item="processedItem"></component> <component v-else :is="templates['icon']" :item="processedItem" :class="cx('icon')"></component>
</a> </a>
</template> </template>
<component v-else :is="templates['item']" :item="processedItem" :index="index"></component> <component v-else :is="templates['item']" :item="processedItem" :index="index"></component>
@ -146,7 +148,7 @@ export default {
}); });
}, },
isSameMenuItem(event) { isSameMenuItem(event) {
return event.currentTarget && (event.currentTarget.isSameNode(event.target) || event.currentTarget.isSameNode(event.target.closest('.p-menuitem'))); return event.currentTarget && (event.currentTarget.isSameNode(event.target) || event.currentTarget.isSameNode(event.target.closest('[data-pc-section="menuitem"]')));
}, },
isItemActive(id) { isItemActive(id) {
return id === this.focusedOptionIndex; return id === this.focusedOptionIndex;
@ -241,56 +243,33 @@ export default {
this.changeFocusedOptionIndex(0); this.changeFocusedOptionIndex(0);
}, },
onEndKey() { onEndKey() {
this.changeFocusedOptionIndex(DomHandler.find(this.$refs.list, 'li.p-dock-item:not(.p-disabled)').length - 1); this.changeFocusedOptionIndex(DomHandler.find(this.$refs.list, 'li[data-pc-section="menuitem"][data-p-disabled="false"]').length - 1);
}, },
onSpaceKey() { onSpaceKey() {
const element = DomHandler.findSingle(this.$refs.list, `li[id="${`${this.focusedOptionIndex}`}"]`); const element = DomHandler.findSingle(this.$refs.list, `li[id="${`${this.focusedOptionIndex}`}"]`);
const anchorElement = element && DomHandler.findSingle(element, '.p-dock-link'); const anchorElement = element && DomHandler.findSingle(element, '[data-pc-section="action"]');
anchorElement ? anchorElement.click() : element && element.click(); anchorElement ? anchorElement.click() : element && element.click();
}, },
findNextOptionIndex(index) { findNextOptionIndex(index) {
const menuitems = DomHandler.find(this.$refs.list, 'li.p-dock-item:not(.p-disabled)'); const menuitems = DomHandler.find(this.$refs.list, 'li[data-pc-section="menuitem"][data-p-disabled="false"]');
const matchedOptionIndex = [...menuitems].findIndex((link) => link.id === index); const matchedOptionIndex = [...menuitems].findIndex((link) => link.id === index);
return matchedOptionIndex > -1 ? matchedOptionIndex + 1 : 0; return matchedOptionIndex > -1 ? matchedOptionIndex + 1 : 0;
}, },
findPrevOptionIndex(index) { findPrevOptionIndex(index) {
const menuitems = DomHandler.find(this.$refs.list, 'li.p-dock-item:not(.p-disabled)'); const menuitems = DomHandler.find(this.$refs.list, 'li[data-pc-section="menuitem"][data-p-disabled="false"]');
const matchedOptionIndex = [...menuitems].findIndex((link) => link.id === index); const matchedOptionIndex = [...menuitems].findIndex((link) => link.id === index);
return matchedOptionIndex > -1 ? matchedOptionIndex - 1 : 0; return matchedOptionIndex > -1 ? matchedOptionIndex - 1 : 0;
}, },
changeFocusedOptionIndex(index) { changeFocusedOptionIndex(index) {
const menuitems = DomHandler.find(this.$refs.list, 'li.p-dock-item:not(.p-disabled)'); const menuitems = DomHandler.find(this.$refs.list, 'li[data-pc-section="menuitem"][data-p-disabled="false"]');
let order = index >= menuitems.length ? menuitems.length - 1 : index < 0 ? 0 : index; let order = index >= menuitems.length ? menuitems.length - 1 : index < 0 ? 0 : index;
this.focusedOptionIndex = menuitems[order].getAttribute('id'); this.focusedOptionIndex = menuitems[order].getAttribute('id');
}, },
itemClass(item, index, id) {
return [
'p-dock-item',
{
'p-focus': this.isItemActive(id),
'p-disabled': this.disabled(item),
'p-dock-item-second-prev': this.currentIndex - 2 === index,
'p-dock-item-prev': this.currentIndex - 1 === index,
'p-dock-item-current': this.currentIndex === index,
'p-dock-item-next': this.currentIndex + 1 === index,
'p-dock-item-second-next': this.currentIndex + 2 === index
}
];
},
linkClass(routerProps) {
return [
'p-dock-link',
{
'router-link-active': routerProps && routerProps.isActive,
'router-link-active-exact': this.exact && routerProps && routerProps.isExactActive
}
];
},
disabled(item) { disabled(item) {
return typeof item.disabled === 'function' ? item.disabled() : item.disabled; return typeof item.disabled === 'function' ? item.disabled() : item.disabled;
} }