Spaces:
Configuration error
Configuration error
| 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; |