AGGrid-Portal / src /components /FormulaBar.jsx
Bhanushray's picture
Upload 42 files
a435638 verified
import React, { useState, useEffect, useRef } from "react";
/**
* FormulaBar – Excel-like formula bar.
* Props:
* cellAddress – "B3", "A1", etc. (empty string if nothing selected)
* formulaDisplay – raw string to show (formula text like "=SUM(Revenue)" or a plain value)
* onFormulaApply – (newValue: string) => void called on Enter / ✔
* readOnly – true for Summary sheet (no editing)
* dark – boolean
*/
function FormulaBar({ cellAddress, formulaDisplay, onFormulaApply, readOnly = false, dark }) {
const [localVal, setLocalVal] = useState("");
const [editing, setEditing] = useState(false);
const inputRef = useRef();
// Sync incoming value whenever the selected cell changes
useEffect(() => {
setLocalVal(formulaDisplay ?? "");
setEditing(false);
}, [formulaDisplay, cellAddress]);
const isFormula = localVal.trim().startsWith("=");
const hasCell = !!cellAddress;
const apply = () => {
if (!readOnly && hasCell) {
onFormulaApply?.(localVal);
}
setEditing(false);
inputRef.current?.blur();
};
const cancel = () => {
setLocalVal(formulaDisplay ?? "");
setEditing(false);
inputRef.current?.blur();
};
const onKeyDown = (e) => {
if (e.key === "Enter") { e.preventDefault(); apply(); }
if (e.key === "Escape") { e.preventDefault(); cancel(); }
};
// ── Token colours ──────────────────────────────────────────────
const surface = dark ? "#141d2e" : "#ffffff";
const border = dark ? "#1e2843" : "#d1d5db";
const textCol = dark ? "#cbd5e1" : "#1e293b";
const muted = dark ? "#4a5a7a" : "#94a3b8";
const accent = "#3b82f6";
return (
<div style={{
display:"flex", alignItems:"center",
height:"33px", flexShrink:0,
background: surface,
borderBottom:`1px solid ${border}`,
padding:"0 8px", gap:"5px",
}}>
{/* Cell address box */}
<div style={{
minWidth:"68px", maxWidth:"68px",
height:"21px",
display:"flex", alignItems:"center", justifyContent:"center",
background: dark ? "#1a2540" : "#f3f4f6",
border:`1px solid ${dark ? "#1e2843" : "#d1d5db"}`,
borderRadius:"3px",
fontSize:"11.5px", fontWeight:"600", fontFamily:"monospace",
color: hasCell ? (dark ? "#93c5fd" : "#2563eb") : muted,
letterSpacing:"0.04em",
userSelect:"none", flexShrink:0,
}}>
{cellAddress || ""}
</div>
{/* Thin separator */}
<div style={{ width:"1px", height:"18px", background: border, flexShrink:0 }} />
{/* Cancel / Accept – only while editing */}
{editing && !readOnly && (
<>
<button onClick={cancel} title="Cancel (Esc)" style={{
width:"20px", height:"20px", border:"none", borderRadius:"3px",
background:"transparent", cursor:"pointer",
color:"#ef4444", fontSize:"13px", fontWeight:"700",
display:"flex", alignItems:"center", justifyContent:"center",
}}
onMouseEnter={e => e.currentTarget.style.background="#fee2e2"}
onMouseLeave={e => e.currentTarget.style.background="transparent"}
>✕</button>
<button onClick={apply} title="Apply (Enter)" style={{
width:"20px", height:"20px", border:"none", borderRadius:"3px",
background:"transparent", cursor:"pointer",
color:"#10b981", fontSize:"13px", fontWeight:"700",
display:"flex", alignItems:"center", justifyContent:"center",
}}
onMouseEnter={e => e.currentTarget.style.background="#d1fae5"}
onMouseLeave={e => e.currentTarget.style.background="transparent"}
>✔</button>
</>
)}
{/* fx badge */}
<div style={{
display:"flex", alignItems:"baseline", gap:"1px",
padding:"0 6px", height:"21px",
alignSelf:"center",
background: isFormula ? (dark ? "rgba(59,130,246,0.15)" : "rgba(59,130,246,0.08)") : "transparent",
border: isFormula ? `1px solid rgba(59,130,246,0.3)` : "1px solid transparent",
borderRadius:"3px",
transition:"all 0.15s",
flexShrink:0,
justifyContent:"center",
}}>
<span style={{
fontFamily:"'Times New Roman', Georgia, serif",
fontStyle:"italic", fontWeight:"700", fontSize:"14px",
color: isFormula ? accent : muted,
lineHeight:"21px",
}}>f</span>
<span style={{
fontFamily:"'Times New Roman', Georgia, serif",
fontStyle:"italic", fontWeight:"700", fontSize:"11px",
color: isFormula ? "#60a5fa" : muted,
lineHeight:"21px",
}}>x</span>
</div>
{/* Main input */}
<div style={{ flex:1, position:"relative", minWidth:0 }}>
<input
ref={inputRef}
type="text"
value={localVal}
disabled={readOnly || !hasCell}
placeholder={
readOnly ? "Click a cell to see its formula" :
!hasCell ? "Select a cell to edit" :
"Value or =formula…"
}
onChange={e => { setLocalVal(e.target.value); setEditing(true); }}
onFocus={() => { if (!readOnly && hasCell) setEditing(true); }}
onBlur={() => setTimeout(() => setEditing(false), 180)}
onKeyDown={onKeyDown}
style={{
width:"100%",
height:"21px",
padding:"0 8px",
border: editing
? `1px solid ${accent}`
: "1px solid transparent",
borderRadius:"3px",
background: editing
? (dark ? "#0f1828" : "#fefce8")
: "transparent",
outline:"none",
fontSize:"12.5px",
fontFamily: isFormula ? "'Courier New', monospace" : "inherit",
fontWeight: isFormula ? "500" : "400",
color: isFormula
? (dark ? "#60a5fa" : "#1d4ed8")
: textCol,
cursor: (!readOnly && hasCell) ? "text" : "default",
transition:"border 0.15s, background 0.15s",
boxSizing:"border-box",
}}
/>
</div>
{/* Formula badge on the right */}
{isFormula && (
<div style={{
fontSize:"10px", color: dark ? "#3b5bdb" : "#93c5fd",
background: dark ? "rgba(59,130,246,0.1)" : "rgba(59,130,246,0.07)",
border:"1px solid rgba(59,130,246,0.2)",
borderRadius:"3px", padding:"1px 6px",
fontWeight:"600", letterSpacing:"0.04em",
userSelect:"none", flexShrink:0,
}}>
FORMULA
</div>
)}
{readOnly && hasCell && (
<div style={{
fontSize:"10px", color: dark ? "#4a5a7a" : "#94a3b8",
fontWeight:"500", userSelect:"none", flexShrink:0,
whiteSpace:"nowrap",
}}>
read-only
</div>
)}
</div>
);
}
export default FormulaBar;