calcsuite-react 1.1.0 → 1.1.1
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/CHANGELOG.md +8 -0
- package/README.md +3 -0
- package/dist/calcsuite.js +161 -157
- package/dist/settings/SettingsContext.d.ts +3 -1
- package/package.json +1 -1
- package/src/theme.css +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to **CalcSuite** are documented here. This project adheres to
|
|
4
4
|
[Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## [1.1.1] — 2026-09-04
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- **Dialog layers above host UI.** Raised the dialog / command-palette / toast z-index so CalcSuite renders above app chrome (e.g. MUI app bars & drawers) when embedded in another app.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **`<FinCalcProvider settings={…}>` now applies.** The provider accepts a deep-partial `settings` prop as *defaults* (region, currency, theme, …). The user's in-app choices still persist in `localStorage` and take precedence, so region stays user-driven.
|
|
13
|
+
|
|
6
14
|
## [1.1.0] — 2026-09-04
|
|
7
15
|
|
|
8
16
|
### Added
|
package/README.md
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
[](https://github.com/ashish13377/calcsuite/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/calcsuite-react)
|
|
5
5
|
[](LICENSE)
|
|
6
|
+
[](https://ashish13377.github.io/calcsuite/)
|
|
7
|
+
|
|
8
|
+
**▶ Live demo:** https://ashish13377.github.io/calcsuite/
|
|
6
9
|
|
|
7
10
|
**Decimal-exact, offline-first financial calculator library for React** — ~55 calculators for **🇮🇳 India (₹)** and **🇺🇸 United States ($)**, a scientific calculator, live currency conversion, export, and a keyboard-first launcher/dialog. All money math runs on `decimal.js` — no floating-point in any money path.
|
|
8
11
|
|
package/dist/calcsuite.js
CHANGED
|
@@ -3,7 +3,7 @@ var pa = (e, t, n) => t in e ? ma(e, t, { enumerable: !0, configurable: !0, writ
|
|
|
3
3
|
var ge = (e, t, n) => pa(e, typeof t != "symbol" ? t + "" : t, n);
|
|
4
4
|
import { jsx as o, jsxs as b, Fragment as re } from "react/jsx-runtime";
|
|
5
5
|
import { useState as M, useCallback as ke, useMemo as ne, useContext as ha, createContext as fa, useRef as de, useEffect as X, Fragment as xn, useSyncExternalStore as ya } from "react";
|
|
6
|
-
import
|
|
6
|
+
import dt from "decimal.js";
|
|
7
7
|
const ba = {
|
|
8
8
|
money: 2,
|
|
9
9
|
rate: 6,
|
|
@@ -29,7 +29,7 @@ const ba = {
|
|
|
29
29
|
persistence: { driver: "localStorage", namespace: "calcsuite", historyLimit: 100 },
|
|
30
30
|
features: { integrationPanel: !1, beta: !1 }
|
|
31
31
|
};
|
|
32
|
-
function
|
|
32
|
+
function xt(e) {
|
|
33
33
|
return e === "US" ? {
|
|
34
34
|
...qt,
|
|
35
35
|
region: "US",
|
|
@@ -68,12 +68,12 @@ function Nt(e) {
|
|
|
68
68
|
defaults: { tenureUnit: "both", rateType: "floating", maxRatePercent: 50, sipReturnPercent: "12", inflationPercent: "6" }
|
|
69
69
|
};
|
|
70
70
|
}
|
|
71
|
-
const Ze =
|
|
71
|
+
const Ze = xt("IN"), H = dt.clone({
|
|
72
72
|
precision: 40,
|
|
73
|
-
rounding:
|
|
73
|
+
rounding: dt.ROUND_HALF_UP,
|
|
74
74
|
toExpPos: 60,
|
|
75
75
|
toExpNeg: -60,
|
|
76
|
-
modulo:
|
|
76
|
+
modulo: dt.ROUND_DOWN
|
|
77
77
|
}), g = (e) => new H(e), cs = (e, t) => g(e).eq(t), us = (e, t) => g(e).gt(t), ds = (e, t) => g(e).lt(t), ce = (e, t = "1e-9") => e.abs().lt(t), ga = {
|
|
78
78
|
HALF_UP: H.ROUND_HALF_UP,
|
|
79
79
|
HALF_EVEN: H.ROUND_HALF_EVEN,
|
|
@@ -122,66 +122,70 @@ function Sn(e) {
|
|
|
122
122
|
};
|
|
123
123
|
return { settings: e, money: m, moneyParts: d, num: i, pct: (l, p = e.numberFormat.percentPlaces) => `${i(l, p)}%`, compact: u, round: n };
|
|
124
124
|
}
|
|
125
|
-
function
|
|
125
|
+
function mt(e) {
|
|
126
126
|
const t = Math.floor(e / 12), n = e % 12, a = [];
|
|
127
127
|
return t && a.push(`${t} yr`), n && a.push(`${n} mo`), a.join(" ") || "0 mo";
|
|
128
128
|
}
|
|
129
129
|
const Cn = fa(null), Pn = "calcsuite:settings";
|
|
130
|
-
function
|
|
130
|
+
function Xe(e, t) {
|
|
131
131
|
if (t == null) return e;
|
|
132
132
|
const n = Array.isArray(e) ? [...e] : { ...e };
|
|
133
133
|
for (const a of Object.keys(t)) {
|
|
134
134
|
const r = t[a], s = e[a];
|
|
135
|
-
n[a] = r && typeof r == "object" && !Array.isArray(r) && s && typeof s == "object" ?
|
|
135
|
+
n[a] = r && typeof r == "object" && !Array.isArray(r) && s && typeof s == "object" ? Xe(s, r) : r;
|
|
136
136
|
}
|
|
137
137
|
return n;
|
|
138
138
|
}
|
|
139
|
-
function ka() {
|
|
139
|
+
function ka(e) {
|
|
140
|
+
const t = e ? Xe(Ze, e) : Ze;
|
|
140
141
|
try {
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
142
|
+
const n = localStorage.getItem(Pn);
|
|
143
|
+
if (n) return Xe(t, JSON.parse(n));
|
|
143
144
|
} catch {
|
|
144
145
|
}
|
|
145
|
-
return
|
|
146
|
+
return t;
|
|
146
147
|
}
|
|
147
|
-
function
|
|
148
|
+
function pt(e) {
|
|
148
149
|
try {
|
|
149
150
|
e.persistence.driver === "localStorage" && localStorage.setItem(Pn, JSON.stringify(e));
|
|
150
151
|
} catch {
|
|
151
152
|
}
|
|
152
153
|
}
|
|
153
|
-
function ms({
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
function ms({
|
|
155
|
+
children: e,
|
|
156
|
+
settings: t
|
|
157
|
+
}) {
|
|
158
|
+
const [n, a] = M(() => ka(t)), r = ke((p) => {
|
|
159
|
+
a(p), pt(p);
|
|
160
|
+
}, []), s = ke((p) => a((h) => {
|
|
161
|
+
const f = Xe(h, p);
|
|
162
|
+
return pt(f), f;
|
|
163
|
+
}), []), u = ke((p) => {
|
|
164
|
+
a((h) => {
|
|
165
|
+
const y = { ...xt(p), ui: h.ui, compliance: h.compliance, persistence: h.persistence, features: h.features };
|
|
166
|
+
return pt(y), y;
|
|
163
167
|
});
|
|
164
|
-
}, []),
|
|
165
|
-
var
|
|
166
|
-
const
|
|
167
|
-
return
|
|
168
|
-
}, [
|
|
169
|
-
() => ({ settings:
|
|
170
|
-
[
|
|
168
|
+
}, []), m = ke(() => r(xt(n.region)), [r, n.region]), d = ke((p) => r(p), [r]), i = ne(() => Sn(n), [n]), c = ne(() => {
|
|
169
|
+
var h;
|
|
170
|
+
const p = n.ui.theme;
|
|
171
|
+
return p === "system" ? (h = window.matchMedia) != null && h.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "light" : p;
|
|
172
|
+
}, [n.ui.theme]), l = ne(
|
|
173
|
+
() => ({ settings: n, fmt: i, update: s, setRegion: u, reset: m, replace: d, resolvedTheme: c }),
|
|
174
|
+
[n, i, s, u, m, d, c]
|
|
171
175
|
);
|
|
172
|
-
return /* @__PURE__ */ o(Cn.Provider, { value:
|
|
176
|
+
return /* @__PURE__ */ o(Cn.Provider, { value: l, children: e });
|
|
173
177
|
}
|
|
174
178
|
function ue() {
|
|
175
179
|
const e = ha(Cn);
|
|
176
180
|
if (!e) throw new Error("useSettings must be used within SettingsProvider");
|
|
177
181
|
return e;
|
|
178
182
|
}
|
|
179
|
-
let
|
|
183
|
+
let Qe = 0;
|
|
180
184
|
const wa = () => {
|
|
181
|
-
|
|
185
|
+
Qe += 1;
|
|
182
186
|
}, Na = () => {
|
|
183
|
-
|
|
184
|
-
}, xa = () =>
|
|
187
|
+
Qe = Math.max(0, Qe - 1);
|
|
188
|
+
}, xa = () => Qe > 0, Sa = 'a[href],button:not([disabled]),textarea:not([disabled]),input:not([disabled]),select:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
185
189
|
function Ca({
|
|
186
190
|
open: e,
|
|
187
191
|
onClose: t,
|
|
@@ -261,7 +265,7 @@ function be(e, t, n, a = !1) {
|
|
|
261
265
|
let m = s.times(u.minus(1)).div(r);
|
|
262
266
|
return a && (m = m.times(r.plus(1))), m;
|
|
263
267
|
}
|
|
264
|
-
function
|
|
268
|
+
function et(e, t, n) {
|
|
265
269
|
return g(e).times(g(t).plus(1).pow(n));
|
|
266
270
|
}
|
|
267
271
|
function Tn(e, t, n, a = !1) {
|
|
@@ -285,7 +289,7 @@ function Ta(e, t, n) {
|
|
|
285
289
|
const a = g(n), r = g(e), s = g(t);
|
|
286
290
|
return ce(a) ? r.div(s) : H.ln(s.div(s.minus(r.times(a)))).div(H.ln(a.plus(1)));
|
|
287
291
|
}
|
|
288
|
-
function
|
|
292
|
+
function rt(e, t = -0.9999, n = 100, a = 200) {
|
|
289
293
|
let r = g(t), s = g(n), u = e(r), m = e(s);
|
|
290
294
|
if (u.times(m).gt(0)) return null;
|
|
291
295
|
for (let d = 0; d < a; d++) {
|
|
@@ -303,7 +307,7 @@ function At(e, t) {
|
|
|
303
307
|
return a;
|
|
304
308
|
}
|
|
305
309
|
function Fn(e) {
|
|
306
|
-
return
|
|
310
|
+
return rt((t) => At(t, e));
|
|
307
311
|
}
|
|
308
312
|
const Fa = (e, t) => (Date.parse(t) - Date.parse(e)) / 864e5;
|
|
309
313
|
function In(e, t) {
|
|
@@ -318,17 +322,17 @@ function In(e, t) {
|
|
|
318
322
|
function Rn(e) {
|
|
319
323
|
if (e.length < 2) return null;
|
|
320
324
|
const t = [...e].sort((n, a) => Date.parse(n.date) - Date.parse(a.date));
|
|
321
|
-
return
|
|
325
|
+
return rt((n) => In(n, t), -0.9999, 100);
|
|
322
326
|
}
|
|
323
|
-
function
|
|
327
|
+
function ot(e, t, n) {
|
|
324
328
|
return g(t).div(e).pow(g(1).div(n)).minus(1);
|
|
325
329
|
}
|
|
326
330
|
const ps = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
327
331
|
__proto__: null,
|
|
328
|
-
bisectRate:
|
|
329
|
-
cagr:
|
|
332
|
+
bisectRate: rt,
|
|
333
|
+
cagr: ot,
|
|
330
334
|
fvAnnuity: be,
|
|
331
|
-
fvLump:
|
|
335
|
+
fvLump: et,
|
|
332
336
|
irr: Fn,
|
|
333
337
|
nper: Ta,
|
|
334
338
|
npv: At,
|
|
@@ -374,8 +378,8 @@ class se extends Error {
|
|
|
374
378
|
this.name = "FinCalcError", this.code = n, this.field = r;
|
|
375
379
|
}
|
|
376
380
|
}
|
|
377
|
-
const Ia = 2, ee = (e) => e.toDecimalPlaces(Ia, H.ROUND_HALF_UP),
|
|
378
|
-
function
|
|
381
|
+
const Ia = 2, ee = (e) => e.toDecimalPlaces(Ia, H.ROUND_HALF_UP), St = (e) => e.div(100).div(12);
|
|
382
|
+
function Ct(e, t, n) {
|
|
379
383
|
if (ce(t)) return e.div(n);
|
|
380
384
|
const a = t.plus(1).pow(n);
|
|
381
385
|
return e.times(t).times(a).div(a.minus(1));
|
|
@@ -402,7 +406,7 @@ function Gt(e, t, n, a) {
|
|
|
402
406
|
throw new se("RATE_OUT_OF_RANGE", "Payment is too low to repay this amount.", "payment");
|
|
403
407
|
let r = g(0), s = g(a);
|
|
404
408
|
for (let m = 0; m < 200; m++) {
|
|
405
|
-
const d = r.plus(s).div(2), i =
|
|
409
|
+
const d = r.plus(s).div(2), i = Ct(e, St(d), t);
|
|
406
410
|
if (ce(i.minus(n), "1e-8")) return d;
|
|
407
411
|
i.lt(n) ? r = d : s = d;
|
|
408
412
|
}
|
|
@@ -466,10 +470,10 @@ function Ie(e) {
|
|
|
466
470
|
else throw s === "tenure" ? new se("MISSING_SOLVE_TARGET", "Flat-rate loans need an explicit tenure.", "tenureMonths") : new se("MISSING_SOLVE_TARGET", "Flat-rate loans need an explicit rate.", "annualRatePct");
|
|
467
471
|
c = Gt(u, d, i, t.maxRatePct), l = "Flat: interest = P × rate × years; EMI = (P + interest) / n";
|
|
468
472
|
} else {
|
|
469
|
-
const k = () =>
|
|
473
|
+
const k = () => St(m);
|
|
470
474
|
switch (s) {
|
|
471
475
|
case "payment":
|
|
472
|
-
i = ee(
|
|
476
|
+
i = ee(Ct(u, k(), d)), l = "PMT = P·r·(1+r)^n / ((1+r)^n − 1)";
|
|
473
477
|
break;
|
|
474
478
|
case "principal":
|
|
475
479
|
u = Ra(i, k(), d), l = "P = PMT·((1+r)^n − 1) / (r·(1+r)^n)";
|
|
@@ -482,7 +486,7 @@ function Ie(e) {
|
|
|
482
486
|
break;
|
|
483
487
|
}
|
|
484
488
|
}
|
|
485
|
-
const p =
|
|
489
|
+
const p = St(m), h = n === "flat" ? i : ee(Ct(u, p, d)), f = Ma(u, p, d, h);
|
|
486
490
|
d = f.length;
|
|
487
491
|
const y = f.reduce((k, S) => k.plus(S.interest), g(0)), w = f.reduce((k, S) => k.plus(S.payment), g(0));
|
|
488
492
|
return {
|
|
@@ -794,7 +798,7 @@ const Aa = {
|
|
|
794
798
|
let S = a;
|
|
795
799
|
for (let F = 1; F <= s; F++) S = S.plus(S.times(m)).minus(k.times(d(F)));
|
|
796
800
|
return S;
|
|
797
|
-
}, c = U(
|
|
801
|
+
}, c = U(rt((k) => i(k), 0, a.toNumber(), 200) ?? we(a, m, s)), l = [];
|
|
798
802
|
let p = a, h = g(0), f = c;
|
|
799
803
|
for (let k = 1; k <= s && p.gt("0.005"); k++) {
|
|
800
804
|
const S = U(p.times(m));
|
|
@@ -969,7 +973,7 @@ const Aa = {
|
|
|
969
973
|
Ba,
|
|
970
974
|
_a,
|
|
971
975
|
Ha
|
|
972
|
-
],
|
|
976
|
+
], it = Ze.defaults.sipReturnPercent, Ga = Ze.defaults.inflationPercent, st = (e, t) => ({
|
|
973
977
|
labels: e,
|
|
974
978
|
series: [{ name: "Value", tone: "accent", points: t, area: !0 }]
|
|
975
979
|
}), Dt = (e) => ({
|
|
@@ -987,7 +991,7 @@ const Aa = {
|
|
|
987
991
|
keywords: ["sip", "systematic investment plan", "mutual fund", "monthly investment", "future value"],
|
|
988
992
|
inputs: [
|
|
989
993
|
{ key: "monthlyAmount", label: "Monthly investment", kind: "money", prefix: "currency", default: "10000" },
|
|
990
|
-
{ key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default:
|
|
994
|
+
{ key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
|
|
991
995
|
{ key: "tenure", label: "Investment period", kind: "tenure", default: 120 }
|
|
992
996
|
],
|
|
993
997
|
compute(e, t) {
|
|
@@ -1005,7 +1009,7 @@ const Aa = {
|
|
|
1005
1009
|
],
|
|
1006
1010
|
split: Lt(i.toFixed(2), c.toFixed(2)),
|
|
1007
1011
|
schedule: Dt(p),
|
|
1008
|
-
chart:
|
|
1012
|
+
chart: st(p.map((f) => f.label), h),
|
|
1009
1013
|
formula: "FV = P·[((1+i)^n − 1) / i]·(1+i), i = r/12 (invested at the start of each month)",
|
|
1010
1014
|
notes: ["Returns are assumed constant; actual market returns vary year to year."],
|
|
1011
1015
|
raw: {
|
|
@@ -1025,7 +1029,7 @@ const Aa = {
|
|
|
1025
1029
|
inputs: [
|
|
1026
1030
|
{ key: "monthlyAmount", label: "Initial monthly investment", kind: "money", prefix: "currency", default: "10000" },
|
|
1027
1031
|
{ key: "annualStepPct", label: "Annual step-up", kind: "percent", suffix: "%", default: "10" },
|
|
1028
|
-
{ key: "returnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default:
|
|
1032
|
+
{ key: "returnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
|
|
1029
1033
|
{ key: "tenure", label: "Investment period", kind: "tenure", default: 120 }
|
|
1030
1034
|
],
|
|
1031
1035
|
compute(e, t) {
|
|
@@ -1044,7 +1048,7 @@ const Aa = {
|
|
|
1044
1048
|
],
|
|
1045
1049
|
split: Lt(c.toFixed(2), f.toFixed(2)),
|
|
1046
1050
|
schedule: Dt(p),
|
|
1047
|
-
chart:
|
|
1051
|
+
chart: st(p.map((y) => y.label), h),
|
|
1048
1052
|
formula: "Monthly simulation; the SIP amount is increased by the step-up % every 12 months",
|
|
1049
1053
|
notes: ["The monthly amount steps up on each yearly anniversary; returns are assumed constant."],
|
|
1050
1054
|
raw: { maturity: i.toFixed(2), invested: c.toFixed(2), gains: f.toFixed(2), finalMonthly: l.toFixed(2) }
|
|
@@ -1058,7 +1062,7 @@ const Aa = {
|
|
|
1058
1062
|
keywords: ["lump sum", "lumpsum", "one time investment", "compound interest", "maturity"],
|
|
1059
1063
|
inputs: [
|
|
1060
1064
|
{ key: "principal", label: "Investment amount", kind: "money", prefix: "currency", default: "100000" },
|
|
1061
|
-
{ key: "ratePct", label: "Expected return", kind: "percent", suffix: "% p.a.", default:
|
|
1065
|
+
{ key: "ratePct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
|
|
1062
1066
|
{ key: "years", label: "Investment period", kind: "years", suffix: "years", default: 10 },
|
|
1063
1067
|
{
|
|
1064
1068
|
key: "compounding",
|
|
@@ -1074,7 +1078,7 @@ const Aa = {
|
|
|
1074
1078
|
}
|
|
1075
1079
|
],
|
|
1076
1080
|
compute(e, t) {
|
|
1077
|
-
const { D: n, fmt: a } = t, r = D(e.principal, "100000"), s = n(C(e.ratePct, Number(t.settings.defaults.sipReturnPercent))), u = Math.max(1, Math.round(C(e.years, 10))), m = Ya[_(e.compounding, "annual")] ?? 1, d = s.div(100).div(m), i = r.times(d.plus(1).pow(m * u)), c = i.minus(r), l = r.isZero() ? n(0) :
|
|
1081
|
+
const { D: n, fmt: a } = t, r = D(e.principal, "100000"), s = n(C(e.ratePct, Number(t.settings.defaults.sipReturnPercent))), u = Math.max(1, Math.round(C(e.years, 10))), m = Ya[_(e.compounding, "annual")] ?? 1, d = s.div(100).div(m), i = r.times(d.plus(1).pow(m * u)), c = i.minus(r), l = r.isZero() ? n(0) : ot(r, i, u), p = [], h = [];
|
|
1078
1082
|
for (let f = 1; f <= u; f++) {
|
|
1079
1083
|
const y = r.times(d.plus(1).pow(m * f));
|
|
1080
1084
|
p.push({ label: String(f), cells: [a.money(r), a.money(y.minus(r)), a.money(y)] }), h.push(Number(y.toFixed(2)));
|
|
@@ -1088,7 +1092,7 @@ const Aa = {
|
|
|
1088
1092
|
],
|
|
1089
1093
|
split: Lt(r.toFixed(2), c.toFixed(2)),
|
|
1090
1094
|
schedule: Dt(p),
|
|
1091
|
-
chart:
|
|
1095
|
+
chart: st(p.map((f) => f.label), h),
|
|
1092
1096
|
formula: "A = P·(1 + r/f)^(f·t)",
|
|
1093
1097
|
notes: ["Returns are assumed constant across the whole period."],
|
|
1094
1098
|
raw: { maturity: i.toFixed(2), invested: r.toFixed(2), gains: c.toFixed(2), cagr: l.times(100).toFixed(4) }
|
|
@@ -1133,7 +1137,7 @@ const Aa = {
|
|
|
1133
1137
|
rows: h,
|
|
1134
1138
|
toneCols: { 2: "interest", 3: "principal" }
|
|
1135
1139
|
},
|
|
1136
|
-
chart:
|
|
1140
|
+
chart: st(h.map((N) => N.label), f),
|
|
1137
1141
|
formula: "Each month: balance = balance·(1 + r/12) − withdrawal",
|
|
1138
1142
|
notes: [
|
|
1139
1143
|
S ? `The corpus is exhausted in month ${p}; the final withdrawal may be partial.` : "The corpus survives the whole withdrawal period; the remaining balance is shown.",
|
|
@@ -1155,12 +1159,12 @@ const Aa = {
|
|
|
1155
1159
|
inputs: [
|
|
1156
1160
|
{ key: "targetCorpus", label: "Today's cost of goal", kind: "money", prefix: "currency", default: "10000000" },
|
|
1157
1161
|
{ key: "years", label: "Years to goal", kind: "years", suffix: "years", default: 15 },
|
|
1158
|
-
{ key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default:
|
|
1162
|
+
{ key: "expectedReturnPct", label: "Expected return", kind: "percent", suffix: "% p.a.", default: it },
|
|
1159
1163
|
{ key: "inflationPct", label: "Inflation", kind: "percent", suffix: "% p.a.", default: Ga },
|
|
1160
1164
|
{ key: "existingSavings", label: "Existing savings", kind: "money", prefix: "currency", default: "0", optional: !0 }
|
|
1161
1165
|
],
|
|
1162
1166
|
compute(e, t) {
|
|
1163
|
-
const { D: n, fmt: a } = t, r = D(e.targetCorpus, "10000000"), s = Math.max(1, Math.round(C(e.years, 15))), u = C(e.expectedReturnPct, Number(t.settings.defaults.sipReturnPercent)), m = n(C(e.inflationPct, Number(t.settings.defaults.inflationPercent))).div(100), d = D(e.existingSavings, "0"), i = s * 12, c = J(u, 12), l = r.times(m.plus(1).pow(s)), p =
|
|
1167
|
+
const { D: n, fmt: a } = t, r = D(e.targetCorpus, "10000000"), s = Math.max(1, Math.round(C(e.years, 15))), u = C(e.expectedReturnPct, Number(t.settings.defaults.sipReturnPercent)), m = n(C(e.inflationPct, Number(t.settings.defaults.inflationPercent))).div(100), d = D(e.existingSavings, "0"), i = s * 12, c = J(u, 12), l = r.times(m.plus(1).pow(s)), p = et(d, c, i), h = l.minus(p), f = be(1, c, i, !0), y = h.gt(0) ? h.div(f) : n(0), w = y.times(i), k = h.gt(0) ? h.minus(w) : n(0), S = [
|
|
1164
1168
|
`Target grows with ${a.pct(m.times(100))} inflation to ${a.money(l)} in ${s} years.`
|
|
1165
1169
|
];
|
|
1166
1170
|
d.gt(0) && S.push(`Existing savings grow to ${a.money(p)}, reducing what the SIP must fund.`);
|
|
@@ -1636,7 +1640,7 @@ const Aa = {
|
|
|
1636
1640
|
{ key: "collegeCostInflationPct", label: "College cost inflation", kind: "percent", suffix: "%", default: 5, advanced: !0 }
|
|
1637
1641
|
],
|
|
1638
1642
|
compute(e, t) {
|
|
1639
|
-
const { fmt: n } = t, a = g(C(e.currentSavings)), r = g(C(e.monthlyContribution)), s = Math.max(0, Math.round(C(e.yearsUntilCollege))), u = s * 12, m = J(C(e.expectedReturnPct), 12), d =
|
|
1643
|
+
const { fmt: n } = t, a = g(C(e.currentSavings)), r = g(C(e.monthlyContribution)), s = Math.max(0, Math.round(C(e.yearsUntilCollege))), u = s * 12, m = J(C(e.expectedReturnPct), 12), d = et(a, m, u), i = be(r, m, u), c = d.plus(i), l = a.plus(r.times(u)), p = c.minus(l), h = [
|
|
1640
1644
|
v("Total invested", n.money(l), "principal"),
|
|
1641
1645
|
v("Investment growth", n.money(p), "interest")
|
|
1642
1646
|
], f = {
|
|
@@ -1650,7 +1654,7 @@ const Aa = {
|
|
|
1650
1654
|
const k = g(C(e.currentAnnualCost)), S = g(C(e.collegeCostInflationPct)).div(100);
|
|
1651
1655
|
let F = g(0);
|
|
1652
1656
|
for (let x = 0; x < 4; x++)
|
|
1653
|
-
F = F.plus(
|
|
1657
|
+
F = F.plus(et(k, S, s + x));
|
|
1654
1658
|
const N = c.minus(F), P = N.gte(0);
|
|
1655
1659
|
h.push(v("4-year college cost", n.money(F), "default", "inflation-adjusted")), h.push(
|
|
1656
1660
|
v(
|
|
@@ -1675,7 +1679,7 @@ const Aa = {
|
|
|
1675
1679
|
raw: f
|
|
1676
1680
|
};
|
|
1677
1681
|
}
|
|
1678
|
-
}, lr = [or, ir, sr], cr = (e) => e === "annual" ? 1 : e === "semiannual" ? 2 : e === "quarterly" ? 4 : 12,
|
|
1682
|
+
}, lr = [or, ir, sr], cr = (e) => e === "annual" ? 1 : e === "semiannual" ? 2 : e === "quarterly" ? 4 : 12, lt = (e) => _(e).split(/[, ]+/).map((t) => t.trim()).filter(Boolean).map(Number).filter((t) => Number.isFinite(t)), ur = {
|
|
1679
1683
|
id: "returns.tvm",
|
|
1680
1684
|
group: "returns",
|
|
1681
1685
|
title: "Time value of money (TVM)",
|
|
@@ -1755,7 +1759,7 @@ const Aa = {
|
|
|
1755
1759
|
{ key: "years", label: "Period", kind: "years", default: "10" }
|
|
1756
1760
|
],
|
|
1757
1761
|
compute(e, t) {
|
|
1758
|
-
const n = t.D(C(e.begin)), a = t.D(C(e.end)), r = C(e.years) || 1, s =
|
|
1762
|
+
const n = t.D(C(e.begin)), a = t.D(C(e.end)), r = C(e.years) || 1, s = ot(n, a, r).times(100), u = a.minus(n).div(n).times(100);
|
|
1759
1763
|
return {
|
|
1760
1764
|
primary: v("CAGR", `${t.fmt.num(s, 2)}%`, "accent"),
|
|
1761
1765
|
secondary: [
|
|
@@ -1779,7 +1783,7 @@ const Aa = {
|
|
|
1779
1783
|
],
|
|
1780
1784
|
compute(e, t) {
|
|
1781
1785
|
const n = t.D(C(e.invested)), a = t.D(C(e.current)), r = a.minus(n).div(n).times(100), s = C(e.years), u = [v("Total gain", t.fmt.money(a.minus(n)), a.gte(n) ? "positive" : "negative")];
|
|
1782
|
-
return s > 0 && u.push(v("Annualised (CAGR)", `${t.fmt.num(
|
|
1786
|
+
return s > 0 && u.push(v("Annualised (CAGR)", `${t.fmt.num(ot(n, a, s).times(100), 2)}%`)), {
|
|
1783
1787
|
primary: v("Absolute return", `${t.fmt.num(r, 2)}%`, "accent"),
|
|
1784
1788
|
secondary: u,
|
|
1785
1789
|
formula: "Absolute return = (Current − Invested) / Invested",
|
|
@@ -1819,7 +1823,7 @@ const Aa = {
|
|
|
1819
1823
|
keywords: ["irr", "internal rate of return"],
|
|
1820
1824
|
inputs: [{ key: "series", label: "Cashflows (comma-separated, period 0 first)", kind: "text", default: "-100000, 30000, 40000, 50000, 40000", help: "-100000, 30000, ..." }],
|
|
1821
1825
|
compute(e, t) {
|
|
1822
|
-
const n =
|
|
1826
|
+
const n = lt(_(e.series));
|
|
1823
1827
|
if (n.length < 2) return { primary: v("IRR", "—"), warnings: ["Enter at least two cashflows."] };
|
|
1824
1828
|
const a = Fn(n);
|
|
1825
1829
|
return a ? { primary: v("IRR", `${t.fmt.num(a.times(100), 2)}%`, "accent"), formula: "IRR: rate where NPV = 0", raw: { irr: a.times(100).toNumber() } } : { primary: v("IRR", "—"), warnings: ["No sign change — IRR is undefined for these flows."] };
|
|
@@ -1835,7 +1839,7 @@ const Aa = {
|
|
|
1835
1839
|
{ key: "series", label: "Cashflows (comma-separated, period 0 first)", kind: "text", default: "-100000, 30000, 40000, 50000, 40000" }
|
|
1836
1840
|
],
|
|
1837
1841
|
compute(e, t) {
|
|
1838
|
-
const n =
|
|
1842
|
+
const n = lt(_(e.series)), a = At(g(C(e.ratePct)).div(100), n);
|
|
1839
1843
|
return {
|
|
1840
1844
|
primary: v("NPV", t.fmt.money(a), a.gte(0) ? "positive" : "negative"),
|
|
1841
1845
|
secondary: [v(a.gte(0) ? "Value-creating" : "Value-destroying", a.gte(0) ? "NPV ≥ 0" : "NPV < 0")],
|
|
@@ -1855,7 +1859,7 @@ const Aa = {
|
|
|
1855
1859
|
{ key: "reinvestPct", label: "Reinvestment rate", kind: "percent", default: "12" }
|
|
1856
1860
|
],
|
|
1857
1861
|
compute(e, t) {
|
|
1858
|
-
const n =
|
|
1862
|
+
const n = lt(_(e.series)), a = n.length - 1;
|
|
1859
1863
|
if (a < 1) return { primary: v("MIRR", "—"), warnings: ["Enter at least two cashflows."] };
|
|
1860
1864
|
const r = g(C(e.financePct)).div(100), s = g(C(e.reinvestPct)).div(100);
|
|
1861
1865
|
let u = g(0), m = g(0);
|
|
@@ -1877,7 +1881,7 @@ const Aa = {
|
|
|
1877
1881
|
{ key: "discountPct", label: "Discount rate (for discounted payback)", kind: "percent", default: "0", optional: !0, advanced: !0 }
|
|
1878
1882
|
],
|
|
1879
1883
|
compute(e, t) {
|
|
1880
|
-
const n = t.D(C(e.investment)), a =
|
|
1884
|
+
const n = t.D(C(e.investment)), a = lt(_(e.series)), r = g(C(e.discountPct)).div(100), s = r.gt(0);
|
|
1881
1885
|
let u = g(0), m = 0, d = null;
|
|
1882
1886
|
for (let i = 0; i < a.length; i++) {
|
|
1883
1887
|
const c = s ? g(a[i]).div(r.plus(1).pow(i + 1)) : g(a[i]), l = u;
|
|
@@ -1962,7 +1966,7 @@ function Ut(e, t, n) {
|
|
|
1962
1966
|
}
|
|
1963
1967
|
return { tax: a, rows: s };
|
|
1964
1968
|
}
|
|
1965
|
-
const wr = (e, t) => Ut(e, t, Nr).tax, Nr = { money: (e) => String(e) }, jt = (e, t) => e.gt(t) ? g(t) : e,
|
|
1969
|
+
const wr = (e, t) => Ut(e, t, Nr).tax, Nr = { money: (e) => String(e) }, jt = (e, t) => e.gt(t) ? g(t) : e, ct = (e, t) => v(e, t, "positive"), xr = {
|
|
1966
1970
|
id: "tax.gst",
|
|
1967
1971
|
group: "tax",
|
|
1968
1972
|
title: "GST Calculator",
|
|
@@ -2077,7 +2081,7 @@ const wr = (e, t) => Ut(e, t, Nr).tax, Nr = { money: (e) => String(e) }, jt = (e
|
|
|
2077
2081
|
), {
|
|
2078
2082
|
primary: v("TDS deducted", n.money(p), p.gt(0) ? "negative" : "positive"),
|
|
2079
2083
|
secondary: [
|
|
2080
|
-
|
|
2084
|
+
ct("Net interest received", n.money(h)),
|
|
2081
2085
|
v("Effective TDS rate", n.pct(f), "accent"),
|
|
2082
2086
|
v("Applicable threshold", n.money(d), "default")
|
|
2083
2087
|
],
|
|
@@ -2244,7 +2248,7 @@ const Tr = {
|
|
|
2244
2248
|
l.lt(h) && (h = l), p.lt(h) && (h = p);
|
|
2245
2249
|
const f = s.minus(h);
|
|
2246
2250
|
return {
|
|
2247
|
-
primary:
|
|
2251
|
+
primary: ct("HRA exempt", n.money(h)),
|
|
2248
2252
|
secondary: [
|
|
2249
2253
|
v("Taxable HRA", n.money(f), "negative"),
|
|
2250
2254
|
v("HRA received", n.money(s), "principal"),
|
|
@@ -2405,7 +2409,7 @@ const Tr = {
|
|
|
2405
2409
|
v("Taxable income", n.money(i), "principal", `after ${n.money(m)} deduction`),
|
|
2406
2410
|
v("Effective rate", n.pct(p), "accent"),
|
|
2407
2411
|
v("Marginal rate", `${f}%`, "default"),
|
|
2408
|
-
|
|
2412
|
+
ct("After-tax income", n.money(y))
|
|
2409
2413
|
],
|
|
2410
2414
|
schedule: {
|
|
2411
2415
|
title: "Bracket breakdown",
|
|
@@ -2445,7 +2449,7 @@ const Tr = {
|
|
|
2445
2449
|
"Acquisition-debt limit is $750,000 ($375,000 if married filing separately) for loans after 15 Dec 2017. " + Ne
|
|
2446
2450
|
];
|
|
2447
2451
|
return s.gt(u) && i.unshift(`Loan balance exceeds $750k: only ${n.pct(g(u).div(s).times(100))} of the interest is deductible.`), {
|
|
2448
|
-
primary:
|
|
2452
|
+
primary: ct("Estimated tax savings", n.money(d)),
|
|
2449
2453
|
secondary: [
|
|
2450
2454
|
v("Deductible interest", n.money(m), "principal"),
|
|
2451
2455
|
v("Marginal tax rate", n.pct(g(C(e.marginalTaxRatePct, 24))), "accent")
|
|
@@ -2470,7 +2474,7 @@ const Tr = {
|
|
|
2470
2474
|
area: { sqm: 1, sqft: 0.092903, sqyd: 0.836127, acre: 4046.8564224, hectare: 1e4, bigha: 1337.8, gunta: 101.17, cent: 40.4686 },
|
|
2471
2475
|
weight: { kg: 1, g: 1e-3, mg: 1e-6, lb: 0.45359237, oz: 0.0283495, tonne: 1e3, quintal: 100 },
|
|
2472
2476
|
volume: { l: 1, ml: 1e-3, m3: 1e3, gal_us: 3.785411784, gal_uk: 4.54609, cup: 0.24, pint: 0.473176 }
|
|
2473
|
-
},
|
|
2477
|
+
}, Pt = {
|
|
2474
2478
|
m: "Meters (m)",
|
|
2475
2479
|
km: "Kilometers (km)",
|
|
2476
2480
|
cm: "Centimeters (cm)",
|
|
@@ -2504,7 +2508,7 @@ const Tr = {
|
|
|
2504
2508
|
C: "Celsius (°C)",
|
|
2505
2509
|
F: "Fahrenheit (°F)",
|
|
2506
2510
|
K: "Kelvin (K)"
|
|
2507
|
-
}, Lr = ["C", "F", "K"], Wt = (e) => e.map((t) => ({ value: t, label:
|
|
2511
|
+
}, Lr = ["C", "F", "K"], Wt = (e) => e.map((t) => ({ value: t, label: Pt[t] ?? t })), Ae = (e, t, n, a) => [
|
|
2508
2512
|
{ key: `${e}From`, label: "From", kind: "select", default: n, options: Wt(t), showIf: (r) => r.category === e },
|
|
2509
2513
|
{ key: `${e}To`, label: "To", kind: "select", default: a, options: Wt(t), showIf: (r) => r.category === e }
|
|
2510
2514
|
], Ur = {
|
|
@@ -2544,21 +2548,21 @@ const Tr = {
|
|
|
2544
2548
|
const p = $e[s];
|
|
2545
2549
|
i = r.times(p[u] ?? 1).div(p[m] ?? 1), (u === "bigha" || m === "bigha") && d.push("Bigha is not standardised — its size varies by state; this uses a common ~1337.8 m² value.");
|
|
2546
2550
|
}
|
|
2547
|
-
const c =
|
|
2551
|
+
const c = Pt[u] ?? u, l = Pt[m] ?? m;
|
|
2548
2552
|
return {
|
|
2549
2553
|
primary: v(`${r.toString()} ${c} =`, `${a.num(i, 4)} ${l}`, "accent"),
|
|
2550
2554
|
notes: d,
|
|
2551
2555
|
raw: { result: i.toFixed(6), from: u, to: m, category: s }
|
|
2552
2556
|
};
|
|
2553
2557
|
}
|
|
2554
|
-
}, je = 864e5,
|
|
2558
|
+
}, je = 864e5, ht = (e) => {
|
|
2555
2559
|
if (!e) {
|
|
2556
2560
|
const r = /* @__PURE__ */ new Date();
|
|
2557
2561
|
return new Date(Date.UTC(r.getUTCFullYear(), r.getUTCMonth(), r.getUTCDate()));
|
|
2558
2562
|
}
|
|
2559
2563
|
const [t, n, a] = e.split("-").map(Number);
|
|
2560
2564
|
return new Date(Date.UTC(t, (n || 1) - 1, a || 1));
|
|
2561
|
-
},
|
|
2565
|
+
}, ft = (e, t) => new Date(Date.UTC(e, t, 0)).getUTCDate(), Ve = (e) => e.toISOString().slice(0, 10), Or = {
|
|
2562
2566
|
id: "tools.dateCalc",
|
|
2563
2567
|
group: "tools",
|
|
2564
2568
|
title: "Date Calculator",
|
|
@@ -2605,15 +2609,15 @@ const Tr = {
|
|
|
2605
2609
|
],
|
|
2606
2610
|
compute(e) {
|
|
2607
2611
|
if (_(e.mode, "difference") === "addSubtract") {
|
|
2608
|
-
const l =
|
|
2612
|
+
const l = ht(_(e.startDate, "")), p = Math.round(C(e.count, 0)), h = _(e.unit, "days"), f = _(e.direction, "add") === "subtract" ? -1 : 1, y = f * p;
|
|
2609
2613
|
let w;
|
|
2610
2614
|
if (h === "days" || h === "weeks")
|
|
2611
2615
|
w = new Date(l.getTime() + y * (h === "weeks" ? 7 : 1) * je);
|
|
2612
2616
|
else if (h === "months") {
|
|
2613
|
-
const S = l.getUTCMonth() + y, F = l.getUTCFullYear() + Math.floor(S / 12), N = (S % 12 + 12) % 12, P = Math.min(l.getUTCDate(),
|
|
2617
|
+
const S = l.getUTCMonth() + y, F = l.getUTCFullYear() + Math.floor(S / 12), N = (S % 12 + 12) % 12, P = Math.min(l.getUTCDate(), ft(F, N + 1));
|
|
2614
2618
|
w = new Date(Date.UTC(F, N, P));
|
|
2615
2619
|
} else {
|
|
2616
|
-
const S = l.getUTCFullYear() + y, F = Math.min(l.getUTCDate(),
|
|
2620
|
+
const S = l.getUTCFullYear() + y, F = Math.min(l.getUTCDate(), ft(S, l.getUTCMonth() + 1));
|
|
2617
2621
|
w = new Date(Date.UTC(S, l.getUTCMonth(), F));
|
|
2618
2622
|
}
|
|
2619
2623
|
const k = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][w.getUTCDay()];
|
|
@@ -2623,10 +2627,10 @@ const Tr = {
|
|
|
2623
2627
|
raw: { resultDate: Ve(w), weekday: k, from: Ve(l) }
|
|
2624
2628
|
};
|
|
2625
2629
|
}
|
|
2626
|
-
let n =
|
|
2630
|
+
let n = ht(_(e.startDate, "")), a = ht(_(e.endDate, "")), r = !1;
|
|
2627
2631
|
a.getTime() < n.getTime() && ([n, a] = [a, n], r = !0);
|
|
2628
2632
|
let s = a.getUTCFullYear() - n.getUTCFullYear(), u = a.getUTCMonth() - n.getUTCMonth(), m = a.getUTCDate() - n.getUTCDate();
|
|
2629
|
-
m < 0 && (u -= 1, m +=
|
|
2633
|
+
m < 0 && (u -= 1, m += ft(a.getUTCFullYear(), a.getUTCMonth())), u < 0 && (s -= 1, u += 12);
|
|
2630
2634
|
const d = Math.round((a.getTime() - n.getTime()) / je);
|
|
2631
2635
|
let i = 0;
|
|
2632
2636
|
for (let l = n.getTime() + je; l <= a.getTime(); l += je) {
|
|
@@ -2645,22 +2649,22 @@ const Tr = {
|
|
|
2645
2649
|
raw: { years: s, months: u, days: m, totalDays: d, weeks: Number((d / 7).toFixed(2)), businessDays: i }
|
|
2646
2650
|
};
|
|
2647
2651
|
}
|
|
2648
|
-
},
|
|
2652
|
+
}, Tt = ["Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"], Br = ["", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"], tt = (e) => e < 20 ? Tt[e] : Br[Math.floor(e / 10)] + (e % 10 ? " " + Tt[e % 10] : ""), Ft = (e) => {
|
|
2649
2653
|
const t = Math.floor(e / 100), n = e % 100, a = [];
|
|
2650
|
-
return t && a.push(
|
|
2654
|
+
return t && a.push(Tt[t] + " Hundred"), n && a.push(tt(n)), a.join(" ");
|
|
2651
2655
|
}, An = (e) => {
|
|
2652
2656
|
if (e === 0) return "Zero";
|
|
2653
2657
|
const t = ["", " Thousand", " Million", " Billion", " Trillion"], n = [];
|
|
2654
2658
|
let a = 0;
|
|
2655
2659
|
for (; e > 0 && a < t.length; ) {
|
|
2656
2660
|
const r = e % 1e3;
|
|
2657
|
-
r && n.unshift(
|
|
2661
|
+
r && n.unshift(Ft(r) + t[a]), e = Math.floor(e / 1e3), a++;
|
|
2658
2662
|
}
|
|
2659
2663
|
return n.length ? n.join(" ") : "Zero";
|
|
2660
2664
|
}, _r = (e) => {
|
|
2661
2665
|
if (e === 0) return "Zero";
|
|
2662
2666
|
const t = Math.floor(e / 1e7), n = Math.floor(e / 1e5) % 100, a = Math.floor(e / 1e3) % 100, r = e % 1e3, s = [];
|
|
2663
|
-
return t && s.push((t <= 999 ?
|
|
2667
|
+
return t && s.push((t <= 999 ? Ft(t) : An(t)) + " Crore"), n && s.push(tt(n) + " Lakh"), a && s.push(tt(a) + " Thousand"), r && s.push(Ft(r)), s.join(" ");
|
|
2664
2668
|
}, Hr = {
|
|
2665
2669
|
id: "tools.numToWords",
|
|
2666
2670
|
group: "tools",
|
|
@@ -2684,7 +2688,7 @@ const Tr = {
|
|
|
2684
2688
|
compute(e, t) {
|
|
2685
2689
|
const { D: n, fmt: a } = t, r = _(e.scale, "indian"), s = ye(e.cheque, !1), u = n(_(e.amount, "0").replace(/[, ]/g, "") || "0"), m = u.isNegative(), d = u.abs(), i = d.floor(), c = Number(d.minus(i).times(100).toDecimalPlaces(0).toString()), l = Number(i.toString()), p = t.settings.currency.code, h = p === "INR" ? "Rupees" : p === "USD" ? "Dollars" : p, f = p === "INR" ? "Paise" : "Cents";
|
|
2686
2690
|
let y = r === "western" ? An(l) : _r(l);
|
|
2687
|
-
return c > 0 && (y += ` and ${
|
|
2691
|
+
return c > 0 && (y += ` and ${tt(c)} ${f}`), s && (y = `${h} ${y} Only`), m && (y = `Minus ${y}`), {
|
|
2688
2692
|
primary: v("In words", y, "accent"),
|
|
2689
2693
|
secondary: [v("In figures", a.num(u, c > 0 ? 2 : 0))],
|
|
2690
2694
|
notes: ['Words are Title Case with the chosen number scale; the cheque format adds the currency name and "Only".'],
|
|
@@ -2731,17 +2735,17 @@ const Tr = {
|
|
|
2731
2735
|
...Dr,
|
|
2732
2736
|
...qr,
|
|
2733
2737
|
...Gr
|
|
2734
|
-
],
|
|
2738
|
+
], It = [];
|
|
2735
2739
|
function hs(e) {
|
|
2736
|
-
|
|
2740
|
+
It.some((t) => t.id === e.id) || It.push(e);
|
|
2737
2741
|
}
|
|
2738
2742
|
function Dn() {
|
|
2739
|
-
return [...Yr, ...
|
|
2743
|
+
return [...Yr, ...It];
|
|
2740
2744
|
}
|
|
2741
2745
|
function Kr(e) {
|
|
2742
2746
|
return Dn().filter((t) => !t.regions || t.regions.includes(e));
|
|
2743
2747
|
}
|
|
2744
|
-
function
|
|
2748
|
+
function Rt(e) {
|
|
2745
2749
|
return Dn().find((t) => t.id === e);
|
|
2746
2750
|
}
|
|
2747
2751
|
const Wr = [
|
|
@@ -3042,19 +3046,19 @@ function oo(e) {
|
|
|
3042
3046
|
var t;
|
|
3043
3047
|
return e ? e.groups ? e.groups.reduce((n, a) => n + a.rows.length, 0) : ((t = e.rows) == null ? void 0 : t.length) ?? 0 : 0;
|
|
3044
3048
|
}
|
|
3045
|
-
function
|
|
3049
|
+
function Et(e) {
|
|
3046
3050
|
return String(e ?? "").replace(/[/\\]/g, "-").replace(/[-<>:"|?*]/g, "").trim().replace(/^\.+/, "") || "export";
|
|
3047
3051
|
}
|
|
3048
3052
|
function ve(e, t) {
|
|
3049
3053
|
var m;
|
|
3050
|
-
const n = new Date(((m = e.meta) == null ? void 0 : m.computedAt) || Date.now()), a = n.getFullYear(), r = String(n.getMonth() + 1).padStart(2, "0"), s = String(n.getDate()).padStart(2, "0"), u =
|
|
3051
|
-
return
|
|
3054
|
+
const n = new Date(((m = e.meta) == null ? void 0 : m.computedAt) || Date.now()), a = n.getFullYear(), r = String(n.getMonth() + 1).padStart(2, "0"), s = String(n.getDate()).padStart(2, "0"), u = Et(e.calculatorId || e.title || "export");
|
|
3055
|
+
return Et(`${u}-${a}${r}${s}.${t}`);
|
|
3052
3056
|
}
|
|
3053
3057
|
function Se(e, t, n = "application/octet-stream") {
|
|
3054
3058
|
if (!Ot() || typeof URL > "u" || !URL.createObjectURL)
|
|
3055
3059
|
throw new Error("Download is only available in the browser.");
|
|
3056
3060
|
const a = t instanceof Blob ? t : new Blob([t], { type: n }), r = URL.createObjectURL(a), s = document.createElement("a");
|
|
3057
|
-
s.href = r, s.download =
|
|
3061
|
+
s.href = r, s.download = Et(e), s.style.display = "none", document.body.appendChild(s), s.click(), setTimeout(() => {
|
|
3058
3062
|
URL.revokeObjectURL(r), s.remove();
|
|
3059
3063
|
}, 0);
|
|
3060
3064
|
}
|
|
@@ -3482,7 +3486,7 @@ function Wn() {
|
|
|
3482
3486
|
payment: T ? t.money(T.payment) : "—",
|
|
3483
3487
|
principal: T ? t.money(T.principal) : "—",
|
|
3484
3488
|
rate: T ? `${t.num(T.annualRatePct, 3)} %` : "—",
|
|
3485
|
-
tenure: T ?
|
|
3489
|
+
tenure: T ? mt(T.tenureMonths) : "—"
|
|
3486
3490
|
}, G = T ? t.moneyParts(T.payment) : { symbol: "", digits: "—" }, q = e.currency.symbol, A = {
|
|
3487
3491
|
region: n,
|
|
3488
3492
|
basis: u,
|
|
@@ -3523,7 +3527,7 @@ function Wn() {
|
|
|
3523
3527
|
{ label: "Principal", value: t.money(R.principal) },
|
|
3524
3528
|
{ label: "Total interest", value: t.money(R.totalInterest), tone: "interest" },
|
|
3525
3529
|
{ label: "Total payment", value: t.money(R.totalPayment) },
|
|
3526
|
-
{ label: a.tenureWord, value:
|
|
3530
|
+
{ label: a.tenureWord, value: mt(R.tenureMonths) }
|
|
3527
3531
|
],
|
|
3528
3532
|
schedule: j,
|
|
3529
3533
|
formula: R.formula,
|
|
@@ -3559,8 +3563,8 @@ function Wn() {
|
|
|
3559
3563
|
] })
|
|
3560
3564
|
] }),
|
|
3561
3565
|
/* @__PURE__ */ b("div", { className: "grid two", children: [
|
|
3562
|
-
/* @__PURE__ */ o(
|
|
3563
|
-
/* @__PURE__ */ o(
|
|
3566
|
+
/* @__PURE__ */ o(yt, { label: "Loan amount", solved: L("principal"), solvedText: B.principal, affix: q, children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: d, onChange: (R) => i(R.target.value), "aria-label": "Loan amount" }) }),
|
|
3567
|
+
/* @__PURE__ */ o(yt, { label: "Interest rate", solved: L("rate"), solvedText: B.rate, suffix: "% p.a.", children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: c, onChange: (R) => l(R.target.value), "aria-label": "Interest rate" }) }),
|
|
3564
3568
|
/* @__PURE__ */ b("div", { className: "field", children: [
|
|
3565
3569
|
/* @__PURE__ */ o("span", { className: "lbl", children: a.tenureWord }),
|
|
3566
3570
|
L("tenure") ? /* @__PURE__ */ b(re, { children: [
|
|
@@ -3577,7 +3581,7 @@ function Wn() {
|
|
|
3577
3581
|
] })
|
|
3578
3582
|
] })
|
|
3579
3583
|
] }),
|
|
3580
|
-
/* @__PURE__ */ o(
|
|
3584
|
+
/* @__PURE__ */ o(yt, { label: a.paymentLabel, solved: L("payment"), solvedText: B.payment, affix: q, children: /* @__PURE__ */ o("input", { className: "num", inputMode: "decimal", value: w, onChange: (R) => k(R.target.value), "aria-label": a.paymentLabel }) })
|
|
3581
3585
|
] }),
|
|
3582
3586
|
$ && /* @__PURE__ */ o("div", { className: "error", role: "alert", style: { marginTop: 16 }, children: $ })
|
|
3583
3587
|
] }),
|
|
@@ -3610,7 +3614,7 @@ function Wn() {
|
|
|
3610
3614
|
] }),
|
|
3611
3615
|
/* @__PURE__ */ b("div", { className: "kv", children: [
|
|
3612
3616
|
/* @__PURE__ */ o("div", { className: "k", children: a.tenureWord }),
|
|
3613
|
-
/* @__PURE__ */ o("div", { className: "v num", children:
|
|
3617
|
+
/* @__PURE__ */ o("div", { className: "v num", children: mt(T.tenureMonths) })
|
|
3614
3618
|
] })
|
|
3615
3619
|
] }),
|
|
3616
3620
|
/* @__PURE__ */ b("div", { className: "actions-row", children: [
|
|
@@ -3679,7 +3683,7 @@ function Wn() {
|
|
|
3679
3683
|
] })
|
|
3680
3684
|
] });
|
|
3681
3685
|
}
|
|
3682
|
-
function
|
|
3686
|
+
function yt({
|
|
3683
3687
|
label: e,
|
|
3684
3688
|
solved: t,
|
|
3685
3689
|
solvedText: n,
|
|
@@ -4113,10 +4117,10 @@ function Vo(e) {
|
|
|
4113
4117
|
return m;
|
|
4114
4118
|
}
|
|
4115
4119
|
const Yo = new H("3.141592653589793238462643383279502884197"), Ko = new H("2.718281828459045235360287471352662497757"), Wo = new H("1.618033988749894848204586834365638117720");
|
|
4116
|
-
function
|
|
4120
|
+
function bt(e, t) {
|
|
4117
4121
|
return t === "deg" ? e * Math.PI / 180 : t === "grad" ? e * Math.PI / 200 : e;
|
|
4118
4122
|
}
|
|
4119
|
-
function
|
|
4123
|
+
function gt(e, t) {
|
|
4120
4124
|
return t === "deg" ? e * 180 / Math.PI : t === "grad" ? e * 200 / Math.PI : e;
|
|
4121
4125
|
}
|
|
4122
4126
|
function an(e) {
|
|
@@ -4147,7 +4151,7 @@ function rn(e, t) {
|
|
|
4147
4151
|
}
|
|
4148
4152
|
return n;
|
|
4149
4153
|
}
|
|
4150
|
-
function
|
|
4154
|
+
function vt(e, t) {
|
|
4151
4155
|
if (e.isNegative()) {
|
|
4152
4156
|
if (t.isInteger() && !t.mod(2).isZero()) return e.abs().pow(g(1).div(t)).neg();
|
|
4153
4157
|
throw new Error("root of negative");
|
|
@@ -4167,22 +4171,22 @@ function Zo(e, t = {}) {
|
|
|
4167
4171
|
let p;
|
|
4168
4172
|
switch (i) {
|
|
4169
4173
|
case "sin":
|
|
4170
|
-
p = Math.sin(
|
|
4174
|
+
p = Math.sin(bt(l, n));
|
|
4171
4175
|
break;
|
|
4172
4176
|
case "cos":
|
|
4173
|
-
p = Math.cos(
|
|
4177
|
+
p = Math.cos(bt(l, n));
|
|
4174
4178
|
break;
|
|
4175
4179
|
case "tan":
|
|
4176
|
-
p = Math.tan(
|
|
4180
|
+
p = Math.tan(bt(l, n));
|
|
4177
4181
|
break;
|
|
4178
4182
|
case "asin":
|
|
4179
|
-
p =
|
|
4183
|
+
p = gt(Math.asin(l), n);
|
|
4180
4184
|
break;
|
|
4181
4185
|
case "acos":
|
|
4182
|
-
p =
|
|
4186
|
+
p = gt(Math.acos(l), n);
|
|
4183
4187
|
break;
|
|
4184
4188
|
case "atan":
|
|
4185
|
-
p =
|
|
4189
|
+
p = gt(Math.atan(l), n);
|
|
4186
4190
|
break;
|
|
4187
4191
|
case "sinh":
|
|
4188
4192
|
p = Math.sinh(l);
|
|
@@ -4216,11 +4220,11 @@ function Zo(e, t = {}) {
|
|
|
4216
4220
|
case "sqrt":
|
|
4217
4221
|
return p(1), l.sqrt();
|
|
4218
4222
|
case "cbrt":
|
|
4219
|
-
return p(1),
|
|
4223
|
+
return p(1), vt(l, g(3));
|
|
4220
4224
|
case "qdrt":
|
|
4221
|
-
return p(1),
|
|
4225
|
+
return p(1), vt(l, g(4));
|
|
4222
4226
|
case "root":
|
|
4223
|
-
return p(2),
|
|
4227
|
+
return p(2), vt(l, c[1]);
|
|
4224
4228
|
case "pow":
|
|
4225
4229
|
return p(2), l.pow(c[1]);
|
|
4226
4230
|
case "ln":
|
|
@@ -4536,7 +4540,7 @@ function Jn({ def: e }) {
|
|
|
4536
4540
|
] })
|
|
4537
4541
|
] });
|
|
4538
4542
|
}
|
|
4539
|
-
const
|
|
4543
|
+
const nt = [
|
|
4540
4544
|
{ code: "USD", name: "US Dollar", symbol: "$" },
|
|
4541
4545
|
{ code: "EUR", name: "Euro", symbol: "€" },
|
|
4542
4546
|
{ code: "GBP", name: "British Pound", symbol: "£" },
|
|
@@ -4581,11 +4585,11 @@ const tt = [
|
|
|
4581
4585
|
{ code: "BDT", name: "Bangladeshi Taka", symbol: "৳" },
|
|
4582
4586
|
{ code: "LKR", name: "Sri Lankan Rupee", symbol: "Rs" },
|
|
4583
4587
|
{ code: "NPR", name: "Nepalese Rupee", symbol: "रू" }
|
|
4584
|
-
], Xo = (e) =>
|
|
4588
|
+
], Xo = (e) => nt.find((t) => t.code === e), Qo = (e) => e === "INR" ? "en-IN" : "en-US", Zn = (e, t) => g(e).times(t), Xn = (e) => {
|
|
4585
4589
|
const t = g(e);
|
|
4586
4590
|
return t.gt(0) ? g(1).div(t) : g(0);
|
|
4587
4591
|
};
|
|
4588
|
-
function
|
|
4592
|
+
function Mt(e, t) {
|
|
4589
4593
|
const n = g(e);
|
|
4590
4594
|
try {
|
|
4591
4595
|
return new Intl.NumberFormat(Qo(t), { style: "currency", currency: t }).format(
|
|
@@ -4616,11 +4620,11 @@ function Je(e, t) {
|
|
|
4616
4620
|
}
|
|
4617
4621
|
const ea = (e, t) => t - e > 864e5, fs = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
4618
4622
|
__proto__: null,
|
|
4619
|
-
CURRENCIES:
|
|
4623
|
+
CURRENCIES: nt,
|
|
4620
4624
|
convert: Zn,
|
|
4621
4625
|
currencyByCode: Xo,
|
|
4622
4626
|
currencyDecimals: Qn,
|
|
4623
|
-
formatCurrency:
|
|
4627
|
+
formatCurrency: Mt,
|
|
4624
4628
|
inverseRate: Xn,
|
|
4625
4629
|
isStale: ea,
|
|
4626
4630
|
stalenessLabel: Je
|
|
@@ -4642,7 +4646,7 @@ function ln(e, t) {
|
|
|
4642
4646
|
const n = Date.parse(e);
|
|
4643
4647
|
return Number.isFinite(n) ? n : t;
|
|
4644
4648
|
}
|
|
4645
|
-
const ta = "calcsuite:fxrates", na = "calcsuite:fxmode",
|
|
4649
|
+
const ta = "calcsuite:fxrates", na = "calcsuite:fxmode", kt = () => {
|
|
4646
4650
|
try {
|
|
4647
4651
|
return JSON.parse(localStorage.getItem(ta) || "{}");
|
|
4648
4652
|
} catch {
|
|
@@ -4662,7 +4666,7 @@ const ta = "calcsuite:fxrates", na = "calcsuite:fxmode", vt = () => {
|
|
|
4662
4666
|
}, Ke = (e, t) => `${e}_${t}`;
|
|
4663
4667
|
function aa() {
|
|
4664
4668
|
var _t;
|
|
4665
|
-
const [e, t] = M("USD"), [n, a] = M("INR"), [r, s] = M(""), [u, m] = M(""), [d, i] = M("none"), [c, l] = M(""), [p, h] = M("idle"), [f, y] = M(""), [w, k] = M(() => ai()), [S, F] = M(() =>
|
|
4669
|
+
const [e, t] = M("USD"), [n, a] = M("INR"), [r, s] = M(""), [u, m] = M(""), [d, i] = M("none"), [c, l] = M(""), [p, h] = M("idle"), [f, y] = M(""), [w, k] = M(() => ai()), [S, F] = M(() => kt()), [N, P] = M(() => Date.now()), x = de(null);
|
|
4666
4670
|
X(() => {
|
|
4667
4671
|
const O = setInterval(() => P(Date.now()), 3e4);
|
|
4668
4672
|
return () => clearInterval(O);
|
|
@@ -4684,7 +4688,7 @@ function aa() {
|
|
|
4684
4688
|
ae.signal.aborted || (m(xe.rate), i("live"), l(xe.asOf), h("idle"), T(xe.rate, ln(xe.asOf, Date.now())));
|
|
4685
4689
|
}).catch((xe) => {
|
|
4686
4690
|
if (ae.signal.aborted) return;
|
|
4687
|
-
const Ht =
|
|
4691
|
+
const Ht = kt()[Ke(O, Z)];
|
|
4688
4692
|
Ht ? (m(Ht.rate), i("saved"), h("error"), y("Offline — showing your last saved rate. Refresh when back online.")) : (i("none"), h("error"), y(`Couldn’t fetch a live rate (${xe instanceof Error ? xe.message : "offline"}). Enter one manually.`));
|
|
4689
4693
|
});
|
|
4690
4694
|
}, L = (O, Z) => {
|
|
@@ -4693,7 +4697,7 @@ function aa() {
|
|
|
4693
4697
|
m("1"), i("saved");
|
|
4694
4698
|
return;
|
|
4695
4699
|
}
|
|
4696
|
-
const ae =
|
|
4700
|
+
const ae = kt()[Ke(O, Z)];
|
|
4697
4701
|
ae ? (m(ae.rate), i("saved")) : (m(""), i("none"));
|
|
4698
4702
|
};
|
|
4699
4703
|
X(() => (w === "online" ? $(e, n) : L(e, n), () => {
|
|
@@ -4752,12 +4756,12 @@ function aa() {
|
|
|
4752
4756
|
] }),
|
|
4753
4757
|
/* @__PURE__ */ b("label", { className: "field cc-cur", children: [
|
|
4754
4758
|
/* @__PURE__ */ o("span", { className: "lbl", children: "From" }),
|
|
4755
|
-
/* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: e, onChange: (O) => t(O.target.value), "aria-label": "From currency", children:
|
|
4759
|
+
/* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: e, onChange: (O) => t(O.target.value), "aria-label": "From currency", children: nt.map(pe) }) })
|
|
4756
4760
|
] }),
|
|
4757
4761
|
/* @__PURE__ */ o("button", { type: "button", className: "cc-swap", onClick: Q, "aria-label": "Swap currencies", title: "Swap", children: "⇄" }),
|
|
4758
4762
|
/* @__PURE__ */ b("label", { className: "field cc-cur", children: [
|
|
4759
4763
|
/* @__PURE__ */ o("span", { className: "lbl", children: "To" }),
|
|
4760
|
-
/* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: n, onChange: (O) => a(O.target.value), "aria-label": "To currency", children:
|
|
4764
|
+
/* @__PURE__ */ o("div", { className: "input-wrap", children: /* @__PURE__ */ o("select", { value: n, onChange: (O) => a(O.target.value), "aria-label": "To currency", children: nt.map(pe) }) })
|
|
4761
4765
|
] })
|
|
4762
4766
|
] }),
|
|
4763
4767
|
/* @__PURE__ */ b("label", { className: "field", style: { marginTop: 16 }, children: [
|
|
@@ -4798,10 +4802,10 @@ function aa() {
|
|
|
4798
4802
|
/* @__PURE__ */ b("section", { className: "card", children: [
|
|
4799
4803
|
j ? /* @__PURE__ */ b("div", { className: "result", "aria-live": "polite", children: [
|
|
4800
4804
|
/* @__PURE__ */ b("div", { className: "label", children: [
|
|
4801
|
-
|
|
4805
|
+
Mt(q, e),
|
|
4802
4806
|
" ="
|
|
4803
4807
|
] }),
|
|
4804
|
-
/* @__PURE__ */ o("div", { className: "value num accent-txt", children:
|
|
4808
|
+
/* @__PURE__ */ o("div", { className: "value num accent-txt", children: Mt(j, n) }),
|
|
4805
4809
|
/* @__PURE__ */ b("div", { className: "secondary", children: [
|
|
4806
4810
|
/* @__PURE__ */ b("div", { className: "kv", children: [
|
|
4807
4811
|
/* @__PURE__ */ o("div", { className: "k", children: "Rate" }),
|
|
@@ -4894,7 +4898,7 @@ function ii({
|
|
|
4894
4898
|
actions: s
|
|
4895
4899
|
}) {
|
|
4896
4900
|
var L, B, G, q;
|
|
4897
|
-
const u = e ?? (t ?
|
|
4901
|
+
const u = e ?? (t ? Rt(t) : void 0), m = u ?? ri, d = { ...oi, ...a }, { settings: i, fmt: c } = ue(), [l, p] = M(() => cn(m, n)), [h, f] = M("schedule"), [y, w] = M(!1);
|
|
4898
4902
|
X(() => p(cn(m, n)), [m.id, n]);
|
|
4899
4903
|
const k = i.region, S = (A, I) => p((R) => ({ ...R, [A]: I })), F = m.inputs.filter((A) => A.showIf ? A.showIf(l, k) : !0), N = F.filter((A) => !A.advanced), P = F.filter((A) => A.advanced), { result: x, error: T } = ne(() => {
|
|
4900
4904
|
const A = { settings: i, region: k, fmt: c, D: g };
|
|
@@ -4976,10 +4980,10 @@ const si = [
|
|
|
4976
4980
|
{ id: "blue", label: "Blue", main: "#2065D1", light: "#76B0F1", dark: "#103996", ink: "#FFFFFF" },
|
|
4977
4981
|
{ id: "orange", label: "Orange", main: "#FDA92D", light: "#FED680", dark: "#B66816", ink: "#212B36" },
|
|
4978
4982
|
{ id: "gray", label: "Gray", main: "#A4AAB3", light: "#CED1D7", dark: "#63686C", ink: "#FFFFFF" }
|
|
4979
|
-
],
|
|
4980
|
-
{ id: "Inter Tight", label: "Inter Tight", stack: `'Inter Tight', ${
|
|
4981
|
-
{ id: "Public Sans", label: "Public Sans", stack: `'Public Sans', ${
|
|
4982
|
-
{ id: "system-ui", label: "System UI", stack: `system-ui, ${
|
|
4983
|
+
], wt = "-apple-system, 'Segoe UI', system-ui, sans-serif", li = [
|
|
4984
|
+
{ id: "Inter Tight", label: "Inter Tight", stack: `'Inter Tight', ${wt}` },
|
|
4985
|
+
{ id: "Public Sans", label: "Public Sans", stack: `'Public Sans', ${wt}` },
|
|
4986
|
+
{ id: "system-ui", label: "System UI", stack: `system-ui, ${wt}` },
|
|
4983
4987
|
{ id: "Georgia", label: "Georgia (serif)", stack: "Georgia, 'Times New Roman', serif" }
|
|
4984
4988
|
];
|
|
4985
4989
|
class z extends Error {
|
|
@@ -5031,7 +5035,7 @@ function oa(e, t) {
|
|
|
5031
5035
|
const n = /* @__PURE__ */ new Date(), a = (d) => String(d).padStart(2, "0"), r = (((m = t.filename) == null ? void 0 : m.split(".").pop()) || t.kind || "bin").toLowerCase(), s = (t.inputsHash || "").replace(/^sha256:/, "").slice(0, 8) || "00000000", u = e.replace(/\{calculator\}/g, t.calculator || "calc").replace(/\{yyyy\}/g, String(n.getFullYear())).replace(/\{MM\}/g, a(n.getMonth() + 1)).replace(/\{dd\}/g, a(n.getDate())).replace(/\{hash8\}/g, s).replace(/\{ext\}/g, r).replace(/\{kind\}/g, t.kind || "file");
|
|
5032
5036
|
return pi(u);
|
|
5033
5037
|
}
|
|
5034
|
-
function
|
|
5038
|
+
function $t(e, t = []) {
|
|
5035
5039
|
const n = /* @__PURE__ */ new Set([...ci, ...t.map((r) => r.toLowerCase())]), a = {};
|
|
5036
5040
|
for (const [r, s] of Object.entries(e)) a[r] = n.has(r.toLowerCase()) ? "***" : s;
|
|
5037
5041
|
return a;
|
|
@@ -5146,7 +5150,7 @@ function fi(e) {
|
|
|
5146
5150
|
...R.headers
|
|
5147
5151
|
};
|
|
5148
5152
|
$ && (j[a.headerName] = $);
|
|
5149
|
-
const Y =
|
|
5153
|
+
const Y = $t(j, R.keys);
|
|
5150
5154
|
let V = P.body;
|
|
5151
5155
|
const Q = { endpoint: String(N), method: x, url: T, headers: Y, body: V, attempt: I };
|
|
5152
5156
|
e.transformRequest && V !== void 0 && (V = e.transformRequest(V, Q)), (B = e.onRequest) == null || B.call(e, Q);
|
|
@@ -5443,13 +5447,13 @@ function Ci(e, t, n) {
|
|
|
5443
5447
|
return String(e);
|
|
5444
5448
|
}
|
|
5445
5449
|
}
|
|
5446
|
-
function
|
|
5450
|
+
function at(e, t) {
|
|
5447
5451
|
if (t === "number") return e;
|
|
5448
5452
|
if (typeof e == "number") return String(e);
|
|
5449
|
-
if (Array.isArray(e)) return e.map((n) =>
|
|
5453
|
+
if (Array.isArray(e)) return e.map((n) => at(n, t));
|
|
5450
5454
|
if (e && typeof e == "object") {
|
|
5451
5455
|
const n = {};
|
|
5452
|
-
for (const [a, r] of Object.entries(e)) n[a] =
|
|
5456
|
+
for (const [a, r] of Object.entries(e)) n[a] = at(r, t);
|
|
5453
5457
|
return n;
|
|
5454
5458
|
}
|
|
5455
5459
|
return e;
|
|
@@ -5490,7 +5494,7 @@ function Ti(e, t, n) {
|
|
|
5490
5494
|
u.transform && u.transform !== "none" && (m = xi(m, u.transform)), bn(a, i, Ci(m, u.type, t));
|
|
5491
5495
|
}
|
|
5492
5496
|
const r = t.include, s = (u, m) => {
|
|
5493
|
-
m !== void 0 && (a[gn(u, t.keyCase)] =
|
|
5497
|
+
m !== void 0 && (a[gn(u, t.keyCase)] = at(m, t.numberEncoding));
|
|
5494
5498
|
};
|
|
5495
5499
|
return r != null && r.inputs && s("inputs", n.inputs), r != null && r.outputs && s("outputs", n.outputs), r != null && r.schedule && s("schedule", n.schedule), r != null && r.settingsSnapshot && s("settingsSnapshot", n.settings), r != null && r.meta && s("meta", n.context), t.numberEncoding === "number" && console.warn('[fincalc] numberEncoding="number" reintroduces float error; prefer "string".'), t.mode === "wrapped" && t.wrapperKey ? { [t.wrapperKey]: a } : a;
|
|
5496
5500
|
}
|
|
@@ -5503,7 +5507,7 @@ const ys = {
|
|
|
5503
5507
|
include: { inputs: !0, outputs: !0, schedule: !1, settingsSnapshot: !0, meta: !0 }
|
|
5504
5508
|
};
|
|
5505
5509
|
function vn(e) {
|
|
5506
|
-
return
|
|
5510
|
+
return at(e, "string");
|
|
5507
5511
|
}
|
|
5508
5512
|
function bs(e) {
|
|
5509
5513
|
const t = e.settings;
|
|
@@ -6001,9 +6005,9 @@ function Gi({ cfg: e, getToken: t }) {
|
|
|
6001
6005
|
const c = performance.now();
|
|
6002
6006
|
try {
|
|
6003
6007
|
const l = await fetch(d, { method: m.method, headers: i, credentials: e.credentials }), p = await l.text(), h = {};
|
|
6004
|
-
l.headers.forEach((f, y) => h[y] = f), a({ loading: !1, ok: l.ok, status: l.status, ms: Math.round(performance.now() - c), headers: h, body: Ki(p), sent: { url: d, method: m.method, headers:
|
|
6008
|
+
l.headers.forEach((f, y) => h[y] = f), a({ loading: !1, ok: l.ok, status: l.status, ms: Math.round(performance.now() - c), headers: h, body: Ki(p), sent: { url: d, method: m.method, headers: $t(i) } });
|
|
6005
6009
|
} catch (l) {
|
|
6006
|
-
a({ loading: !1, ok: !1, ms: Math.round(performance.now() - c), error: l instanceof Error ? l.message : "request failed", sent: { url: d, method: m.method, headers:
|
|
6010
|
+
a({ loading: !1, ok: !1, ms: Math.round(performance.now() - c), error: l instanceof Error ? l.message : "request failed", sent: { url: d, method: m.method, headers: $t(i) } });
|
|
6007
6011
|
}
|
|
6008
6012
|
}, disabled: n.loading, children: n.loading ? "Testing…" : "Test connection" }) })
|
|
6009
6013
|
] }),
|
|
@@ -6373,7 +6377,7 @@ function Zi({
|
|
|
6373
6377
|
] })
|
|
6374
6378
|
] }) });
|
|
6375
6379
|
}
|
|
6376
|
-
const
|
|
6380
|
+
const ut = (e) => ({
|
|
6377
6381
|
width: e,
|
|
6378
6382
|
height: e,
|
|
6379
6383
|
viewBox: "0 0 24 24",
|
|
@@ -6385,22 +6389,22 @@ const ct = (e) => ({
|
|
|
6385
6389
|
"aria-hidden": !0
|
|
6386
6390
|
});
|
|
6387
6391
|
function Xi({ size: e = 17 }) {
|
|
6388
|
-
return /* @__PURE__ */ b("svg", { ...
|
|
6392
|
+
return /* @__PURE__ */ b("svg", { ...ut(e), children: [
|
|
6389
6393
|
/* @__PURE__ */ o("circle", { cx: "12", cy: "12", r: "3" }),
|
|
6390
6394
|
/* @__PURE__ */ o("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1Z" })
|
|
6391
6395
|
] });
|
|
6392
6396
|
}
|
|
6393
6397
|
function Qi({ size: e = 17 }) {
|
|
6394
|
-
return /* @__PURE__ */ b("svg", { ...
|
|
6398
|
+
return /* @__PURE__ */ b("svg", { ...ut(e), children: [
|
|
6395
6399
|
/* @__PURE__ */ o("circle", { cx: "12", cy: "12", r: "4" }),
|
|
6396
6400
|
/* @__PURE__ */ o("path", { d: "M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41" })
|
|
6397
6401
|
] });
|
|
6398
6402
|
}
|
|
6399
6403
|
function es({ size: e = 17 }) {
|
|
6400
|
-
return /* @__PURE__ */ o("svg", { ...
|
|
6404
|
+
return /* @__PURE__ */ o("svg", { ...ut(e), children: /* @__PURE__ */ o("path", { d: "M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" }) });
|
|
6401
6405
|
}
|
|
6402
6406
|
function ts({ size: e = 17 }) {
|
|
6403
|
-
return /* @__PURE__ */ b("svg", { ...
|
|
6407
|
+
return /* @__PURE__ */ b("svg", { ...ut(e), children: [
|
|
6404
6408
|
/* @__PURE__ */ o("path", { d: "M3 3v5h5" }),
|
|
6405
6409
|
/* @__PURE__ */ o("path", { d: "M3.05 13A9 9 0 1 0 6 5.3L3 8" }),
|
|
6406
6410
|
/* @__PURE__ */ o("path", { d: "M12 7v5l4 2" })
|
|
@@ -6412,7 +6416,7 @@ function as({ onClose: e }) {
|
|
|
6412
6416
|
X(() => {
|
|
6413
6417
|
const x = () => {
|
|
6414
6418
|
const T = new URLSearchParams(location.hash.replace(/^#/, "") || location.search), $ = T.get("fincalc");
|
|
6415
|
-
if ($ &&
|
|
6419
|
+
if ($ && Rt($)) {
|
|
6416
6420
|
d($), c("calc");
|
|
6417
6421
|
const L = T.get("s");
|
|
6418
6422
|
if (L)
|
|
@@ -6428,7 +6432,7 @@ function as({ onClose: e }) {
|
|
|
6428
6432
|
(x.metaKey || x.ctrlKey) && x.key.toLowerCase() === "k" && (x.preventDefault(), f(!0));
|
|
6429
6433
|
}, S = (x) => {
|
|
6430
6434
|
d(x), c("calc"), p(void 0), f(!1);
|
|
6431
|
-
}, F =
|
|
6435
|
+
}, F = Rt(m) ?? u[0], N = [
|
|
6432
6436
|
{ id: "settings", label: "Open settings", run: () => {
|
|
6433
6437
|
c("settings"), f(!1);
|
|
6434
6438
|
} },
|
|
@@ -6590,7 +6594,7 @@ function gs({
|
|
|
6590
6594
|
/* @__PURE__ */ o(Ca, { open: k, onClose: F.close, title: h, size: p, children: /* @__PURE__ */ o(as, { onClose: F.close }) })
|
|
6591
6595
|
] });
|
|
6592
6596
|
}
|
|
6593
|
-
const rs = 60 * 60 * 1e3,
|
|
6597
|
+
const rs = 60 * 60 * 1e3, Nt = (e, t) => `${e}|${[...t].sort().join(",")}`;
|
|
6594
6598
|
function vs(e, t = {}) {
|
|
6595
6599
|
const n = t.ttlMs ?? rs, a = t.now ?? Date.now, r = /* @__PURE__ */ new Map();
|
|
6596
6600
|
let s = null;
|
|
@@ -6604,7 +6608,7 @@ function vs(e, t = {}) {
|
|
|
6604
6608
|
return a() - i.lastUpdated < n;
|
|
6605
6609
|
}
|
|
6606
6610
|
async function d(i, c) {
|
|
6607
|
-
const l =
|
|
6611
|
+
const l = Nt(i, c), p = r.get(l);
|
|
6608
6612
|
if (p && m(p)) return { ...p, stale: !1 };
|
|
6609
6613
|
if (e)
|
|
6610
6614
|
try {
|
|
@@ -6627,12 +6631,12 @@ function vs(e, t = {}) {
|
|
|
6627
6631
|
return {
|
|
6628
6632
|
getRates: d,
|
|
6629
6633
|
/** Non-throwing peek at whatever is cached, if anything. */
|
|
6630
|
-
peek: (i, c) => r.get(
|
|
6634
|
+
peek: (i, c) => r.get(Nt(i, c)),
|
|
6631
6635
|
get lastUpdated() {
|
|
6632
6636
|
return s == null ? null : new Date(s);
|
|
6633
6637
|
},
|
|
6634
6638
|
isStale(i, c) {
|
|
6635
|
-
const l = r.get(
|
|
6639
|
+
const l = r.get(Nt(i, c));
|
|
6636
6640
|
return !l || !m(l);
|
|
6637
6641
|
},
|
|
6638
6642
|
clear: () => r.clear()
|
|
@@ -6675,7 +6679,7 @@ export {
|
|
|
6675
6679
|
oa as buildFilename,
|
|
6676
6680
|
Ti as buildPayload,
|
|
6677
6681
|
bs as buildSavePayload,
|
|
6678
|
-
|
|
6682
|
+
Rt as calculatorById,
|
|
6679
6683
|
Kr as calculatorsForRegion,
|
|
6680
6684
|
Eo as clearHistory,
|
|
6681
6685
|
To as createExporter,
|
|
@@ -6696,7 +6700,7 @@ export {
|
|
|
6696
6700
|
v as metric,
|
|
6697
6701
|
C as numval,
|
|
6698
6702
|
Vo as parseExpression,
|
|
6699
|
-
|
|
6703
|
+
xt as regionDefaults,
|
|
6700
6704
|
hs as registerCalculator,
|
|
6701
6705
|
pi as sanitizeFilename,
|
|
6702
6706
|
Yn as saveHistory,
|
|
@@ -13,8 +13,10 @@ interface SettingsCtx {
|
|
|
13
13
|
replace: (s: Settings) => void;
|
|
14
14
|
resolvedTheme: 'light' | 'dark' | 'highContrast';
|
|
15
15
|
}
|
|
16
|
-
export declare function SettingsProvider({ children }: {
|
|
16
|
+
export declare function SettingsProvider({ children, settings: initial, }: {
|
|
17
17
|
children: ReactNode;
|
|
18
|
+
/** Default settings (deep-partial). The user's in-app choices still persist and win. */
|
|
19
|
+
settings?: DeepPartial<Settings>;
|
|
18
20
|
}): import("react").JSX.Element;
|
|
19
21
|
export declare function useSettings(): SettingsCtx;
|
|
20
22
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "calcsuite-react",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Decimal-exact, offline-first financial calculator library for React — India (₹) & US ($). ~55 calculators, scientific calculator, live FX, export, launcher/dialog. The financial-calculator module of AceCBM (Ace Cloud Business Management).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"finance",
|
package/src/theme.css
CHANGED
|
@@ -461,7 +461,7 @@ td .in-txt { color: var(--fc-interest); }
|
|
|
461
461
|
|
|
462
462
|
/* FAB */
|
|
463
463
|
.fc-fab {
|
|
464
|
-
position: fixed; z-index:
|
|
464
|
+
position: fixed; z-index: 9000; width: 56px; height: 56px; border-radius: 50%;
|
|
465
465
|
border: 0; background: var(--fc-accent); color: #fff; cursor: pointer;
|
|
466
466
|
box-shadow: var(--fc-shadow);
|
|
467
467
|
display: flex; align-items: center; justify-content: center;
|
|
@@ -477,7 +477,7 @@ td .in-txt { color: var(--fc-interest); }
|
|
|
477
477
|
/* Dialog */
|
|
478
478
|
.dialog-backdrop {
|
|
479
479
|
position: fixed; inset: 0; background: rgba(10, 16, 20, 0.5);
|
|
480
|
-
display: flex; align-items: center; justify-content: center; z-index:
|
|
480
|
+
display: flex; align-items: center; justify-content: center; z-index: 2147483000; padding: 20px;
|
|
481
481
|
animation: fc-fade 0.12s ease;
|
|
482
482
|
}
|
|
483
483
|
.dialog {
|
|
@@ -501,7 +501,7 @@ td .in-txt { color: var(--fc-interest); }
|
|
|
501
501
|
}
|
|
502
502
|
|
|
503
503
|
/* Command palette */
|
|
504
|
-
.palette-backdrop { position: fixed; inset: 0; background: rgba(10, 16, 20, 0.4); z-index:
|
|
504
|
+
.palette-backdrop { position: fixed; inset: 0; background: rgba(10, 16, 20, 0.4); z-index: 2147483010; display: flex; justify-content: center; align-items: flex-start; padding-top: 12vh; }
|
|
505
505
|
.palette { background: var(--fc-surface); border: 1px solid var(--fc-line); border-radius: 14px; width: min(560px, 92vw); box-shadow: var(--fc-shadow); overflow: hidden; }
|
|
506
506
|
.palette-input { width: 100%; border: 0; border-bottom: 1px solid var(--fc-line); outline: 0; background: transparent; color: var(--fc-ink); font: inherit; font-size: 16px; padding: 16px; }
|
|
507
507
|
.palette-list { list-style: none; margin: 0; padding: 6px; max-height: 50vh; overflow-y: auto; }
|
|
@@ -577,7 +577,7 @@ td .in-txt { color: var(--fc-interest); }
|
|
|
577
577
|
bottom: 20px;
|
|
578
578
|
left: 50%;
|
|
579
579
|
transform: translateX(-50%);
|
|
580
|
-
z-index:
|
|
580
|
+
z-index: 2147483020;
|
|
581
581
|
padding: 10px 16px;
|
|
582
582
|
border-radius: 999px;
|
|
583
583
|
font-size: 13px;
|