bug fix clean-up

This commit is contained in:
2026-03-29 14:04:20 -04:00
parent c378ec59e4
commit 49fa8b61eb
3 changed files with 12 additions and 56 deletions

View File

@@ -74,26 +74,22 @@ function TimeInputMobile({ value, onChange }) {
const [inputVal, setInputVal] = useState(fmt12(value));
const wrapRef = useRef(null);
const listRef = useRef(null);
const inputRef = useRef(null);
useEffect(() => { setInputVal(fmt12(value)); }, [value]);
// Programmatically disable autocomplete after mount
useEffect(() => {
if (inputRef.current) {
inputRef.current.setAttribute('autocomplete', 'off');
inputRef.current.setAttribute('autocorrect', 'off');
inputRef.current.setAttribute('autocapitalize', 'off');
inputRef.current.setAttribute('spellcheck', 'false');
}
}, []);
useEffect(() => {
if (!open || !listRef.current) return;
const idx = TIME_SLOTS.findIndex(s => s.value === value);
if (idx >= 0) listRef.current.scrollTop = idx * 40 - 40;
}, [open, value]);
useEffect(() => {
if (!open) return;
const h = e => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
document.addEventListener('mousedown', h);
return () => document.removeEventListener('mousedown', h);
}, [open]);
const commit = (raw) => {
const parsed = parseTypedTime(raw);
if (parsed) { onChange(parsed); setInputVal(fmt12(parsed)); }
@@ -104,16 +100,13 @@ function TimeInputMobile({ value, onChange }) {
return (
<div ref={wrapRef} style={{ position: 'relative', display: 'inline-block' }}>
<input
ref={inputRef}
type="text"
value={inputVal}
onChange={e => setInputVal(e.target.value)}
onFocus={() => setOpen(true)}
onBlur={e => setTimeout(() => commit(e.target.value), 150)}
onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); commit(inputVal); } if (e.key === 'Escape') { setInputVal(fmt12(value)); setOpen(false); } }}
autoComplete="nope"
data-autocomplete="off"
inputMode="none"
autoComplete="off"
style={{ fontSize: 15, color: 'var(--primary)', fontWeight: 600, background: 'transparent', border: 'none', outline: 'none', cursor: 'text', width: 90 }}
/>
{open && (
@@ -492,7 +485,7 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
{/* form wrapper suppresses Chrome Android's autofill chip bar; autoComplete="new-password"
on individual inputs is ignored by Chrome but respected on the form element */}
<form autoComplete="nope" onSubmit={e => e.preventDefault()} style={{ flex:1,overflowY:'auto' }}>
<form autoComplete="off" onSubmit={e => e.preventDefault()} style={{ flex:1,overflowY:'auto' }}>
{/* Title */}
<div style={{ padding:'16px 20px',borderBottom:'1px solid var(--border)' }}>
<input value={title} onChange={e => setTitle(e.target.value)} autoComplete="new-password" placeholder="Add title" autoCorrect="off" autoCapitalize="sentences" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:22,fontWeight:700,color:'var(--text-primary)',outline:'none' }}/>

View File

@@ -149,22 +149,11 @@ function TimeInput({ value, onChange, style }) {
const [inputVal, setInputVal] = useState(fmt12(value));
const wrapRef = useRef(null);
const listRef = useRef(null);
const inputRef = useRef(null);
// Keep display in sync when value changes externally
useEffect(() => { setInputVal(fmt12(value)); }, [value]);
// Programmatically disable autocomplete after mount
useEffect(() => {
if (inputRef.current) {
inputRef.current.setAttribute('autocomplete', 'off');
inputRef.current.setAttribute('autocorrect', 'off');
inputRef.current.setAttribute('autocapitalize', 'off');
inputRef.current.setAttribute('spellcheck', 'false');
}
}, []);
// Scroll the dropdown so the selected slot is near the top
// Scroll the dropdown so that selected slot is near the top
useEffect(() => {
if (!open || !listRef.current) return;
const idx = TIME_SLOTS.findIndex(s => s.value === value);
@@ -196,7 +185,6 @@ function TimeInput({ value, onChange, style }) {
return (
<div ref={wrapRef} style={{ position: 'relative', ...style }}>
<input
ref={inputRef}
type="text"
className="input"
value={inputVal}
@@ -208,9 +196,7 @@ function TimeInput({ value, onChange, style }) {
}}
onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); commit(inputVal); } if (e.key === 'Escape') { setInputVal(fmt12(value)); setOpen(false); } }}
style={{ width: '100%', cursor: 'text' }}
autoComplete="nope"
data-autocomplete="off"
inputMode="none"
autoComplete="off"
placeholder="9:00 AM"
/>
{open && (
@@ -680,7 +666,7 @@ function EventForm({ event, userGroups, eventTypes, selectedDate, onSave, onCanc
<div style={{width:'100%',maxWidth:1024,overflowX:'auto'}}>
{/* form wrapper suppresses Chrome Android's autofill chip bar; autoComplete="new-password"
on individual inputs is ignored by Chrome but respected on the form element */}
<form autoComplete="nope" onSubmit={e => e.preventDefault()}>
<form autoComplete="off" onSubmit={e => e.preventDefault()}>
<div style={{minWidth:500}} onKeyDown={e=>{if(e.key==='Enter'&&e.target.tagName!=='TEXTAREA') e.preventDefault();}}>
{/* Title */}
<div style={{marginBottom:20}}>

View File

@@ -38,29 +38,6 @@ html {
font-size: 100%; /* inherits system font size — allows Android accessibility font scaling */
}
/* Aggressively disable Chrome autocomplete on Android */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0 1000px white inset !important;
background-color: white !important;
background-image: none !important;
transition: background-color 5000s ease-in-out 0s !important;
}
/* Disable autocomplete dropdown/panel */
input::-webkit-credentials-auto-fill-button,
input::-webkit-contacts-auto-fill-button {
display: none !important;
visibility: hidden !important;
pointer-events: none !important;
position: absolute !important;
right: 0 !important;
}
button { font-family: var(--font); cursor: pointer; border: none; background: none; }
input, textarea { font-family: var(--font); }
a { color: inherit; text-decoration: none; }