Composables
useTheme
Gestione tema chiaro/scuro/sistema con persistenza localStorage e sincronizzazione MediaQuery del SO.
Signature
function useTheme(): {
isDark: Ref<boolean>
mode: Ref<'light' | 'dark' | 'system'>
setTheme: (newMode: 'light' | 'dark' | 'system') => void
toggleTheme: () => void
}
Gestisce lo stato del tema (chiaro/scuro/sistema) come singleton globale con persistenza localStorage e sync automatica con prefers-color-scheme del browser.
Stato globale condiviso:
isDark e mode sono ref dichiarate al module-scope e condivise tra tutti i consumer di useTheme(). Modificare il tema in un componente lo aggiorna ovunque.Comportamento
Init
Al primo useTheme() montato:
- Legge
localStorage['pzeta-fogli-theme']('light' | 'dark' | 'system') - Risolve
mode === 'system'consultandomatchMedia('(prefers-color-scheme: dark)') - Applica
document.documentElement.classList.toggle('dark', isDark) - Registra listener su
MediaQueryList.changeper reagire ai cambi del SO
setTheme(newMode)
setTheme('dark')
// → mode.value = 'dark'
// → localStorage['pzeta-fogli-theme'] = 'dark'
// → isDark.value = true
// → <html class="dark">
toggleTheme()
toggleTheme()
// → setTheme(isDark.value ? 'light' : 'dark')
Se la modalità corrente è 'system', parte dallo isDark calcolato (che dipende dal SO).
Sync MediaQuery
Se mode.value === 'system', un cambio della preferenza OS (es. dark mode automatico al tramonto) aggiorna automaticamente isDark senza richiedere refresh.
Esempio: theme switcher
<script setup lang="ts">
import { useTheme } from '@pzeta/vue-foglidicalcolo'
const { isDark, mode, setTheme, toggleTheme } = useTheme()
</script>
<template>
<button @click="toggleTheme">
<i :class="isDark ? 'pi pi-sun' : 'pi pi-moon'" />
</button>
<select :value="mode" @change="setTheme($event.target.value)">
<option value="light">Chiaro</option>
<option value="dark">Scuro</option>
<option value="system">Sistema</option>
</select>
</template>
Storage key
pzeta-fogli-theme
Valori ammessi: 'light' | 'dark' | 'system'. Valori non validi vengono ignorati (cade su 'system' default).
Vincoli
- Browser only: usa
localStorage,matchMedia,document. In SSR i side-effect sono evitati mamoderesta a'system'finché non avviene il mount client-side. - CSS dark class: il toggle aggiunge/rimuove la classe
darksu<html>. La libreria si aspetta un sistema CSS dark-mode basato su selettori.dark .foo {...}(Tailwind, PrimeVue dark theme). - Tema indipendente dal
MFEContext.theme(di@pzeta/mfe-contracts): se la shell usa un proprio sistema tema, è responsabilità del consumer sincronizzarli.
Pattern: sync con MFEContext.theme
Se l'app è un MFE caricato in una shell che fornisce MFEContext.theme:
<script setup lang="ts">
import { watch } from 'vue'
import { useMfeContext } from '@pzeta/mfe-contracts/composables'
import { useTheme } from '@pzeta/vue-foglidicalcolo'
const ctx = useMfeContext()
const { mode, setTheme } = useTheme()
// Quando la shell cambia tema, aggiorna anche il tema del foglio
watch(() => ctx.theme?.mode, (newMode) => {
if (newMode && newMode !== mode.value) {
setTheme(newMode)
}
})
</script>