Common

useAttentionPulse

Composable interno per la pulsazione di attenzione di un overlay, quando un'interazione non ha effetto e serve un'azione esplicita.

Composable interno — utilizzato da Dialog e ConfirmDialog sul click alla mask.

Introdotto nella 1.9.0 insieme ai dialoghi non dismissibili dal backdrop: il click sulla mask non chiude nulla, e senza riscontro visivo l'interfaccia sembra bloccata. Il composable gestisce la finestra temporale in cui applicare la classe dell'animazione.

Firma TypeScript

export function useAttentionPulse(durationMs?: number): UseAttentionPulseResult

export interface UseAttentionPulseResult {
  isPulsing: Ref<boolean>;
  pulse: () => void;
}

Parametri

ParametroTipoDescrizione
durationMsnumberDurata della pulsazione, allineata ai keyframes CSS (default: 320)

Valore di Ritorno

ProprietàTipoDescrizione
isPulsingRef<boolean>true mentre la pulsazione è in corso: applicare .hs-overlay-attention
pulse() => voidAvvia (o riavvia) la pulsazione

Esempio

<script setup lang="ts">
  import { useAttentionPulse } from '@/composables/common'

  const { isPulsing, pulse } = useAttentionPulse()

  const handleOverlayClick = (event: MouseEvent) => {
    if (event.target !== event.currentTarget) return
    emit('maskClick', event)
    if (props.dismissableMask) {
      requestClose('mask', event)
      return
    }
    pulse()
  }
</script>

<template>
  <div class="hs-modal-container" :class="{ 'hs-overlay-attention': isPulsing }" />
</template>

Animazione CSS

L'animazione vera è in CSS, sulla classe .hs-overlay-attention:

@keyframes hs-overlay-attention {
  0%   { scale: 1; }
  35%  { scale: 1.015; }
  70%  { scale: 0.995; }
  100% { scale: 1; }
}

Due scelte importanti:

  • agisce sulla proprietà scale, non su transform: quest'ultimo è occupato dal riposizionamento del dialogo trascinabile, che durante la pulsazione non deve saltare;
  • è disattivata sotto prefers-reduced-motion: reduce (WCAG 2.3.3).

Su click ripetuti la classe viene rimossa e riapplicata in due frame distinti, così i keyframes ripartono da capo: rimuoverla e riaggiungerla nello stesso tick non cambierebbe il DOM e l'animazione non si riavvierebbe.