@gumigumih/react-calculator-input-form 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -40
- package/dist/components/organisms/Calculator.d.ts +1 -1
- package/dist/index.esm.js +87 -33
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +87 -33
- package/dist/index.js.map +1 -1
- package/dist/styles/index.d.ts +6 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6381,7 +6381,7 @@ function NumericFormat(props) {
|
|
|
6381
6381
|
}
|
|
6382
6382
|
|
|
6383
6383
|
const CalculatorDisplay = ({ value, error, inputRef, editable, placeholder, onChange, numberFormatOptions = {} }) => {
|
|
6384
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [editable ? (jsxRuntime.jsx(NumericFormat, { className: "calculator-display-input", value: value, onValueChange: (vals) => onChange?.(vals.value), placeholder: placeholder ?? '数値を入力', inputMode: "decimal", ...numberFormatOptions })) : (jsxRuntime.jsx("div", { className: "calculator-display-input", children: jsxRuntime.jsx("div", { ref: inputRef, style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: value ? (jsxRuntime.jsx(NumericFormat, { value: value, displayType: "text", ...numberFormatOptions })) : '' }) })), error && jsxRuntime.jsx("div", { className: "calculator-error", children: error })] }));
|
|
6384
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [editable ? (jsxRuntime.jsx(NumericFormat, { className: "calculator-display-input", value: value, onValueChange: (vals) => onChange?.(vals.value), placeholder: placeholder ?? '数値を入力', inputMode: "decimal", ...numberFormatOptions })) : (jsxRuntime.jsx("div", { className: "calculator-display-input", children: jsxRuntime.jsx("div", { ref: inputRef, style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: value ? (jsxRuntime.jsx(NumericFormat, { value: value, displayType: "text", ...numberFormatOptions })) : (jsxRuntime.jsx("span", { className: "text-gray-400", children: placeholder ?? '0' })) }) })), error && jsxRuntime.jsx("div", { className: "calculator-error", children: error })] }));
|
|
6385
6385
|
};
|
|
6386
6386
|
|
|
6387
6387
|
const CalculatorKeypad = ({ onButtonClick, onEqual, onDecide, onTaxInclude, onTaxExclude, enableTaxCalculation = true, decimalPlaces = 6 }) => {
|
|
@@ -6448,11 +6448,11 @@ function calculateExpression(expr) {
|
|
|
6448
6448
|
return '0';
|
|
6449
6449
|
}
|
|
6450
6450
|
}
|
|
6451
|
-
const Calculator = ({ isOpen, onClose, onCalculate, initialValue = '', title, description, enableTaxCalculation = false, decimalPlaces = 6, numberFormatOptions = {},
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
const [input, setInput] = React.useState(initialValue || '');
|
|
6451
|
+
const Calculator = ({ isOpen, onClose, onCalculate, initialValue = '', title, description, enableTaxCalculation = false, decimalPlaces = 6, numberFormatOptions = {}, placeholder, }) => {
|
|
6452
|
+
const [expression, setExpression] = React.useState(initialValue || '');
|
|
6453
|
+
const [displayValue, setDisplayValue] = React.useState(initialValue || '');
|
|
6455
6454
|
const [error, setError] = React.useState('');
|
|
6455
|
+
const [isWaitingForOperand, setIsWaitingForOperand] = React.useState(false);
|
|
6456
6456
|
const [mounted, setMounted] = React.useState(false);
|
|
6457
6457
|
const inputRef = React.useRef(null);
|
|
6458
6458
|
// DOM要素の存在確認
|
|
@@ -6462,7 +6462,9 @@ const Calculator = ({ isOpen, onClose, onCalculate, initialValue = '', title, de
|
|
|
6462
6462
|
}, []);
|
|
6463
6463
|
React.useEffect(() => {
|
|
6464
6464
|
if (isOpen) {
|
|
6465
|
-
|
|
6465
|
+
setExpression(initialValue || '');
|
|
6466
|
+
setDisplayValue(initialValue || '');
|
|
6467
|
+
setIsWaitingForOperand(false);
|
|
6466
6468
|
setError('');
|
|
6467
6469
|
}
|
|
6468
6470
|
}, [isOpen, initialValue]);
|
|
@@ -6506,84 +6508,136 @@ const Calculator = ({ isOpen, onClose, onCalculate, initialValue = '', title, de
|
|
|
6506
6508
|
};
|
|
6507
6509
|
window.addEventListener('keydown', handleKeyDown);
|
|
6508
6510
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
6509
|
-
}, [isOpen,
|
|
6511
|
+
}, [isOpen, expression, displayValue]);
|
|
6512
|
+
const handleDisplayChange = (newValue) => {
|
|
6513
|
+
setError('');
|
|
6514
|
+
setDisplayValue(newValue);
|
|
6515
|
+
if (isWaitingForOperand) {
|
|
6516
|
+
// 演算子入力後の直接入力の場合、式を更新しない
|
|
6517
|
+
// If an operator was just entered, and user types directly,
|
|
6518
|
+
// the new value is the start of the next operand.
|
|
6519
|
+
// Append it to the expression.
|
|
6520
|
+
setExpression(expression + newValue);
|
|
6521
|
+
setIsWaitingForOperand(false); // No longer waiting for operand
|
|
6522
|
+
}
|
|
6523
|
+
else {
|
|
6524
|
+
// 既存の式の最後の数値を置き換える
|
|
6525
|
+
const newExpression = expression.replace(/[\d.]+$/, newValue);
|
|
6526
|
+
setExpression(newExpression);
|
|
6527
|
+
}
|
|
6528
|
+
};
|
|
6510
6529
|
const handleButtonClick = (val) => {
|
|
6511
6530
|
setError('');
|
|
6512
6531
|
if (val === 'C') {
|
|
6513
|
-
|
|
6532
|
+
setExpression('');
|
|
6533
|
+
setDisplayValue('');
|
|
6534
|
+
setIsWaitingForOperand(false);
|
|
6514
6535
|
}
|
|
6515
6536
|
else if (val === '←') {
|
|
6516
|
-
|
|
6537
|
+
if (displayValue.length > 0) {
|
|
6538
|
+
const newDisplayValue = displayValue.slice(0, -1);
|
|
6539
|
+
setDisplayValue(newDisplayValue);
|
|
6540
|
+
setExpression((prev) => prev.slice(0, -1));
|
|
6541
|
+
}
|
|
6517
6542
|
}
|
|
6518
6543
|
else if (val === '.') {
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6544
|
+
if (!displayValue.includes('.')) {
|
|
6545
|
+
const newDisplayValue = displayValue ? displayValue + '.' : '0.';
|
|
6546
|
+
setDisplayValue(newDisplayValue);
|
|
6547
|
+
if (isWaitingForOperand) {
|
|
6548
|
+
setExpression(expression + newDisplayValue);
|
|
6549
|
+
setIsWaitingForOperand(false);
|
|
6550
|
+
}
|
|
6551
|
+
else {
|
|
6552
|
+
setExpression(expression + (displayValue ? '.' : '0.'));
|
|
6553
|
+
// Append decimal to the last number in the expression
|
|
6554
|
+
const lastNumberRegex = /([\d.]+)$/;
|
|
6555
|
+
setExpression(expression.replace(lastNumberRegex, (match) => match + '.'));
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6527
6558
|
}
|
|
6528
6559
|
else if (['+', '-', '×', '÷'].includes(val)) {
|
|
6529
|
-
if (
|
|
6530
|
-
|
|
6531
|
-
|
|
6560
|
+
if (expression) {
|
|
6561
|
+
if (/[+\-×÷]$/.test(expression)) {
|
|
6562
|
+
setExpression(expression.slice(0, -1) + val);
|
|
6563
|
+
}
|
|
6564
|
+
else {
|
|
6565
|
+
const result = calculateExpression(expression);
|
|
6566
|
+
setExpression(result + val);
|
|
6567
|
+
setDisplayValue(result);
|
|
6568
|
+
}
|
|
6569
|
+
setIsWaitingForOperand(true);
|
|
6570
|
+
}
|
|
6532
6571
|
}
|
|
6533
6572
|
else {
|
|
6534
|
-
|
|
6573
|
+
if (isWaitingForOperand) {
|
|
6574
|
+
setDisplayValue(val);
|
|
6575
|
+
setExpression(expression + val);
|
|
6576
|
+
setIsWaitingForOperand(false);
|
|
6577
|
+
}
|
|
6578
|
+
else {
|
|
6579
|
+
const newDisplayValue = displayValue === '0' ? val : displayValue + val;
|
|
6580
|
+
setDisplayValue(newDisplayValue);
|
|
6581
|
+
setExpression(expression === '0' ? val : expression + val);
|
|
6582
|
+
}
|
|
6535
6583
|
}
|
|
6536
6584
|
};
|
|
6537
6585
|
const handleEqual = () => {
|
|
6538
|
-
if (!
|
|
6586
|
+
if (!expression)
|
|
6539
6587
|
return;
|
|
6540
|
-
const result = calculateExpression(
|
|
6541
|
-
|
|
6588
|
+
const result = calculateExpression(expression);
|
|
6589
|
+
setExpression(result);
|
|
6590
|
+
setDisplayValue(result);
|
|
6591
|
+
setIsWaitingForOperand(false);
|
|
6542
6592
|
};
|
|
6543
6593
|
const handleDecide = () => {
|
|
6544
|
-
if (!
|
|
6594
|
+
if (!expression) {
|
|
6545
6595
|
setError('金額を入力してください');
|
|
6546
6596
|
return;
|
|
6547
6597
|
}
|
|
6548
|
-
const result = calculateExpression(
|
|
6598
|
+
const result = calculateExpression(expression);
|
|
6549
6599
|
onCalculate(result);
|
|
6550
6600
|
onClose();
|
|
6551
6601
|
};
|
|
6552
6602
|
const handleTaxInclude = (rate) => {
|
|
6553
6603
|
if (!enableTaxCalculation)
|
|
6554
6604
|
return;
|
|
6555
|
-
if (!
|
|
6605
|
+
if (!expression) {
|
|
6556
6606
|
setError('金額を入力してください');
|
|
6557
6607
|
return;
|
|
6558
6608
|
}
|
|
6559
|
-
const currentValue = parseFloat(calculateExpression(
|
|
6609
|
+
const currentValue = parseFloat(calculateExpression(expression));
|
|
6560
6610
|
if (isNaN(currentValue)) {
|
|
6561
6611
|
setError('有効な金額を入力してください');
|
|
6562
6612
|
return;
|
|
6563
6613
|
}
|
|
6564
6614
|
const taxIncluded = currentValue * (1 + rate);
|
|
6565
|
-
|
|
6615
|
+
const result = normalizeNumberString(taxIncluded, decimalPlaces);
|
|
6616
|
+
setExpression(result);
|
|
6617
|
+
setDisplayValue(result);
|
|
6566
6618
|
setError('');
|
|
6567
6619
|
};
|
|
6568
6620
|
const handleTaxExclude = (rate) => {
|
|
6569
6621
|
if (!enableTaxCalculation)
|
|
6570
6622
|
return;
|
|
6571
|
-
if (!
|
|
6623
|
+
if (!expression) {
|
|
6572
6624
|
setError('金額を入力してください');
|
|
6573
6625
|
return;
|
|
6574
6626
|
}
|
|
6575
|
-
const currentValue = parseFloat(calculateExpression(
|
|
6627
|
+
const currentValue = parseFloat(calculateExpression(expression));
|
|
6576
6628
|
if (isNaN(currentValue)) {
|
|
6577
6629
|
setError('有効な金額を入力してください');
|
|
6578
6630
|
return;
|
|
6579
6631
|
}
|
|
6580
6632
|
const taxExcluded = currentValue / (1 + rate);
|
|
6581
|
-
|
|
6633
|
+
const result = normalizeNumberString(taxExcluded, decimalPlaces);
|
|
6634
|
+
setExpression(result);
|
|
6635
|
+
setDisplayValue(result);
|
|
6582
6636
|
setError('');
|
|
6583
6637
|
};
|
|
6584
6638
|
if (!isOpen || !mounted)
|
|
6585
6639
|
return null;
|
|
6586
|
-
const modal = (jsxRuntime.jsx("div", { className: "calculator-overlay", children: jsxRuntime.jsxs("div", { className: "calculator-modal", children: [title || description ? (jsxRuntime.jsxs("div", { className: "calculator-header", children: [jsxRuntime.jsxs("div", { children: [title && jsxRuntime.jsx("h2", { className: "calculator-title", children: title }), description && jsxRuntime.jsx("p", { className: "calculator-subtitle", children: description })] }), jsxRuntime.jsx("button", { onClick: onClose, className: "calculator-close-button", "aria-label": "\u9589\u3058\u308B", children: jsxRuntime.jsx(Icon, { icon: faTimes, className: "w-5 h-5" }) })] })) : (jsxRuntime.jsxs("div", { className: "calculator-header", children: [jsxRuntime.jsx("div", {}), jsxRuntime.jsx("button", { onClick: onClose, className: "calculator-close-button", "aria-label": "\u9589\u3058\u308B", children: jsxRuntime.jsx(Icon, { icon: faTimes, className: "w-5 h-5" }) })] })), jsxRuntime.jsx("div", { className: "calculator-display", children: jsxRuntime.jsx(CalculatorDisplay, { value:
|
|
6640
|
+
const modal = (jsxRuntime.jsx("div", { className: "calculator-overlay", children: jsxRuntime.jsxs("div", { className: "calculator-modal", children: [title || description ? (jsxRuntime.jsxs("div", { className: "calculator-header", children: [jsxRuntime.jsxs("div", { children: [title && jsxRuntime.jsx("h2", { className: "calculator-title", children: title }), description && jsxRuntime.jsx("p", { className: "calculator-subtitle", children: description })] }), jsxRuntime.jsx("button", { onClick: onClose, className: "calculator-close-button", "aria-label": "\u9589\u3058\u308B", children: jsxRuntime.jsx(Icon, { icon: faTimes, className: "w-5 h-5" }) })] })) : (jsxRuntime.jsxs("div", { className: "calculator-header", children: [jsxRuntime.jsx("div", {}), jsxRuntime.jsx("button", { onClick: onClose, className: "calculator-close-button", "aria-label": "\u9589\u3058\u308B", children: jsxRuntime.jsx(Icon, { icon: faTimes, className: "w-5 h-5" }) })] })), jsxRuntime.jsx("div", { className: "calculator-display", children: jsxRuntime.jsx(CalculatorDisplay, { value: displayValue, error: error, inputRef: inputRef, editable: true, onChange: handleDisplayChange, numberFormatOptions: numberFormatOptions, placeholder: placeholder }) }), jsxRuntime.jsx(CalculatorKeypad, { onButtonClick: handleButtonClick, onEqual: handleEqual, onDecide: handleDecide, onTaxInclude: handleTaxInclude, onTaxExclude: handleTaxExclude, enableTaxCalculation: enableTaxCalculation, decimalPlaces: decimalPlaces })] }) }));
|
|
6587
6641
|
// DOM要素の存在確認を行ってからポータルを作成
|
|
6588
6642
|
if (typeof document !== 'undefined' && document.body) {
|
|
6589
6643
|
return reactDom.createPortal(modal, document.body);
|