/** * Un foglio con un campo solo e una spiegazione: l'indirizzo per «Da un link» * e la ricerca per «Cerca sul web». * * La conferma può richiedere tempo (scaricare una pagina): intanto il comando * a destra si spegne e sotto il campo gira la rotellina. Se la conferma * restituisce un errore, lo si scrive sotto il campo e il foglio resta aperto * col testo dentro, così si corregge senza riscrivere. * * I colori non si scrivono qui: vengono da tema.ts, come nelle altre schermate. */ import { useMemo, useRef, useState } from 'react'; import type { TextInput, TextInputProps } from 'react-native'; import { ActivityIndicator, StyleSheet, Text, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useApp } from '../contesto.ts'; import type { Colori } from '../tema.ts'; import { SPAZIO, TESTO, useColori } from '../tema.ts'; import { CampoTesto } from './Campo.tsx'; import { Foglio } from './Foglio.tsx'; import { TestaFoglio } from './TestaFoglio.tsx'; export type PropsFoglioCampo = { visibile: boolean; titolo: string; etichetta: string; esempio: string; spiega: string; conferma: string; tastiera?: TextInputProps['keyboardType']; /** Restituisce il testo di un errore da mostrare, o null se è andata e il foglio si può chiudere. */ onConferma: (testo: string) => Promise; onChiudi: () => void; }; export function FoglioCampo({ visibile, titolo, etichetta, esempio, spiega, conferma, tastiera, onConferma, onChiudi, }: PropsFoglioCampo) { const { testo } = useApp(); const colori = useColori(); const stili = useMemo(() => creaStili(colori), [colori]); const sotto = useSafeAreaInsets().bottom; const campo = useRef(null); const [valore, setValore] = useState(''); const [errore, setErrore] = useState(null); const [inCorso, setInCorso] = useState(false); // Ogni apertura riparte da capo già nel primo disegno (stato derivato). const [apertoPrima, setApertoPrima] = useState(visibile); if (visibile !== apertoPrima) { setApertoPrima(visibile); if (visibile) { setValore(''); setErrore(null); setInCorso(false); } } const vai = async () => { if (valore.trim() === '' || inCorso) return; setInCorso(true); setErrore(null); const esito = await onConferma(valore.trim()); setInCorso(false); if (esito === null) onChiudi(); else setErrore(esito); }; return ( campo.current?.focus()}> void vai(), spento: valore.trim() === '' || inCorso }} /> {spiega} { setValore(v); setErrore(null); }} keyboardType={tastiera} autoCapitalize="none" autoCorrect={false} returnKeyType="go" onSubmitEditing={() => void vai()} /> {inCorso ? : null} {errore !== null ? {errore} : null} ); } const creaStili = (colori: Colori) => StyleSheet.create({ foglio: { backgroundColor: colori.fondo, borderTopLeftRadius: 22, borderTopRightRadius: 22 }, dentro: { paddingHorizontal: SPAZIO.l, paddingTop: SPAZIO.s, gap: SPAZIO.m }, spiega: { ...TESTO.piccolo, color: colori.testoTenue, lineHeight: 18 }, rotella: { alignSelf: 'flex-start' }, errore: { ...TESTO.piccolo, color: colori.attenzione, lineHeight: 18 }, });