import React from 'react'; import { motion } from 'motion/react'; import { useSetting } from './settingsRegistry'; import { Switch } from './Switch'; import { Input } from './Input'; import { Eye, EyeOff } from 'lucide-react'; export interface SettingsSwitchProps { settingKey: string; label: string; description?: string; defaultValue?: boolean; className?: string; } /** * SettingsSwitch — Un interruptor (switch) auto-enlazado y reactivo en caliente. * Se conecta de forma transparente a una única clave del Cascade Settings Engine. */ export const SettingsSwitch: React.FC = ({ settingKey, label, description, defaultValue = false, className = '' }) => { const [checked, setChecked, { isSaving }] = useSetting(settingKey, defaultValue); return (
{description && ( {description} )}
setChecked(checkedValue)} disabled={isSaving} />
); }; export interface SettingsSelectProps { settingKey: string; label: string; description?: string; options: { value: string; label: string }[]; defaultValue?: string; className?: string; } /** * SettingsSelect — Un menú selector auto-enlazado y reactivo en caliente. */ export const SettingsSelect: React.FC = ({ settingKey, label, description, options, defaultValue = '', className = '' }) => { const [value, setValue, { isSaving }] = useSetting(settingKey, defaultValue); return (
▼
{description && ( {description} )}
); }; export interface SettingsTextProps { settingKey: string; label: string; description?: string; placeholder?: string; defaultValue?: string; className?: string; } /** * SettingsText — Entrada de texto auto-enlazada. Persiste de forma optimista * al perder el foco (onBlur) o al pulsar Enter para no sobrecargar el bus IPC. */ export const SettingsText: React.FC = ({ settingKey, label, description, placeholder, defaultValue = '', className = '' }) => { const [value, setValue, { isSaving }] = useSetting(settingKey, defaultValue); const [localVal, setLocalVal] = React.useState(value || ''); React.useEffect(() => { setLocalVal(value || ''); }, [value]); const handleSave = () => { if (localVal !== value) { setValue(localVal); } }; return (
setLocalVal(e.target.value)} onBlur={handleSave} onKeyDown={(e) => e.key === 'Enter' && handleSave()} disabled={isSaving} className="bg-surface/50" /> {isSaving && ( guardando... )}
{description && ( {description} )}
); }; /** * SettingsPassword — Entrada de contraseña enmascarada auto-enlazada. */ export const SettingsPassword: React.FC = ({ settingKey, label, description, placeholder, defaultValue = '', className = '' }) => { const [value, setValue, { isSaving }] = useSetting(settingKey, defaultValue); const [localVal, setLocalVal] = React.useState(value || ''); const [visible, setVisible] = React.useState(false); React.useEffect(() => { setLocalVal(value || ''); }, [value]); const handleSave = () => { if (localVal !== value) { setValue(localVal); } }; return (
setLocalVal(e.target.value)} onBlur={handleSave} onKeyDown={(e) => e.key === 'Enter' && handleSave()} disabled={isSaving} className="bg-surface/50" icon={ } /> {isSaving && ( guardando... )}
{description && ( {description} )}
); }; export interface SettingsGroupProps { title: string; description?: string; children: React.ReactNode; className?: string; } /** * SettingsGroup — Contenedor visual glassmorphic para agrupar múltiples controles atómicos. */ export const SettingsGroup: React.FC = ({ title, description, children, className = '' }) => { return (

{title}

{description && (

{description}

)}
{children}
); };