mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
1654a2681f
Summary: This moves all client code to core, and makes minimal fix-ups to get grist and grist-core to compile correctly. The client works in core, but I'm leaving clean-up around the build and bundles to follow-up. Test Plan: existing tests pass; server-dev bundle looks sane Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2627
81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
/**
|
|
* This module implements tooltips of two kinds:
|
|
* - to be shown on hover, similar to the native "title" attribute (popweasel meant to provide
|
|
* that, but its machinery isn't really needed). TODO these aren't yet implemented.
|
|
* - to be shown briefly, as a transient notification next to some action element.
|
|
*/
|
|
|
|
import {prepareForTransition} from 'app/client/ui/transitions';
|
|
import {testId} from 'app/client/ui2018/cssVars';
|
|
import {dom, styled} from 'grainjs';
|
|
import Popper from 'popper.js';
|
|
|
|
interface ITipOptions {
|
|
// Where to place the tooltip relative to the reference element. Defaults to 'top'.
|
|
// See https://popper.js.org/docs/v1/#popperplacements--codeenumcode
|
|
placement?: Popper.Placement;
|
|
|
|
// When to remove the transient tooltip. Defaults to 2000ms.
|
|
timeoutMs?: number;
|
|
|
|
// When set, a tooltip will replace any previous tooltip with the same key.
|
|
key?: string;
|
|
}
|
|
|
|
// Map of open tooltips, mapping the key (from ITipOptions) to the cleanup function that removes
|
|
// the tooltip.
|
|
const openTooltips = new Map<string, () => void>();
|
|
|
|
export function showTransientTooltip(refElem: Element, text: string, options: ITipOptions = {}) {
|
|
const placement: Popper.Placement = options.placement || 'top';
|
|
const timeoutMs: number = options.timeoutMs || 2000;
|
|
const key = options.key;
|
|
|
|
// If we had a previous tooltip with the same key, clean it up.
|
|
if (key) { openTooltips.get(key)?.(); }
|
|
|
|
// Add the content element.
|
|
const content = cssTooltip({role: 'tooltip'}, text, testId(`transient-tooltip`));
|
|
document.body.appendChild(content);
|
|
|
|
// Create a popper for positioning the tooltip content relative to refElem.
|
|
const popperOptions: Popper.PopperOptions = {
|
|
modifiers: {preventOverflow: {boundariesElement: 'viewport'}},
|
|
placement,
|
|
};
|
|
const popper = new Popper(refElem, content, popperOptions);
|
|
|
|
// Fade in the content using transitions.
|
|
prepareForTransition(content, () => { content.style.opacity = '0'; });
|
|
content.style.opacity = '';
|
|
|
|
// Cleanup involves destroying the Popper instance, removing the element, etc.
|
|
function cleanup() {
|
|
popper.destroy();
|
|
dom.domDispose(content);
|
|
content.remove();
|
|
if (key) { openTooltips.delete(key); }
|
|
clearTimeout(timer);
|
|
}
|
|
const timer = setTimeout(cleanup, timeoutMs);
|
|
if (key) { openTooltips.set(key, cleanup); }
|
|
}
|
|
|
|
|
|
const cssTooltip = styled('div', `
|
|
position: absolute;
|
|
z-index: 5000; /* should be higher than a modal */
|
|
background-color: black;
|
|
border-radius: 3px;
|
|
box-shadow: 0 0 2px rgba(0,0,0,0.5);
|
|
text-align: center;
|
|
color: white;
|
|
width: auto;
|
|
font-family: sans-serif;
|
|
font-size: 10pt;
|
|
padding: 8px 16px;
|
|
margin: 4px;
|
|
opacity: 0.65;
|
|
transition: opacity 0.2s;
|
|
`);
|