-
Notifications
You must be signed in to change notification settings - Fork 204
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add source and provider definition tooltips (#3407)
* Add source and provider definition Signed-off-by: Olga Bulat <[email protected]> * Add suggestions from code review Signed-off-by: Olga Bulat <[email protected]> * Rename describedBy Signed-off-by: Olga Bulat <[email protected]> --------- Signed-off-by: Olga Bulat <[email protected]>
- Loading branch information
Showing
10 changed files
with
293 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
frontend/src/components/VMediaInfo/VSourceProviderTooltip.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
<template> | ||
<dt> | ||
{{ $t(datum.label) }} | ||
<VTooltip placement="top" :described-by="describedBy" class="ms-1"> | ||
<template #default> | ||
<p | ||
class="caption-regular rounded-sm bg-dark-charcoal px-2 py-1 text-white" | ||
> | ||
{{ description }} | ||
</p> | ||
</template> | ||
</VTooltip> | ||
</dt> | ||
</template> | ||
<script lang="ts"> | ||
import { computed, defineComponent, PropType } from "vue" | ||
import { Metadata } from "~/types/media" | ||
import { useI18n } from "~/composables/use-i18n" | ||
import VTooltip from "~/components/VTooltip/VTooltip.vue" | ||
export default defineComponent({ | ||
name: "VSourceProviderTooltip", | ||
components: { VTooltip }, | ||
props: { | ||
datum: { | ||
type: Object as PropType<Metadata>, | ||
required: true, | ||
}, | ||
describedBy: { | ||
type: String, | ||
required: true, | ||
}, | ||
}, | ||
setup(props) { | ||
const i18n = useI18n() | ||
const description = computed(() => { | ||
if (!props.datum.name) { | ||
return "" | ||
} | ||
return i18n.t( | ||
props.datum.name === "source" | ||
? "mediaDetails.sourceDescription" | ||
: "mediaDetails.providerDescription" | ||
) | ||
}) | ||
return { | ||
description, | ||
} | ||
}, | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
<template> | ||
<div> | ||
<!-- re: disabled static element interactions rule https://github.com/WordPress/openverse/issues/2906 --> | ||
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events, vuejs-accessibility/no-static-element-interactions --> | ||
<div | ||
ref="triggerContainerRef" | ||
class="flex w-min items-stretch whitespace-nowrap" | ||
@keydown.esc="handleEscape" | ||
> | ||
<!-- | ||
@slot The trigger, should be a button 99.99% of the time. If you need custom event handling on the trigger button, ensure bubbling is not prevented or else the tooltip will not open | ||
@binding {object} a11yProps | ||
@binding {boolean} visible | ||
--> | ||
<slot name="trigger" :open="open"> | ||
<VIconButton | ||
:label="describedBy" | ||
:aria-describedby="describedBy" | ||
variant="bordered-white" | ||
size="disabled" | ||
class="h-4 w-4 hover:!border-tx" | ||
:icon-props="{ name: 'info', size: 4 }" | ||
@click="open" | ||
/> | ||
</slot> | ||
</div> | ||
<div | ||
v-show="visibleRef" | ||
:id="describedBy" | ||
ref="tooltipRef" | ||
role="tooltip" | ||
:class="`z-${zIndex} w-max-content absolute left-0 top-0`" | ||
:style="{ ...style }" | ||
:aria-hidden="!visibleRef" | ||
> | ||
<slot /> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import { | ||
defineComponent, | ||
ref, | ||
PropType, | ||
watch, | ||
toRefs, | ||
onBeforeUnmount, | ||
} from "vue" | ||
import { zIndexValidator } from "~/constants/z-indices" | ||
import { useFloatingUi } from "~/composables/use-floating-ui" | ||
import { hasFocusWithin } from "~/utils/reakit-utils/focus" | ||
import VIconButton from "~/components/VIconButton/VIconButton.vue" | ||
import type { Placement, Strategy } from "@floating-ui/dom" | ||
export default defineComponent({ | ||
name: "VTooltip", | ||
components: { VIconButton }, | ||
props: { | ||
/** | ||
* The placement of the tooltip relative to the trigger. Should be one of the options | ||
* for `placement` passed to floating-ui. | ||
* | ||
* @see https://floating-ui.com/docs/tutorial#placements | ||
* | ||
* @default 'bottom' | ||
*/ | ||
placement: { | ||
type: String as PropType<Placement>, | ||
default: "bottom", | ||
}, | ||
/** | ||
* The positioning strategy of the tooltip. If your reference element is in a fixed container | ||
* use the fixed strategy; otherwise use the default, absolute strategy. | ||
* | ||
* @see https://floating-ui.com/docs/computeposition#strategy | ||
* | ||
* @default 'absolute' | ||
*/ | ||
strategy: { | ||
type: String as PropType<Strategy>, | ||
default: "absolute", | ||
}, | ||
/** | ||
* The id of the element labelling the popover content. | ||
* The owning element must have `aria-describedby` set to this value. | ||
*/ | ||
describedBy: { | ||
type: String, | ||
required: true, | ||
}, | ||
/** | ||
* the z-index to apply to the tooltip content | ||
*/ | ||
zIndex: { | ||
type: [Number, String], | ||
default: "popover", // named z-index | ||
validator: zIndexValidator, | ||
}, | ||
}, | ||
setup(props) { | ||
const visibleRef = ref(false) | ||
const triggerContainerRef = ref<HTMLElement | null>(null) | ||
const closeIfNeeded = () => { | ||
if (triggerRef.value && !hasFocusWithin(triggerRef.value)) { | ||
visibleRef.value = false | ||
} | ||
} | ||
const open = () => { | ||
visibleRef.value = true | ||
} | ||
const listeners = { | ||
mouseover: open, | ||
mouseout: closeIfNeeded, | ||
focus: open, | ||
blur: closeIfNeeded, | ||
} | ||
const setTrigger = (triggerElement: HTMLElement) => { | ||
triggerRef.value = triggerElement | ||
for (const [event, listener] of Object.entries(listeners)) { | ||
triggerElement.addEventListener(event, listener) | ||
} | ||
} | ||
const triggerRef = ref<HTMLElement | null>(null) | ||
watch(triggerContainerRef, (container) => { | ||
if (container) { | ||
setTrigger(container.firstElementChild as HTMLElement) | ||
} | ||
}) | ||
onBeforeUnmount(() => { | ||
if (triggerRef.value) { | ||
for (const [event, listener] of Object.entries(listeners)) { | ||
triggerRef.value.removeEventListener(event, listener) | ||
} | ||
} | ||
}) | ||
const tooltipRef = ref<HTMLElement | null>(null) | ||
const propsRefs = toRefs(props) | ||
const { style } = useFloatingUi({ | ||
floatingElRef: tooltipRef, | ||
floatingPropsRefs: { | ||
placement: propsRefs.placement, | ||
strategy: propsRefs.strategy, | ||
clippable: ref(false), | ||
visible: visibleRef, | ||
triggerElement: triggerRef, | ||
}, | ||
}) | ||
const handleEscape = () => { | ||
if (visibleRef.value) { | ||
visibleRef.value = false | ||
} | ||
} | ||
return { | ||
visibleRef, | ||
triggerContainerRef, | ||
triggerRef, | ||
tooltipRef, | ||
style, | ||
open, | ||
handleEscape, | ||
} | ||
}, | ||
}) | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.