Skip to content

Commit

Permalink
Fix tooltips go offscreen and arrowless on mobile
Browse files Browse the repository at this point in the history
- Fix tooltip overflowing when hovering on script selection options
  (None, Standard, Strict, All) on UI. This issue was caused because
  these options had `white-space: nowrap` so they're rendered together.
  However, as tooltips are rendered inside of the same DOM element with
  their triggering elements, this style was propagated and caused
  overflow content to overflow on smaller screens. This commit adds
  `white-space: initial` on tooltip overlay/container to stop the
  propogation and fix the issue.
- Fix overflow issue revealed another issue with tooltip arrow
  rendering. When tooltip is shifted from its default position (top) to
  bottom on smaller screens when there are not enough space on top, the
  tooltip arrow did not change its position and still stayed on bottom.
  This was caused because of using wrong reference to get current
  placement of the tooltip. The issue is fixed by using the reference
  from `useFloating` function.
- Improve `DevToolkit` component to be less intrusive during tests. The
  DevToolkit is now non-interactable except its buttons for easier
  testing of tooltips on smaller screens. A new close button is also
  added on the box, so it can be closed completely if desired.
  • Loading branch information
undergroundwires committed Dec 10, 2023
1 parent 47b4823 commit 2cf3a13
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 21 deletions.
89 changes: 74 additions & 15 deletions src/presentation/components/DevToolkit/DevToolkit.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,44 @@
<template>
<div class="dev-toolkit">
<div class="title">
Tools
<div v-if="isOpen" class="dev-toolkit-container">
<div class="dev-toolkit">
<div class="toolkit-header">
<div class="title">
Tools
</div>
<button type="button" class="close-button" @click="close">
<AppIcon icon="xmark" />
</button>
</div>
<hr />
<div class="action-buttons">
<button
v-for="action in devActions"
:key="action.name"
type="button"
class="action-button"
@click="action.handler"
>
{{ action.name }}
</button>
</div>
</div>
<hr />
<button
v-for="action in devActions"
:key="action.name"
type="button"
@click="action.handler"
>
{{ action.name }}
</button>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, ref } from 'vue';
import { injectKey } from '@/presentation/injectionSymbols';
import AppIcon from '@/presentation/components/Shared/Icon/AppIcon.vue';
import { dumpNames } from './DumpNames';
export default defineComponent({
components: {
AppIcon,
},
setup() {
const { log } = injectKey((keys) => keys.useLogger);
const isOpen = ref(true);
const devActions: readonly DevAction[] = [
{
name: 'Log script/category names',
Expand All @@ -32,8 +48,15 @@ export default defineComponent({
},
},
];
function close() {
isOpen.value = false;
}
return {
devActions,
isOpen,
close,
};
},
});
Expand All @@ -47,7 +70,7 @@ interface DevAction {
<style scoped lang="scss">
@use "@/presentation/assets/styles/main" as *;
.dev-toolkit {
.dev-toolkit-container {
position: fixed;
top: 0;
right: 0;
Expand All @@ -56,19 +79,55 @@ interface DevAction {
padding: 10px;
z-index: 10000;
display:flex;
flex-direction: column;
/* Minimize interaction, so it does not interfere with events targeting elements behind it to allow easier tests */
pointer-events: none;
* > button {
pointer-events: initial;
}
}
.dev-toolkit {
display:flex;
flex-direction: column;
.toolkit-header {
display:flex;
flex-direction: row;
align-items: center;
.title {
flex: 1;
}
.close-button {
flex-shrink: 0;
}
}
.title {
font-weight: bold;
text-align: center;
}
.action-buttons {
display: flex;
flex-direction: column;
gap: 10px;
}
button {
display: block;
margin-bottom: 10px;
padding: 5px 10px;
background-color: $color-primary;
color: $color-on-primary;
border: none;
cursor: pointer;
@include hover-or-touch {
background-color: $color-secondary;
color: $color-on-secondary;
}
}
}
</style>
21 changes: 15 additions & 6 deletions src/presentation/components/Shared/TooltipWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<div class="tooltip__overlay">
<div
ref="tooltipDisplayElement"
class="tooltip__display"
:style="displayStyles"
>
<div class="tooltip__content">
Expand Down Expand Up @@ -40,20 +41,21 @@ const GAP_BETWEEN_TOOLTIP_AND_TRIGGER_IN_PX = 2;
const ARROW_SIZE_IN_PX = 4;
const MARGIN_FROM_DOCUMENT_EDGE_IN_PX = 2;
const DEFAULT_PLACEMENT: Placement = 'top';
export default defineComponent({
setup() {
const tooltipDisplayElement = shallowRef<HTMLElement | undefined>();
const triggeringElement = shallowRef<HTMLElement | undefined>();
const arrowElement = shallowRef<HTMLElement | undefined>();
const placement = shallowRef<Placement>('top');
useResizeObserverPolyfill();
const { floatingStyles, middlewareData } = useFloating(
const { floatingStyles, middlewareData, placement } = useFloating(
triggeringElement,
tooltipDisplayElement,
{
placement,
placement: DEFAULT_PLACEMENT,
middleware: [
offset(ARROW_SIZE_IN_PX + GAP_BETWEEN_TOOLTIP_AND_TRIGGER_IN_PX),
/* Shifts the element along the specified axes in order to keep it in view. */
Expand All @@ -68,6 +70,7 @@ export default defineComponent({
whileElementsMounted: autoUpdate,
},
);
const arrowStyles = computed<CSSProperties>(() => {
if (!middlewareData.value.arrow) {
return {
Expand Down Expand Up @@ -146,14 +149,14 @@ $color-tooltip-background: $color-primary-darkest;
- Using the `display` property doesn't support smooth transitions (e.g., fading out).
- Keeping invisible tooltips in the DOM is a best practice for accessibility (screen readers).
*/
$animation-duration: 0.5s;
transition: opacity $animation-duration, visibility $animation-duration;
@if $isVisible {
visibility: visible;
opacity: 1;
transition: opacity .15s, visibility .15s;
} @else {
visibility: hidden;
opacity: 0;
transition: opacity .15s, visibility .15s;
}
}
Expand Down Expand Up @@ -190,13 +193,19 @@ $color-tooltip-background: $color-primary-darkest;
.tooltip__overlay {
@include set-visibility(false);
@include fixed-fullscreen;
/*
Reset white-space to the default value.
This avoids inheriting white-space styles from the trigger element, which may unintentionally cause layout issues or overflow in the tooltip.
*/
white-space: initial;
}
.tooltip__trigger {
@include hover-or-touch {
+ .tooltip__overlay {
z-index: 10000;
@include set-visibility(true);
z-index: 10000;
}
}
}
Expand Down

0 comments on commit 2cf3a13

Please sign in to comment.