From 24db678df4f978964dbfb81de0c56a26c3392d7d Mon Sep 17 00:00:00 2001 From: Alexandra Goff Date: Tue, 2 Apr 2024 16:43:19 -0700 Subject: [PATCH] [C] refactor calculators --- app/api/xlsx/formatter/calculator/index.ts | 9 +- components/atomic/Equation/index.tsx | 1 + components/calculators/Output/index.tsx | 14 --- components/calculators/interactive/index.tsx | 71 +++++++++-- .../interactive/peakAbsoluteMagnitude.tsx | 94 --------------- components/calculators/interactive/styles.ts | 19 +-- .../interactive/supernovaDistance.tsx | 110 ------------------ components/calculators/lib/equations.ts | 42 +++++++ components/calculators/lib/fields.ts | 22 ++++ components/calculators/lib/index.ts | 39 +++++++ components/calculators/lib/latex.ts | 76 ++++++++++++ components/calculators/lib/placeholders.ts | 6 + components/calculators/math/index.ts | 62 ---------- components/calculators/static/index.tsx | 10 +- .../factories/CalculatorFactory/index.tsx | 28 ----- .../form/Input/patterns/MathInput/index.tsx | 2 +- components/questions/Calculator/index.tsx | 8 +- .../questions/Review/Calculator/index.tsx | 4 +- public/localeStrings/en/translation.json | 8 +- theme/styles/components/_index.scss | 1 + .../styles/components/_math.scss | 15 +-- types/calculators.d.ts | 32 +++-- 22 files changed, 301 insertions(+), 372 deletions(-) delete mode 100644 components/calculators/Output/index.tsx delete mode 100644 components/calculators/interactive/peakAbsoluteMagnitude.tsx delete mode 100644 components/calculators/interactive/supernovaDistance.tsx create mode 100644 components/calculators/lib/equations.ts create mode 100644 components/calculators/lib/fields.ts create mode 100644 components/calculators/lib/index.ts create mode 100644 components/calculators/lib/latex.ts create mode 100644 components/calculators/lib/placeholders.ts delete mode 100644 components/calculators/math/index.ts delete mode 100644 components/factories/CalculatorFactory/index.tsx rename components/calculators/Output/styles.ts => theme/styles/components/_math.scss (52%) diff --git a/app/api/xlsx/formatter/calculator/index.ts b/app/api/xlsx/formatter/calculator/index.ts index 0b77aef6..3496daa1 100644 --- a/app/api/xlsx/formatter/calculator/index.ts +++ b/app/api/xlsx/formatter/calculator/index.ts @@ -1,5 +1,5 @@ import { serverTranslation } from "@/lib/i18n"; -import CalculatorFunctions from "@/components/calculators/math"; +import Calculator from "@/components/calculators/lib"; import { CalculatorFormatter } from ".."; const CalculatorFormatter: CalculatorFormatter = async ({ @@ -10,11 +10,8 @@ const CalculatorFormatter: CalculatorFormatter = async ({ }) => { const { t } = await serverTranslation(locale, "translation"); - const calculator = CalculatorFunctions[equation]; - - if (!calculator) cell.value = t("review.no_answer"); - - cell.value = calculator(value) || t("review.no_answer"); + cell.value = + Calculator(equation, value, locale).result || t("review.no_answer"); }; export default CalculatorFormatter; diff --git a/components/atomic/Equation/index.tsx b/components/atomic/Equation/index.tsx index 815445cd..4fae06a1 100644 --- a/components/atomic/Equation/index.tsx +++ b/components/atomic/Equation/index.tsx @@ -6,6 +6,7 @@ const Equation: FunctionComponent<{ latex: string }> = ({ latex }) => { const mathMl = temml.renderToString(latex, { displayMode: true, throwOnError: true, + trust: (context) => context.command === "\\class", }); return ( diff --git a/components/calculators/Output/index.tsx b/components/calculators/Output/index.tsx deleted file mode 100644 index 171da623..00000000 --- a/components/calculators/Output/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { FunctionComponent, ReactNode } from "react"; -import * as Styled from "./styles"; - -const Output: FunctionComponent<{ - value?: string | number; - forId?: string; - placeholder: ReactNode; -}> = ({ value, placeholder, forId }) => { - return {value || placeholder}; -}; - -Output.displayName = "Calculator.Output"; - -export default Output; diff --git a/components/calculators/interactive/index.tsx b/components/calculators/interactive/index.tsx index 68c02578..15c1729f 100644 --- a/components/calculators/interactive/index.tsx +++ b/components/calculators/interactive/index.tsx @@ -1,14 +1,61 @@ -import { ComponentType } from "react"; -import { Equation, InteractiveCalculatorProps } from "@/types/calculators"; -import PeakAbsoluteMagnitude from "./peakAbsoluteMagnitude"; -import SupernovaDistance from "./supernovaDistance"; - -const InteractiveCalculators: Record< - Equation, - ComponentType -> = { - peakAbsoluteMagnitude: PeakAbsoluteMagnitude, - supernovaDistance: SupernovaDistance, +/* eslint-disable jsx-a11y/label-has-associated-control */ +import { FormEvent, FunctionComponent } from "react"; +import { useTranslation } from "react-i18next"; +import { InteractiveCalculatorProps } from "@/types/calculators"; +import MathInput from "@/components/form/Input/patterns/MathInput"; +import Equation from "@/components/atomic/Equation"; +import Calculator from "@/components/calculators/lib"; +import * as Styled from "./styles"; + +const InteractiveCalculator: FunctionComponent = ({ + equation, + id, + value = {}, + onChangeCallback, +}) => { + const { + t, + i18n: { language }, + } = useTranslation(); + + const { fields = {}, result, latex } = Calculator(equation, value, language); + + const handleChange = (event: FormEvent, key: string) => { + onChangeCallback && + onChangeCallback({ + ...value, + [key]: parseFloat((event.target as HTMLInputElement).value), + }); + }; + + return ( + + + {Object.keys(fields).map((key: string) => { + const { label, precision } = fields[key]; + return ( + + + handleChange(e, key)} + id={key} + step={10 ** -precision} + /> + + ); + })} + + + + {t(`calculators.output.${equation}`, { result })} + + + ); }; -export default InteractiveCalculators; +InteractiveCalculator.displayName = "Calculator.Interactive"; + +export default InteractiveCalculator; diff --git a/components/calculators/interactive/peakAbsoluteMagnitude.tsx b/components/calculators/interactive/peakAbsoluteMagnitude.tsx deleted file mode 100644 index 3c0a0a43..00000000 --- a/components/calculators/interactive/peakAbsoluteMagnitude.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/* eslint-disable jsx-a11y/label-has-associated-control */ -/* eslint-disable react/no-unknown-property */ -import { ChangeEvent, FunctionComponent } from "react"; -import { useTranslation } from "react-i18next"; -import isNumber from "lodash/isNumber"; -import { InteractiveCalculatorProps } from "@/types/calculators"; -import MathInput from "@/components/form/Input/patterns/MathInput"; -import Output from "../Output"; -import * as Styled from "./styles"; -import Equation from "@/components/atomic/Equation"; - -const PeakAbsoluteMagnitude: FunctionComponent< - InteractiveCalculatorProps<{ m15?: number }> -> = ({ value = {}, onChangeCallback, className, equation, id }) => { - const { - t, - i18n: { language }, - } = useTranslation(); - const A = 23.59; - const B = 6.45; - const { m15 } = value; - - const { format } = new Intl.NumberFormat(language); - - const m15Id = "dm15"; - const m15Placeholder = t("calculators.peak_absolute_magnitude.placeholder", { - delta: "\u{394}", - interpolation: { escapeValue: false }, - }); - - const handleChange = (event: ChangeEvent) => { - onChangeCallback && - onChangeCallback({ - m15: parseFloat(event.target.value), - }); - }; - - const { result } = equation(value); - - return ( - - - - - - - - - - - - Mpeak - - } - /> - - = - - - {format(A)} - - + - {format(B)} - - ( - - - {isNumber(m15) ? m15 : } - - - ) - - - - - ); -}; - -PeakAbsoluteMagnitude.displayName = - "Calculator.Interactive.PeakAbsoluteMagnitude"; - -export default PeakAbsoluteMagnitude; diff --git a/components/calculators/interactive/styles.ts b/components/calculators/interactive/styles.ts index 5f3c95e3..2d7e0106 100644 --- a/components/calculators/interactive/styles.ts +++ b/components/calculators/interactive/styles.ts @@ -1,5 +1,4 @@ "use client"; -import { token } from "@rubin-epo/epo-react-lib/styles"; import styled from "styled-components"; export const MathContainer = styled.div` @@ -7,15 +6,10 @@ export const MathContainer = styled.div` display: grid; grid-template-columns: 1fr; - grid-template-rows: 1fr 1fr; + grid-auto-rows: 1fr 1fr; gap: var(--math-gap); justify-items: left; - - @container (min-width: ${token("BREAK_TABLET_MIN")}) { - grid-template-columns: auto 1fr; - grid-template-rows: 1fr; - align-items: center; - } + min-width: 50%; `; export const Inputs = styled.form` @@ -28,3 +22,12 @@ export const InputRow = styled.div` display: flex; align-items: center; `; + +export const LiveRegion = styled.output` + position: absolute; + left: -10000px; + top: auto; + width: 1px; + height: 1px; + overflow: hidden; +`; diff --git a/components/calculators/interactive/supernovaDistance.tsx b/components/calculators/interactive/supernovaDistance.tsx deleted file mode 100644 index a322538e..00000000 --- a/components/calculators/interactive/supernovaDistance.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* eslint-disable jsx-a11y/label-has-associated-control */ -/* eslint-disable react/no-unknown-property */ -import { FormEvent, FunctionComponent } from "react"; -import { useTranslation } from "react-i18next"; -import isNumber from "lodash/isNumber"; -import { InteractiveCalculatorProps } from "@/types/calculators"; -import Output from "../Output"; -import MathInput from "@/components/form/Input/patterns/MathInput"; -import * as Styled from "./styles"; -import Equation from "@/components/atomic/Equation"; - -const SupernovaDistance: FunctionComponent< - InteractiveCalculatorProps<{ peakApparent?: number; peakAbsolute?: number }> -> = ({ value = {}, onChangeCallback, className, equation, id }) => { - const { - t, - i18n: { language }, - } = useTranslation(); - const { peakApparent, peakAbsolute } = value; - const { format } = new Intl.NumberFormat(language); - - const handleChange = (event: FormEvent, key: string) => { - return ( - onChangeCallback && - onChangeCallback({ - peakApparent, - peakAbsolute, - [key]: parseFloat(event.target.value), - }) - ); - }; - - const { result } = equation(value); - - const distance = result - ? t("calculators.supernova_distance.result", { - distance: format(result), - }) - : undefined; - - const peakApparentId = "peakApparent"; - const peakAbsoluteId = "peakAbsolute"; - - return ( - - - - - handleChange(e, "peakApparent")} - condensed - id={peakApparentId} - /> - - - - handleChange(e, "peakAbsolute")} - id={peakAbsoluteId} - /> - - - - - - - - - = - - - ( - - {format(3.26)} - - ) - - - - 10 - - - - {isNumber(peakApparent) ? format(peakApparent) : "m"} - - {isNumber(peakAbsolute) ? format(peakAbsolute) : "M"} - - 5 - - + - 1 - - - - - - ); -}; - -SupernovaDistance.displayName = "Calculator.Interactive.SupernovaDistance"; - -export default SupernovaDistance; diff --git a/components/calculators/lib/equations.ts b/components/calculators/lib/equations.ts new file mode 100644 index 00000000..14a81447 --- /dev/null +++ b/components/calculators/lib/equations.ts @@ -0,0 +1,42 @@ +import round from "lodash/round"; +import isNumber from "lodash/isNumber"; +import { Equation, EquationComposer } from "@/types/calculators"; + +const peakAbsoluteMagnitude: EquationComposer = ({ m15 }) => { + const A = -23.598; + const B = 6.457; + + if (isNumber(m15)) { + const result = round(A + B * m15, 1); + + return { constants: { A, B }, result }; + } + + return { constants: { A, B } }; +}; + +const supernovaDistance: EquationComposer = ({ + peakApparentMagnitude, + peakAbsoluteMagnitude, +}) => { + const A = 3.26; + const B = 10; + const C = 5; + const D = 1; + + if (isNumber(peakApparentMagnitude) && isNumber(peakAbsoluteMagnitude)) { + const exponent = (peakApparentMagnitude - peakAbsoluteMagnitude) / C + D; + const result = round((A * Math.pow(B, exponent)) / Math.pow(B, 6)); + + return { constants: { A, B, C, D }, result }; + } + + return { constants: { A, B, C, D } }; +}; + +const Equations: Record = { + peakAbsoluteMagnitude, + supernovaDistance, +}; + +export default Equations; diff --git a/components/calculators/lib/fields.ts b/components/calculators/lib/fields.ts new file mode 100644 index 00000000..f1a4c11e --- /dev/null +++ b/components/calculators/lib/fields.ts @@ -0,0 +1,22 @@ +import { CalculatorInput, Equation } from "@/types/calculators"; +import placeholders from "./placeholders"; + +const FormFields: Record> = { + peakAbsoluteMagnitude: { + m15: { key: "m15", precision: 2, label: `${placeholders.m15} =` }, + }, + supernovaDistance: { + peakApparentMagnitude: { + key: "peakApparentMagnitude", + precision: 1, + label: `${placeholders.peakApparentMagnitude} =`, + }, + peakAbsoluteMagnitude: { + key: "peakAbsoluteMagnitude", + precision: 1, + label: `${placeholders.peakAbsoluteMagnitude} =`, + }, + }, +}; + +export default FormFields; diff --git a/components/calculators/lib/index.ts b/components/calculators/lib/index.ts new file mode 100644 index 00000000..80278517 --- /dev/null +++ b/components/calculators/lib/index.ts @@ -0,0 +1,39 @@ +import { fallbackLng } from "@/lib/i18n/settings"; +import { + Calculator, + CalculatorValues, + NonNullableCalculatorValues, +} from "@/types/calculators"; +import Equations from "./equations"; +import LaTeX from "./latex"; +import FormFields from "./fields"; + +const cleanInput = (values: CalculatorValues): NonNullableCalculatorValues => { + const nonNullValues: NonNullableCalculatorValues = {}; + + Object.keys(values).forEach((key) => { + nonNullValues[key] = values[key] ?? undefined; + }); + + return nonNullValues; +}; + +const Calculator: Calculator = (equation, value, locale = fallbackLng) => { + const cleaned = cleanInput(value); + + const { result } = Equations[equation](cleaned); + + return { + fields: FormFields[equation], + result, + latex: LaTeX[equation]( + { + ...cleaned, + result, + }, + locale + ), + }; +}; + +export default Calculator; diff --git a/components/calculators/lib/latex.ts b/components/calculators/lib/latex.ts new file mode 100644 index 00000000..193fbd49 --- /dev/null +++ b/components/calculators/lib/latex.ts @@ -0,0 +1,76 @@ +import isNumber from "lodash/isNumber"; +import { fallbackLng } from "@/lib/i18n/settings"; +import { LaTeXComposer } from "@/types/calculators"; +import placeholders from "./placeholders"; +import Equations from "./equations"; + +const withClass = (value: string) => `\\class{calc-output}{${value}}`; + +const peakAbsoluteMagnitude: LaTeXComposer = ( + { result = placeholders.peakAbsoluteMagnitude, m15 = placeholders.m15 }, + locale = fallbackLng +) => { + const { + constants: { A, B }, + } = Equations.peakAbsoluteMagnitude({}); + + const { format } = new Intl.NumberFormat(locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); + const { format: resultFormat } = new Intl.NumberFormat(locale, { + minimumFractionDigits: 1, + maximumFractionDigits: 1, + }); + + const displayResult = isNumber(result) ? resultFormat(result) : result; + const displayM15 = isNumber(m15) ? format(m15) : m15; + + return `${withClass(displayResult)} = ${format(A)} + ${format( + B + )}\\left ( ${displayM15} \\right )`; +}; + +const supernovaDistance: LaTeXComposer = ( + { + result = placeholders.distance, + peakAbsoluteMagnitude = placeholders.peakAbsoluteMagnitude, + peakApparentMagnitude = placeholders.peakApparentMagnitude, + }, + locale = fallbackLng +) => { + const { + constants: { A, B, C, D }, + } = Equations.supernovaDistance({}); + + const { format } = new Intl.NumberFormat(locale, { + minimumFractionDigits: 1, + maximumFractionDigits: 1, + }); + + const displayResult = isNumber(result) + ? `${Intl.NumberFormat(locale, { + maximumSignificantDigits: 3, + }).format(result)}\\space\\text{Mly}` + : result; + const displayPeakAbsolute = isNumber(peakAbsoluteMagnitude) + ? format(peakAbsoluteMagnitude) + : peakAbsoluteMagnitude; + const displayPeakApparent = isNumber(peakApparentMagnitude) + ? format(peakApparentMagnitude) + : peakApparentMagnitude; + + return `${withClass(displayResult)} = \\left (${Intl.NumberFormat(locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }).format( + A + )}\\right )${B}^{\\frac{${displayPeakApparent} - ${displayPeakAbsolute}}{${C}} + ${D}}`; +}; + +const LaTeX = { + peakAbsoluteMagnitude, + supernovaDistance, +}; + +export default LaTeX; diff --git a/components/calculators/lib/placeholders.ts b/components/calculators/lib/placeholders.ts new file mode 100644 index 00000000..1c789c8d --- /dev/null +++ b/components/calculators/lib/placeholders.ts @@ -0,0 +1,6 @@ +export default { + distance: "d", + m15: "\\Delta m_{15}", + peakAbsoluteMagnitude: "M", + peakApparentMagnitude: "m", +}; diff --git a/components/calculators/math/index.ts b/components/calculators/math/index.ts deleted file mode 100644 index 33f80fdd..00000000 --- a/components/calculators/math/index.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { fallbackLng } from "@/lib/i18n/settings"; -import { Calculator, Equation } from "@/types/calculators"; -import round from "lodash/round"; -import isNumber from "lodash/isNumber"; - -const peakAbsoluteMagnitude: Calculator = ({ m15 }, locale = fallbackLng) => { - const A = -23.598; - const B = 6.457; - - const result = round(A + B * m15, 2); - const { format } = new Intl.NumberFormat(locale); - - if (isNumber(result)) { - return { - result, - toLaTeX: () => - `${format(result)} = ${format(-23.59)} + ${format( - 6.45 - )}\\left ( ${format(m15)} \\right )`, - }; - } - - return { - result: undefined, - toLaTeX: () => undefined, - }; -}; - -/** Distance in Megalightyears (Mly) */ -const supernovaDistance: Calculator = ( - { peakApparent, peakAbsolute }, - locale = fallbackLng -) => { - const exponent = (peakApparent - peakAbsolute) / 5 + 1; - - const result = round((3.26 * Math.pow(10, exponent)) / Math.pow(10, 6)); - const { format } = new Intl.NumberFormat(locale); - - if (isNumber(peakApparent) && isNumber(peakAbsolute) && isNumber(result)) { - return { - result, - toLaTeX: () => - `${format(result)} Mly = \\left (${format( - 3.26 - )}\\right )10^{\\frac{${format(peakApparent)} - ${format( - peakAbsolute - )}}{5} + 1}`, - }; - } - - return { - result: undefined, - toLaTeX: () => undefined, - }; -}; - -const calculators: Record = { - peakAbsoluteMagnitude, - supernovaDistance, -}; - -export default calculators; diff --git a/components/calculators/static/index.tsx b/components/calculators/static/index.tsx index b5a055a6..1a7dfb3f 100644 --- a/components/calculators/static/index.tsx +++ b/components/calculators/static/index.tsx @@ -1,17 +1,15 @@ import { FunctionComponent } from "react"; import { CalculatorValues, Equation } from "@/types/calculators"; -import Equations from "@/components/calculators/math"; +import Calculator from "@/components/calculators/lib"; import EquationRenderer from "@/components/atomic/Equation"; import { fallbackLng } from "@/lib/i18n/settings"; const StaticCalculator: FunctionComponent<{ - type: Equation; + equation: Equation; value: CalculatorValues; locale?: string; -}> = ({ type, value, locale = fallbackLng }) => { - const equation = Equations[type]; - const latex = equation(value, locale).toLaTeX(); - if (!equation || !latex) return null; +}> = ({ equation, value, locale = fallbackLng }) => { + const { latex } = Calculator(equation, value, locale); return ; }; diff --git a/components/factories/CalculatorFactory/index.tsx b/components/factories/CalculatorFactory/index.tsx deleted file mode 100644 index d7e00793..00000000 --- a/components/factories/CalculatorFactory/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import "@/lib/temml/Temml-Latin-Modern.css"; -import { FunctionComponent } from "react"; -import { Equation, InteractiveCalculatorProps } from "@/types/calculators"; -import InteractiveCalculators from "@/components/calculators/interactive"; -import Calculators from "@/components/calculators/math"; - -interface CalculatorFactoryProps - extends Omit { - type: Equation; -} - -const CalculatorFactory: FunctionComponent = ({ - type, - ...props -}) => { - const Calculator = InteractiveCalculators[type]; - - if (!Calculator) { - console.error(`${type} calculator is not defined`); - return null; - } - - return ; -}; - -CalculatorFactory.displayName = "Factory.Calculator"; - -export default CalculatorFactory; diff --git a/components/form/Input/patterns/MathInput/index.tsx b/components/form/Input/patterns/MathInput/index.tsx index bbb69998..a5658deb 100644 --- a/components/form/Input/patterns/MathInput/index.tsx +++ b/components/form/Input/patterns/MathInput/index.tsx @@ -21,7 +21,7 @@ const MathInput: FunctionComponent = ({ {...props} type="number" placeholder={placeholder} - value={value?.toString() || ""} + value={value?.toString() ?? ""} style={{ width: `calc(${width}ch + calc(var(--input-padding) * 2))`, height: condensed && "2em", diff --git a/components/questions/Calculator/index.tsx b/components/questions/Calculator/index.tsx index 71af65d3..2e08676f 100644 --- a/components/questions/Calculator/index.tsx +++ b/components/questions/Calculator/index.tsx @@ -4,10 +4,10 @@ import { FragmentType, graphql, useFragment } from "@/gql/public-schema"; import useAnswer from "@/hooks/useAnswer"; import { isNullish } from "@/lib/utils"; import { WidgetInput } from "@/types/answers"; -import { Equation } from "@/types/calculators"; -import CalculatorFactory from "@/components/factories/CalculatorFactory"; +import InteractiveCalculator from "@/components/calculators/Interactive"; import QuestionNumber from "../QuestionNumber"; import * as Styled from "./styles"; +import { Equation } from "@/types/calculators"; const Fragment = graphql(` fragment CalculatorQuestion on questions_default_Entry { @@ -35,10 +35,10 @@ const CalculatorQuestion: FunctionComponent = ({ - {questionText} {value ? ( - + ) : ( t("review.no_answer") )} diff --git a/public/localeStrings/en/translation.json b/public/localeStrings/en/translation.json index a8aeed4e..c6726312 100644 --- a/public/localeStrings/en/translation.json +++ b/public/localeStrings/en/translation.json @@ -307,11 +307,9 @@ } }, "calculators": { - "peak_absolute_magnitude": { - "placeholder": "{{delta}}m15" - }, - "supernova_distance": { - "result": "{{distance}} Mly" + "output": { + "supernovaDistance": "{{result}} Mega light-years", + "peakAbsoluteMagnitude": "Peak absolute magnitude {{result}}" } } } diff --git a/theme/styles/components/_index.scss b/theme/styles/components/_index.scss index 6c5f9261..51a7a49a 100644 --- a/theme/styles/components/_index.scss +++ b/theme/styles/components/_index.scss @@ -1,2 +1,3 @@ @forward "content-rte"; @forward "page-header"; +@forward "math"; diff --git a/components/calculators/Output/styles.ts b/theme/styles/components/_math.scss similarity index 52% rename from components/calculators/Output/styles.ts rename to theme/styles/components/_math.scss index 2b0fd97a..020a6bad 100644 --- a/components/calculators/Output/styles.ts +++ b/theme/styles/components/_math.scss @@ -1,19 +1,10 @@ -"use client"; -import styled from "styled-components"; - -export const Output = styled.output` - cursor: default; +.calc-output { background-color: var(--neutral10, #f5f5f5); border: 1px solid var(--neutral60, #6a6e6e); border-radius: 5px; display: flex; align-items: center; - font-size: 0.75em; + height: 1.5em; text-align: center; - height: 2em; padding-inline: 1ch; - - * { - display: inline; - } -`; +} diff --git a/types/calculators.d.ts b/types/calculators.d.ts index 1df82b85..d9a39a27 100644 --- a/types/calculators.d.ts +++ b/types/calculators.d.ts @@ -1,21 +1,37 @@ export type Equation = "peakAbsoluteMagnitude" | "supernovaDistance"; -export type CalculatorValues = Record; +export type CalculatorValues = Record; +export type NonNullableCalculatorValues = Record; + +export interface CalculatorInput { + key: string; + label: string; + precision: number; +} export type Calculator = ( + equation: Equation, variables: T, locale?: string ) => { + fields: Record; result: number | undefined; - toLaTeX: () => string | undefined; + latex: string; }; -export interface CalculatorProps { - equation: Calculator; - value?: T; -} -export interface InteractiveCalculatorProps - extends CalculatorProps { +export interface InteractiveCalculatorProps { id: string; + equation: Equation; onChangeCallback: (value: Partial) => void; className?: string; + value?: T; } + +export type EquationComposer = (values: NonNullableCalculatorValues) => { + constants: Record; + result?: number; +}; + +export type LaTeXComposer = ( + variables: Record, + locale?: string +) => string;