@govbr-ds/webcomponents
Version:
Biblioteca de Web Components baseado no GovBR-DS
120 lines (119 loc) • 5.41 kB
JavaScript
/*!
* Construído por SERPRO
* © https://serpro.gov.br/ - MIT License.
*/
import { arrow, autoUpdate, computePosition, flip, hide, offset, shift } from "@floating-ui/dom";
/**
* FloatingUIManager é uma classe utilitária que gerencia o posicionamento de elementos flutuantes
* como tooltips ou popovers em relação a um elemento de disparo (trigger).
* Ela utiliza a biblioteca Floating UI para calcular posições e lidar com atualizações.
*/
export class FloatingUIManager {
triggerElement;
contentElement;
arrowElement;
placement;
onUpdate;
cleanupAutoUpdate;
constructor(options) {
this.triggerElement = options.triggerElement;
this.contentElement = options.contentElement;
this.arrowElement = options.arrowElement;
this.placement = options.placement ?? 'top';
this.onUpdate = options.onUpdate;
}
/**
* Inicia o gerenciador Floating UI configurando a atualização automática da posição.
*/
start() {
this.cleanupAutoUpdate = autoUpdate(this.triggerElement, this.contentElement, () => this.updatePosition());
}
/**
* Para o gerenciador Floating UI e limpa os recursos utilizados.
*/
stop() {
this.cleanupAutoUpdate?.();
}
/**
* Atualiza a posição do elemento flutuante com base no elemento disparador e no elemento de conteúdo.
* Esta função é chamada automaticamente quando o gerenciador está ativo.
* Ela calcula a nova posição usando a biblioteca Floating UI e aplica as transformações necessárias.
* Também atualiza a posição da seta, se fornecida.
* Além disso, define o atributo de dados `data-placement` no elemento de conteúdo para refletir a posição atual.
* @returns {Promise<void>} Uma promessa que resolve quando a posição é atualizada.
*/
async updatePosition() {
const data = await computePosition(this.triggerElement, this.contentElement, {
placement: this.placement,
middleware: this.buildMiddleware(),
});
this.updateTooltipPosition(data);
this.updateArrowPosition(data);
this.setPlacementDataAttribute(data);
this.onUpdate?.(data);
}
/**
* Constrói os middlewares necessários para o Floating UI.
* Esses middlewares são usados para ajustar o posicionamento do elemento flutuante,
* incluindo offset, flip, shift e hide. Se uma seta for fornecida, o middleware de seta também é adicionado.
* @returns {Middleware[]} Retorna um array de middlewares configurados para o Floating UI.
*/
buildMiddleware() {
const middleware = [offset(8), flip(), shift({ padding: 5 }), hide()];
if (this.arrowElement != null) {
middleware.push(arrow({ element: this.arrowElement }));
}
return middleware;
}
/**
* Adiciona o estilo necessário para posicionar o tooltip com base nas coordenadas fornecidas.
* Esta função é chamada após o cálculo da posição do tooltip.
* Ela aplica as propriedades CSS `left` e `top` ao elemento de conteúdo do tooltip.
* @param data Contém as coordenadas x e y para posicionar o tooltip.
*/
updateTooltipPosition(data) {
const { x, y } = data;
Object.assign(this.contentElement.style, {
left: `${x}px`,
top: `${y}px`,
});
}
/**
* Adiciona o estilo necessário para posicionar a seta do tooltip com base nos dados de middleware.
* Esta função é chamada após o cálculo da posição do tooltip.
* Ela aplica as propriedades CSS `left`, `top`, `right`, `bottom` e a posição estática da seta.
* A posição estática é determinada com base na colocação do tooltip (top, right, bottom, left).
* Se a seta não estiver presente ou os dados de middleware não contiverem informações sobre a seta, nada será feito.
* @param data Contém a posição da seta e os dados de middleware.
*/
updateArrowPosition(data) {
if (this.arrowElement == null || data.middlewareData.arrow == null)
return;
const { x: arrowX, y: arrowY } = data.middlewareData.arrow;
const basePlacement = data.placement.split('-')[0];
const staticSide = {
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[basePlacement];
Object.assign(this.arrowElement.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : '',
right: '',
bottom: '',
[staticSide]: '-4px',
});
}
/**
* Define o atributo de dados `data-placement` no elemento de conteúdo.
* Este atributo é usado para indicar a posição atual do tooltip ou popover.
* Ele é útil para fins de acessibilidade e para permitir que estilos CSS sejam aplicados com base na posição.
* @param data Objeto contendo a propriedade `placement` que define a posição do tooltip ou popover.
* A propriedade `placement` deve ser uma string representando a posição, como 'top', 'bottom', 'left', 'right', etc.
*/
setPlacementDataAttribute(data) {
this.contentElement.setAttribute('data-placement', data.placement);
}
}
//# sourceMappingURL=floating-ui.js.map