Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(popover, hovercard): DLT-2245 separate Hovercard from Popover #606

Merged
merged 4 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions packages/dialtone-vue2/components/hovercard/hovercard.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<!-- eslint-disable vue/multi-word-component-names -->
<template>
<dt-popover
:id="id"
:open="hovercardOpen"
:placement="placement"
:content-class="contentClass"
:dialog-class="dialogClass"
:fallback-placements="fallbackPlacements"
:padding="padding"
:transition="transition ? 'fade' : null"
Expand All @@ -13,12 +14,14 @@
:header-class="headerClass"
:footer-class="footerClass"
:append-to="appendTo"
:hovercard="true"
data-qa="dt-hovercard"
:open="open"
:enter-delay="enterDelay"
:leave-delay="leaveDelay"
@opened="(e) => ($emit('opened', e))"
@mouseenter-popover="onMouseEnter"
@mouseleave-popover="onMouseLeave"
@mouseenter-popover-anchor="onMouseEnter"
@mouseleave-popover-anchor="onMouseLeave"
>
<template #anchor="{ attrs }">
<slot
Expand Down Expand Up @@ -206,5 +209,51 @@ export default {
*/
'opened',
],

data () {
return {
hovercardOpen: this.open,
inTimer: null,
outTimer: null,
};
},

watch: {
open: {
handler: function (open) {
this.hovercardOpen = open;
},

immediate: true,
},
},

methods: {
setInTimer () {
this.inTimer = setTimeout(() => {
this.hovercardOpen = true;
}, this.enterDelay);
},

setOutTimer () {
this.outTimer = setTimeout(() => {
this.hovercardOpen = false;
}, this.leaveDelay);
},

onMouseEnter () {
if (this.open === null) {
clearTimeout(this.outTimer);
this.setInTimer();
}
},

onMouseLeave () {
if (this.open === null) {
clearTimeout(this.inTimer);
this.setOutTimer();
}
},
},
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
:time="data.time"
:is-active="true"
:state="$attrs.state"
@hover="$attrs.onHover"
@focus="$attrs.onFocus"
>
<template #avatar>
<dt-hovercard
Expand Down
103 changes: 40 additions & 63 deletions packages/dialtone-vue2/components/popover/popover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
@keydown.up.prevent="onArrowKeyPress"
@keydown.down.prevent="onArrowKeyPress"
@keydown.escape.capture="closePopover"
@mouseenter="openHovercard"
@mouseleave="closeHovercard"
@mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
>
<!-- @slot Anchor element that activates the popover. Usually a button. -->
<slot
Expand Down Expand Up @@ -58,8 +58,8 @@
:tabindex="contentTabindex"
appear
v-on="popoverListeners"
@mouseenter="openHovercard"
@mouseleave="closeHovercard"
@mouseenter="onMouseEnterAnchor"
@mouseleave="onMouseLeaveAnchor"
>
<popover-header-footer
v-if="$slots.headerContent || showCloseButton"
Expand Down Expand Up @@ -138,7 +138,6 @@ import { createTippyPopover, getPopperOptions } from './tippy_utils';
import PopoverHeaderFooter from './popover_header_footer.vue';
import SrOnlyCloseButtonMixin from '@/common/mixins/sr_only_close_button';
import SrOnlyCloseButton from '@/common/sr_only_close_button.vue';
import { TOOLTIP_DELAY_MS } from '@/components/tooltip/index.js';

/**
* A Popover displays a content overlay when its anchor element is activated.
Expand Down Expand Up @@ -504,33 +503,6 @@ export default {
(appendTo instanceof HTMLElement);
},
},

/**
* Set this prop to true and popover component will support hovercard behaviour
* It will open on mouseenter and close on mouseleave with timer delay of 300ms
*/
hovercard: {
type: Boolean,
default: false,
},

/**
* The enter delay in milliseconds before the hovercard is shown.
* @type number
*/
enterDelay: {
type: Number,
default: TOOLTIP_DELAY_MS,
},

/**
* The leave delay in milliseconds before the hovercard is hidden.
* @type number
*/
leaveDelay: {
type: Number,
default: TOOLTIP_DELAY_MS,
},
},

emits: [
Expand All @@ -549,6 +521,34 @@ export default {
* @type {Boolean | Array}
*/
'update:open',

/**
* Emitted when the mouse enters the popover
*
* @event mouseenter-popover
*/
'mouseenter-popover',

/**
* Emitted when the mouse leaves the popover
*
* @event mouseleave-popover
*/
'mouseleave-popover',

/**
* Emitted when the mouse enters the popover anchor
*
* @event mouseenter-popover-anchor
*/
'mouseenter-popover-anchor',

/**
* Emitted when the mouse leaves the popover anchor
*
* @event mouseleave-popover-anchor
*/
'mouseleave-popover-anchor',
],

data () {
Expand All @@ -560,8 +560,6 @@ export default {
isOpen: false,
anchorEl: null,
popoverContentEl: null,
inTimer: null,
outTimer: null,
};
},

Expand Down Expand Up @@ -735,7 +733,6 @@ export default {
},

defaultToggleOpen (e) {
if (this.hovercard) { return; }
if (this.openOnContext) { return; }

// Only use default toggle behaviour if the user has not set the open prop.
Expand Down Expand Up @@ -1012,41 +1009,21 @@ export default {
});
},

