export const createCalculator = (options = {}) => { const state = { currentOperand: '', previousOperand: '', operation: undefined, shouldResetDisplay: false, allowNegative: options.allowNegative ?? true, allowDecimal: options.allowDecimal ?? true, allowZero: options.allowZero ?? true, decimalPlaces: options.decimalPlaces ?? null, } // Expose state for debugging and direct access const getState = () => ({ ...state }) const clear = () => { state.currentOperand = '' state.previousOperand = '' state.operation = undefined state.shouldResetDisplay = false return state.currentOperand } const deleteNumber = () => { if (state.currentOperand.length <= 1) { state.currentOperand = '0' } else { state.currentOperand = state.currentOperand.toString().slice(0, -1) } return state.currentOperand } const appendNumber = (number) => { if (number === '.' && !state.allowDecimal) return state.currentOperand if (number === '.' && state.currentOperand.includes('.')) return state.currentOperand if (state.shouldResetDisplay) { state.currentOperand = number.toString() state.shouldResetDisplay = false } else { if (state.currentOperand === '0' && number !== '.') { state.currentOperand = number.toString() } else { state.currentOperand = state.currentOperand.toString() + number.toString() } } return state.currentOperand } const chooseOperation = (operation) => { if (operation === '-' && state.currentOperand === '0' && state.previousOperand === '' && state.allowNegative) { state.currentOperand = '-' return state.currentOperand } if (state.currentOperand === '' || state.currentOperand === '-') return state.currentOperand // If there's a previous operation, compute it first if (state.previousOperand !== '') { compute() } state.operation = operation state.previousOperand = state.currentOperand state.currentOperand = '' return state.previousOperand + state.operation } const compute = () => { // If there's no operation, return the current value if (!state.operation) return parseFloat(state.currentOperand || '0') // If there's no current operand but we have a previous one, use previous as current if (state.currentOperand === '' && state.previousOperand !== '') { state.currentOperand = state.previousOperand } const prev = parseFloat(state.previousOperand) const current = parseFloat(state.currentOperand) if (isNaN(prev) || isNaN(current)) return 0 let result switch (state.operation) { case '+': result = prev + current break case '-': result = prev - current break case '×': result = prev * current break case '÷': if (current === 0) { state.currentOperand = 'Error' return 0 } result = prev / current break default: return parseFloat(state.currentOperand || '0') } // Apply formatting and constraints if (state.decimalPlaces !== null) { result = Number(result.toFixed(state.decimalPlaces)) } if (!state.allowDecimal) { result = Math.round(result) } if (!state.allowNegative && result < 0) { result = 0 } if (!state.allowZero && result === 0) { result = 1 } // Update state state.currentOperand = result.toString() state.previousOperand = '' state.operation = undefined state.shouldResetDisplay = true return result } // Getter methods for the calculator state const getCurrentOperand = () => state.currentOperand const getPreviousOperand = () => state.previousOperand const getOperation = () => state.operation const getDisplayValue = () => { if (state.operation && state.previousOperand) { return `${state.previousOperand} ${state.operation} ${state.currentOperand || ''}`.trim() } return state.currentOperand } return { // Core calculator methods clear, delete: deleteNumber, // Alias for deleteNumber for compatibility deleteNumber, appendNumber, chooseOperation, compute, // State getters getDisplayValue, getCurrentOperand, getPreviousOperand, getOperation, // Direct state access (for debugging) getState, // Direct property access (for compatibility with CalcInput.jsx) get currentOperand() { return state.currentOperand }, get previousOperand() { return state.previousOperand }, get operation() { return state.operation }, get shouldResetDisplay() { return state.shouldResetDisplay }, // Setter for direct property access (if needed) set currentOperand(value) { state.currentOperand = value }, set previousOperand(value) { state.previousOperand = value }, set operation(value) { state.operation = value }, set shouldResetDisplay(value) { state.shouldResetDisplay = value } } }