@benjaminor-dev/quasar-app-extension-dialog-loader
v0.1.10
Published
Dialog loader for Quasar — global loading dialog via useDialogLoader()
Downloads
1,890
Maintainers
Readme
Dialog Loader para Quasar
🇺🇸 English | 🇪🇸 Versión en español
Extensão Quasar para diálogo modal de carregamento global em apps Vue 3 + Quasar, com API imperativa baseada em composable.
Índice
- Em 30 segundos
- O que é e o que inclui
- Requisitos e compatibilidade
- Instalação na app Quasar
- O que a extensão adiciona ao host
- Defaults globais (boot)
- Idioma (i18n)
- Uso rápido
- TypeScript no seu IDE
- API pública
- Variantes visuais
- Indicadores de carregamento (spinner)
- Anti-piscar e operações concorrentes
- Tipos TypeScript exportados
- Entrypoints públicos
- Troubleshooting
Em 30 segundos
Fluxo base recomendado:
- Instalar a extensão na sua app Quasar (
quasar ext add). - Garantir que o boot do Pinia do host roda antes do boot desta extensão.
- Importar
useDialogLoader()onde executar pedidos async. - Envolver a tarefa com
await loader.run({ task: () => api.save() })— ou{ label, task }para override pontual.
A extensão regista boots e CSS no projeto host automaticamente após quasar ext add.
O que é e o que inclui
Diálogo modal global controlado por useDialogLoader() — não é um componente embebível.
run({ task })ourun(task)— caso principal; usa o label do boot se não passarlabel.run({ label, task })— override pontual do texto sem alterar o boot.show()/hide()— controlo manual com contador interno de operações pendentes.- Três variantes de apresentação:
glass,primary,minimal. - Spinners configuráveis (subset curado do Quasar; default
ios). - Anti-piscar: delays de abertura/fecho e tempo mínimo visível.
- Defaults globais no boot do host (
gap,font, variant, spinner…); label por chamada opcional. - i18n built-in
en,es,pt— segue$q.langdo Quasar; overrides no boot (locale,messages). - Controlos em
task:pause,resume,cancelesignal(AbortSignal).
Requisitos e compatibilidade
| Item | Valor | | --- | --- | | Node | >= 20.0.0 | | Quasar | ^2.6.0 | | Vue | ^3.4.18 | | Pinia | ^2.0.11 | ^3.0.0 | | Formato do pacote | ES modules | | CLI recomendado | @quasar/app-vite ^2.x ou ^3.x |
O boot do Pinia do host deve executar-se antes do boot desta extensão.
Instalação na app Quasar
quasar ext add @benjaminor-dev/dialog-loaderRemover:
quasar ext remove @benjaminor-dev/dialog-loaderApós quasar ext add, a extensão regista boots e CSS na sua app automaticamente. Não precisa de passos adicionais numa instalação normal via npm.
O que a extensão adiciona ao host
Recursos instalados ou registados pela extensão:
| Recurso | Rota npm |
| --- | --- |
| Boot do diálogo | ~@benjaminor-dev/quasar-app-extension-dialog-loader/boot/dialog |
| Estilos | ~@benjaminor-dev/quasar-app-extension-dialog-loader/main.css |
| Defaults boot (host) | src/boot/bor/bor-dialog-loader-defaults.ts — criado no install; Skip/Overwrite se já existir |
Install (quasar ext add / invoke): cria src/boot/bor/bor-dialog-loader-defaults.ts (ou .js) e regista-o em quasar.config → boot: [] automaticamente. Não precisa de editar manualmente numa instalação normal. O boot de pacote (boot/dialog) e main.css são injetados em cada dev/build (não aparecem como entradas curtas em quasar.config).
Remove (quasar ext remove): remove o defaults boot e a respetiva entrada em quasar.config.
Ordem mínima de boots:
1. Pinia (host)
2. Dialog Loader — boot/dialog
3. bor/bor-dialog-loader-defaults (host)Em quasar.config só verá bor/bor-dialog-loader-defaults; o boot boot/dialog é adicionado pelo runner ao compilar.
O boot monta o diálogo no documento e liga a store Pinia do host. Não precisa importar DialogLoader em App.vue.
Defaults globais (boot)
Evite repetir variant, spinner, gap, font, delays e zIndex em cada chamada. Prioridade do label: run({ label }) / show() → boot label → i18n (locale / $q.lang / en).
Após quasar ext add, reveja src/boot/bor/bor-dialog-loader-defaults.ts — plantilla com todas as opções boot (// recomendado: …) e instruções de idioma no comentário do ficheiro.
// src/boot/bor/bor-dialog-loader-defaults.ts
import { configureDialogLoaderDefaults } from "@benjaminor-dev/quasar-app-extension-dialog-loader";
configureDialogLoaderDefaults({
// locale: "pt", // descomente para fixar um idioma específico no Dialog Loader
variant: "glass",
spinner: "ios",
openDelayMs: 120,
hideDelayMs: 450,
minVisibleMs: 600,
backdropBlur: "blur(10px)",
zIndex: 6000,
gap: "2rem",
font: {
family: "Arial, sans-serif",
size: "1.35rem",
},
spinnerColor: {
light: "primary",
dark: "white",
},
spinnerTrackColor: {
light: "grey-4",
dark: "grey-7",
},
});Idioma (i18n)
Built-in en, es e pt. Por defeito o label segue o idioma do Quasar ($q.lang.isoName); se o Quasar não definir idioma, cai em en ("Loading...").
Resolução de locale: boot locale → prefixo de $q.lang.isoName (es* → es, pt* → pt) → en.
Resolução do label: run({ label }) / show(label) → boot label → boot messages.loadingLabel → catálogo built-in → en.
Chaves i18n built-in: loadingLabel (texto padrão do loader), operationCancelled (DialogLoaderRunCancelledError quando cancel() aborta a tarefa).
| Opção | Quando usar |
| --- | --- |
| framework.lang em quasar.config.ts | Recomendado — alinha Dialog Loader com o resto do Quasar |
| locale: 'pt' no boot | Fixar um idioma específico (en | es | pt); ignora mudanças de $q.lang |
| messages: { loadingLabel: '…' } | Só alterar um texto sem tocar no locale |
| label: '…' no boot | Label fixo sempre (ignora i18n) |
Exemplo Quasar config (português em toda a app):
// quasar.config.ts
framework: {
lang: "pt-BR",
},configureDialogLoader é alias de configureDialogLoaderDefaults.
| Opção boot | Default built-in | Descrição |
| --- | --- | --- |
| locale | (segue $q.lang) | Fixa en | es | pt para textos da extensão |
| messages | (por locale) | Override parcial (loadingLabel, operationCancelled) |
| label | "Loading..." (i18n) | Texto fixo quando não passa label em show() / run() |
| variant | "glass" | Apresentação do diálogo |
| spinner | "ios" | Indicador de carregamento (ver spinners) |
| openDelayMs | 120 | Atraso antes de mostrar (evita flashes em pedidos muito rápidos) |
| hideDelayMs | 450 | Atraso extra ao fechar (alinha com animação de saída) |
| minVisibleMs | 600 | Tempo mínimo visível ainda que a operação termine antes |
| backdropBlur | "blur(10px)" | Valor CSS backdrop-filter do overlay |
| zIndex | 6000 | Abaixo do Quasar Notify (~9500) para toasts continuarem visíveis |
| gap | "2rem" | Espaço label↔spinner |
| font.family | "Arial, sans-serif" | CSS font-family do label |
| font.size | "1.35rem" | CSS font-size do label |
| spinnerColor | (por variant) | Cor Quasar do spinner — plano ou { light, dark } |
| spinnerTrackColor | (por variant) | Cor Quasar do track em spinners circulares — plano ou { light, dark } |
Se omitir spinnerColor / spinnerTrackColor, o fallback depende de variant: em primary o spinner é branco; em glass e minimal usa primary e grey-4. Configure { light, dark } no boot para adaptar o spinner ao tema do host ($q.dark).
Uso rápido
<script setup lang="ts">
import { useDialogLoader } from "@benjaminor-dev/quasar-app-extension-dialog-loader";
const loader = useDialogLoader();
async function onSave() {
try {
await loader.run({ task: () => api.save(formData) });
// notify.success('Guardado');
} catch (error) {
// notify.error('Erro ao guardar');
}
}
</script>
<template>
<q-btn label="Guardar" @click="onSave" />
</template>Sem label explícito — usa i18n conforme $q.lang (p. ex. "Carregando..." com lang: 'pt-BR'):
await loader.run(() => fetchUsers());
// equivalente:
await loader.run({ task: () => fetchUsers() });Override pontual do texto:
await loader.run({ label: "A guardar...", task: () => api.save(formData) });Controlos opcionais dentro de task:
await loader.run({
task: async ({ pause, resume, cancel, signal }) => {
await api.prepare();
pause(); // oculta overlay; a tarefa continua
await api.finishInBackground();
resume(); // volta a mostrar o loader
await fetch("/api/finalize", { signal }); // cancel() aborta este fetch
},
});| Controlo | O que faz |
| --- | --- |
| pause() | Oculta o loader; não cancela a tarefa |
| resume() | Reabre o loader após um pause() |
| cancel() | Aborta signal, fecha o loader e rejeita run() com DialogLoaderRunCancelledError |
| signal | Passe a fetch / axios para cancelação cooperativa |
pause(), resume() e cancel() são idempotentes e só afetam essa operação de run().
import { DialogLoaderRunCancelledError } from "@benjaminor-dev/quasar-app-extension-dialog-loader";
try {
await loader.run({ task: ({ signal }) => fetch(url, { signal }) });
} catch (error) {
if (error instanceof DialogLoaderRunCancelledError) return;
throw error;
}Controlo manual (menos habitual):
loader.show("A processar...");
try {
await longTask();
} finally {
loader.hide();
}TypeScript no seu IDE
Não memorize a API: deixe o autocompletado guiá-lo.
useDialogLoader()devolveDialogLoaderApi— métodos e refs aparecem ao escreverloader..- Em
configureDialogLoaderDefaults({ ... }), Ctrl+Space (Windows/Linux) ou Cmd+Space (macOS) listavariant,spinner,spinnerColor,spinnerTrackColor,gap,font,openDelayMs, etc. variantaceita"glass" \| "primary" \| "minimal";spinneraceita os valores deDIALOG_LOADER_SPINNER_TYPES(p. ex."ios","dots","circular").run()— overloads:run(task)ourun({ task, label? }); emtask, desestruture{ pause, resume, cancel, signal }com tipos inferidos.- No boot,
localeaceita"en" \| "es" \| "pt";messagesaceitaDialogLoaderMessagesparcial (loadingLabel,operationCancelled). - Passe o cursor sobre um método: o tooltip mostra parâmetros e JSDoc.
Se algo não aparecer no autocompletado, costuma ser uma prop inexistente ou import incorreto — reveja o entrypoint principal antes de procurar no README.
API pública
Ponto de entrada: useDialogLoader().
import { useDialogLoader } from "@benjaminor-dev/quasar-app-extension-dialog-loader";
const loader = useDialogLoader();Métodos
| Método | Descrição |
| --- | --- |
| run(task) | Executa a tarefa com loader; label do boot. Fecha em finally. |
| run({ task }) | Igual ao acima (forma objeto). |
| run({ label, task }) | Igual com label pontual para essa operação. |
| show(label?) | Incrementa o contador interno e agenda abertura do diálogo. |
| hide() | Decrementa o contador; fecha a UI só quando não restam operações pendentes. |
Estado reativo (somente leitura)
| Ref | Descrição |
| --- | --- |
| visible | Se o diálogo está visível. |
| label | Texto mostrado no diálogo. |
Quando usar run vs show / hide
| Abordagem | Quando |
| --- | --- |
| run() | Pedidos async — preferir run({ task }) ou run(task); label só se precisar override. Recomendado. |
| show() / hide() | Fluxos manuais ou várias fases com o mesmo label. |
Variantes visuais
Configure variant no boot do host (ou built-in).
| Valor | Apresentação |
| --- | --- |
| glass | Glassmorphism — card semitransparente com blur (default) |
| primary | Card sólida com cor --q-primary; texto e spinner brancos |
| minimal | Pill horizontal compacto, menos intrusivo |
Indicadores de carregamento (spinner)
Configure spinner no boot. Subset curado de spinners Quasar:
| Valor | Estilo |
| --- | --- |
| ios | Barras radiais estilo iOS (default) |
| circular | Anel com track (QCircularProgress) |
| dots | Três pontos animados |
| oval | Óvalo a rodar |
| tail | Cauda rotativa |
| puff | Círculo pulsante |
| rings | Anéis concêntricos |
| bars | Barras verticais |
| hourglass | Ampulheta |
| infinity | Símbolo ∞ |
Constante exportada: DIALOG_LOADER_SPINNER_TYPES — útil para validar valores em runtime.
Anti-piscar e operações concorrentes
A store mantém um pendingCount: cada show() / início de run() incrementa; cada hide() / fim de run() decrementa. A UI só fecha quando o contador chega a zero.
Delays configuráveis no boot:
openDelayMs— não mostra o diálogo se todas as operações terminarem antes.minVisibleMs— evita flash de fecho imediato após abrir.hideDelayMs— alinha o fecho com a animação fade do overlay.
Várias chamadas concorrentes a run() ou show() partilham o mesmo diálogo até todas terminarem.
Tipos TypeScript exportados
Desde o entrypoint principal:
import {
useDialogLoader,
DialogLoaderRunCancelledError,
resolveDialogLoaderMessages,
resolveExtensionLocale,
type DialogLoaderApi,
type DialogLoaderRunControls,
type DialogLoaderRunOptions,
type DialogLoaderRunTask,
type DialogLoaderDefaults,
type DialogLoaderFontDefaults,
type DialogLoaderMessages,
type DialogLoaderThemeColor,
type DialogLoaderThemeColorValue,
type DialogLoaderThemeMode,
type DialogLoaderVariant,
type DialogLoaderSpinnerType,
type ExtensionLocale,
type ResolvedDialogLoaderDefaults,
} from "@benjaminor-dev/quasar-app-extension-dialog-loader";| Tipo | Uso |
| --- | --- |
| DialogLoaderApi | Retorno de useDialogLoader() |
| ExtensionLocale | "en" \| "es" \| "pt" — boot locale |
| DialogLoaderMessages | Forma de boot messages (loadingLabel, operationCancelled) |
| DialogLoaderRunOptions | Argumento objeto de run({ label?, task }) |
| DialogLoaderRunControls | { pause, resume, cancel, signal } recebido em task |
| DialogLoaderRunTask | Tipo do callback task |
| DialogLoaderRunPause | Oculta o loader sem cancelar |
| DialogLoaderRunResume | Reabre o loader após pause() |
| DialogLoaderRunCancel | Cancela a operação |
| DialogLoaderRunCancelledError | Erro ao cancelar com cancel() |
| DialogLoaderDefaults | Opções admitidas em configureDialogLoaderDefaults |
| DialogLoaderFontDefaults | { family?, size? } dentro de DialogLoaderDefaults.font |
| DialogLoaderThemeColorValue | Cor plana ou { light?, dark? } para spinner |
| DialogLoaderThemeColor | { light?, dark? } — parte de DialogLoaderThemeColorValue |
| DialogLoaderThemeMode | "light" \| "dark" — resolvido com $q.dark.isActive |
| DialogLoaderVariant | "glass" \| "primary" \| "minimal" |
| DialogLoaderSpinnerType | União de spinners suportados |
| ResolvedDialogLoaderDefaults | Defaults já mergeados (interno / referência) |
Também se exportam BUILTIN_DIALOG_LOADER_DEFAULTS, DIALOG_LOADER_SPINNER_TYPES, resolveDialogLoaderMessages, resolveExtensionLocale, configureDialogLoader (alias) e DIALOG_LOADER_API_KEY (chave de provide do boot para integrações avançadas).
Entrypoints públicos
O que importa no seu código:
| Entrypoint | Propósito |
| --- | --- |
| @benjaminor-dev/quasar-app-extension-dialog-loader | useDialogLoader, configureDialogLoaderDefaults, helpers i18n (resolveDialogLoaderMessages, resolveExtensionLocale), tipos e DIALOG_LOADER_SPINNER_TYPES |
Boot (boot/dialog) e estilos (main.css) são registados pela extensão em quasar.config ao instalar — não precisa importá-los manualmente.
Troubleshooting
Vejo "Loading..." e quero português (ou espanhol)
O default sem configurar Quasar é inglês. Escolha uma linha:
// quasar.config.ts — recomendado (toda a app Quasar)
framework: {
lang: "pt-BR",
},// src/boot/bor/bor-dialog-loader-defaults.ts — fixar só o locale do Dialog Loader
configureDialogLoaderDefaults({ locale: "pt" });Override de um só texto:
configureDialogLoaderDefaults({ messages: { loadingLabel: "Carregando..." } });O label não muda se o idioma for alterado durante um run()
Se o usuário mudar o idioma da app enquanto o loader está visível, o texto na tela permanece o de quando run() / show() começou. Ao fechar o loader, o label em repouso segue o novo locale. Para fixar um idioma em toda a extensão, use locale no boot.
Boots ou estilos não aparecem em quasar.config
Em condições normais o install regista o defaults boot em boot: [] e o runner injeta boot/dialog + CSS ao compilar. Se faltar o defaults boot:
npx quasar ext invoke @benjaminor-dev/dialog-loaderErro: Pinia não inicializada
- Verifique um boot de Pinia no host (
app.use(pinia)ou equivalente). - Em
quasar.config, o boot de Pinia deve ir antes do bootdialogdesta extensão.
useDialogLoader() fora de setup
Chame dentro de setup, outro composable ou <script setup>. O boot deve ter sido executado (app montada).
O loader pisca em pedidos rápidos
Ajuste no boot: suba openDelayMs, minVisibleMs ou ambos.
O loader não fecha após show()
Cada show() requer um hide() correspondente (ou use run(), que equilibra automaticamente).
O diálogo fica atrás de outro overlay
Revise zIndex no boot (default 6000).
Mudei spinner no boot e não se reflete
Reinicie o dev server. Confirme que edita src/boot/bor/bor-dialog-loader-defaults.ts do host.
MIT © Benjamín Olvera R.