// ============================================================================
// $ HOVERCARD
// ----------------------------------------------------------------------------

setInTimer () {
this.inTimer = setTimeout(() => {
this.isOpen = true;
}, this.enterDelay);
onMouseEnter () {
this.$emit('mouseenter-popover');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the event be called "mouseenter-popover-anchor" since there could also be the case of the mouse entering the popover dialog?

},

setOutTimer () {
this.outTimer = setTimeout(() => {
this.isOpen = false;
}, this.leaveDelay);
onMouseLeave () {
this.$emit('mouseleave-popover');
},

openHovercard () {
if (!this.hovercard) return;
if (this.open === null || this.open === undefined) {
clearTimeout(this.outTimer);
this.setInTimer();
}
onMouseEnterAnchor () {
this.$emit('mouseenter-popover-anchor');
},

closeHovercard () {
if (!this.hovercard) return;
if (this.open === null || this.open === undefined) {
clearTimeout(this.inTimer);
this.setOutTimer();
}
onMouseLeaveAnchor () {
this.$emit('mouseleave-popover-anchor');
},

// ============================================================================
// $ HOVERCARD
// ----------------------------------------------------------------------------
},
};
</script>
77 changes: 58 additions & 19 deletions packages/dialtone-vue3/components/hovercard/hovercard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
<template>
<dt-popover
:id="id"
:open="hovercardOpen"
:placement="placement"
:content-class="contentClass"
:dialog-class="dialogClass"
:fallback-placements="fallbackPlacements"
:padding="padding"
:transition="transition ? 'fade' : null"
Expand All @@ -13,12 +15,14 @@
:header-class="headerClass"
:footer-class="footerClass"
:append-to="appendTo"
:hovercard="true"
data-qa="dt-hovercard"
:open="open"
:enter-delay="enterDelay"
:leave-delay="leaveDelay"
@opened="(e) => ($emit('opened', e))"
@mouseenter-popover="onMouseEnter"
@mouseleave-popover="onMouseLeave"
@mouseenter-popover-anchor="onMouseEnter"
@mouseleave-popover-anchor="onMouseLeave"
>
<template #anchor="{ attrs }">
<!-- @slot Anchor element that activates the hovercard. Usually a button. -->
Expand All @@ -44,11 +48,12 @@
</template>

<script setup>
import { ref, watch } from 'vue';
import { POPOVER_APPEND_TO_VALUES, POPOVER_PADDING_CLASSES, DtPopover } from '@/components/popover/index.js';
import { TOOLTIP_DIRECTIONS, TOOLTIP_DELAY_MS } from '@/components/tooltip/index.js';
import { getUniqueString } from '@/common/utils';

defineProps({
const props = defineProps({
/**
* Fade transition when the content display is toggled.
* @type boolean
Expand Down Expand Up @@ -173,24 +178,24 @@ defineProps({
return POPOVER_APPEND_TO_VALUES.includes(appendTo) ||
(appendTo instanceof HTMLElement);
},
},

/**
* The enter delay in milliseconds before the hovercard is shown.
* @type number
*/
enterDelay: {
type: Number,
default: TOOLTIP_DELAY_MS,
},
/**
* The enter delay in milliseconds before the hovercard is shown.
* @type number
*/
enterDelay: {
type: Number,
default: TOOLTIP_DELAY_MS,
},

/**
* The leave delay in milliseconds before the hovercard is hidden.
* @type number
*/
leaveDelay: {
type: Number,
default: TOOLTIP_DELAY_MS,
},
/**
* The leave delay in milliseconds before the hovercard is hidden.
* @type number
*/
leaveDelay: {
type: Number,
default: TOOLTIP_DELAY_MS,
},
});

Expand All @@ -203,4 +208,38 @@ defineEmits([
*/
'opened',
]);

const hovercardOpen = ref(props.open);
const inTimer = ref(null);
const outTimer = ref(null);

watch(() => props.open, (open) => {
hovercardOpen.value = open;
}, { immediate: true });

function setInTimer () {
inTimer.value = setTimeout(() => {
hovercardOpen.value = true;
}, props.enterDelay);
}

function setOutTimer () {
outTimer.value = setTimeout(() => {
hovercardOpen.value = false;
}, props.leaveDelay);
}

function onMouseEnter () {
if (props.open === null) {
clearTimeout(outTimer.value);
setInTimer();
}
}

function onMouseLeave () {
if (props.open === null) {
clearTimeout(inTimer.value);
setOutTimer();
}
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
:time="data.time"
:is-active="true"
:state="$attrs.state"
@hover="$attrs.onHover"
@focus="$attrs.onFocus"
>
<template #avatar>
<dt-hovercard
Expand Down
Loading
Loading