Fix tooltip overflow on smaller screens

This commit addresses three main issues related to tooltips on devices
with smaller screens:

1. Fix tooltip overflow: On mobile devices, tooltips associated with
   script selection options (None, Standard, Strict, All) were
   overflowing due to inherited `white-space: nowrap` styling. This
   styling caused tooltips to render beyond screen limits. The fix
   involves applying `white-space: initial` to the tooltip overlay,
   preventing this style propagation and resolving the overflow issue.
2. Corrects tooltip arrow placement: Previously, when tooltips shifted
   from their default top position to the bottom on smaller screens,
   their arrows did not reposition accordingly. This issue was caused by
   using an incorrect reference for tooltip placement calculation. By
   updating the reference used to the one from `useFloating` function,
   the tooltip arrow now correctly aligns with the adjusted position.
3. Uniform margin handling: Enhances the margin settings around tooltips
   to maintain a consistent gap between the tooltip and the document
   edges, visible particularly on smaller screens.

Additionaly, the `DevToolkit` component has been improved for easier
testing. It is now non-interactable (except for its buttons) to prevent
it from getting in the way when testing on smaller screens. A new close
button has been added, allowing developers/testers to completely hide
the DevToolkit if desired.
This commit is contained in:
undergroundwires
2023-12-10 19:53:19 +01:00
parent 47b4823bc5
commit 916c9d62d9
2 changed files with 106 additions and 25 deletions

View File

@@ -1,28 +1,44 @@
<template>
<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>
</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',
@@ -32,8 +48,15 @@ export default defineComponent({
},
},
];
function close() {
isOpen.value = false;
}
return {
devActions,
isOpen,
close,
};
},
});
@@ -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;
@@ -56,19 +79,59 @@ 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;
hr {
width: 100%;
}
.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>

View File

@@ -13,6 +13,7 @@
<div class="tooltip__overlay">
<div
ref="tooltipDisplayElement"
class="tooltip__display"
:style="displayStyles"
>
<div class="tooltip__content">
@@ -38,28 +39,26 @@ import type { CSSProperties } from 'vue';
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. */
shift({
padding: MARGIN_FROM_DOCUMENT_EDGE_IN_PX,
}),
shift(),
/* Changes the placement of the floating element in order to keep it in view,
with the ability to flip to any placement. */
flip(),
@@ -68,6 +67,7 @@ export default defineComponent({
whileElementsMounted: autoUpdate,
},
);
const arrowStyles = computed<CSSProperties>(() => {
if (!middlewareData.value.arrow) {
return {
@@ -129,6 +129,7 @@ function getCounterpartBoxOffsetProperty(placement: Placement): keyof CSSPropert
</script>
<style scoped lang="scss">
@use 'sass:math';
@use "@/presentation/assets/styles/main" as *;
$color-tooltip-background: $color-primary-darkest;
@@ -146,14 +147,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;
}
}
@@ -175,10 +176,12 @@ $color-tooltip-background: $color-primary-darkest;
- Causes screen shaking on Chromium browsers.
*/
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
overflow: hidden;
> * { // Restore styles in children
@@ -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 to prevent inheriting styles from the trigger element.
This prevents unintentional layout issues or overflow.
*/
white-space: normal;
}
.tooltip__trigger {
@include hover-or-touch {
+ .tooltip__overlay {
z-index: 10000;
@include set-visibility(true);
z-index: 10000;
}
}
}
@@ -206,6 +215,15 @@ $color-tooltip-background: $color-primary-darkest;
color: $color-on-primary;
border-radius: 16px;
padding: 5px 10px 4px;
/*
This margin creates a visual buffer between the tooltip and the edges of the document.
It prevents the tooltip from appearing too close to the edges, ensuring a visually pleasing
and balanced layout.
Avoiding setting vertical margin as it disrupts the arrow rendering.
*/
margin-left: 2px;
margin-right: 2px;
}
.tooltip__arrow {