From 49d5c821a2ad07aadf31f09f2814859de2c0f157 Mon Sep 17 00:00:00 2001 From: Jeremy Wiebe Date: Thu, 21 Dec 2023 12:29:55 -0800 Subject: [PATCH 1/6] Add confirmation before deleting a widget config (#894) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: Adds a simple confirmation before proceeding with the widget deletion. This will hopefully prevent alot of frustration by avoiding losing work. Issue: LC-1590 ## Test plan: Run the tests. Author: jeremywiebe Reviewers: jeremywiebe, nedredmond, SonicScrewdriver, handeyeco, nixterrimus, benchristel Required Reviewers: Approved By: nedredmond Checks: ✅ gerald, ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage, ⏭ Publish npm snapshot, ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: https://github.com/Khan/perseus/pull/894 --- .changeset/proud-roses-sneeze.md | 5 + .../src/__tests__/editor.test.tsx | 218 ++++++++++-------- packages/perseus-editor/src/editor.tsx | 7 + 3 files changed, 132 insertions(+), 98 deletions(-) create mode 100644 .changeset/proud-roses-sneeze.md diff --git a/.changeset/proud-roses-sneeze.md b/.changeset/proud-roses-sneeze.md new file mode 100644 index 0000000000..d658f14810 --- /dev/null +++ b/.changeset/proud-roses-sneeze.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus-editor": minor +--- + +Add a confirmation before deleting a configured widget in the Exercise Editor diff --git a/packages/perseus-editor/src/__tests__/editor.test.tsx b/packages/perseus-editor/src/__tests__/editor.test.tsx index 6fca3f411a..f726763445 100644 --- a/packages/perseus-editor/src/__tests__/editor.test.tsx +++ b/packages/perseus-editor/src/__tests__/editor.test.tsx @@ -1,120 +1,142 @@ -import {ApiOptions, Dependencies, Widgets} from "@khanacademy/perseus"; +import { + ApiOptions, + Dependencies, + Widgets, + widgets, + Util, +} from "@khanacademy/perseus"; import {render, screen} from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import * as React from "react"; import "@testing-library/jest-dom"; // Imports custom mathers import {testDependencies} from "../../../../testing/test-dependencies"; -import {wait} from "../../../../testing/wait"; -import {question1} from "../__testdata__/input-number.testdata"; import Editor from "../editor"; +import ImageEditor from "../widgets/image-editor"; + +import type {PropsFor} from "@khanacademy/wonder-blocks-core"; + +const Harnessed = (props: Partial>) => { + return ( + {}} + content="[[☃ image 1]]" + widgets={{ + "image 1": { + type: "image", + options: { + backgroundImage: { + url: "http://placekitten.com/200/300", + }, + }, + }, + }} + {...props} + /> + ); +}; describe("Editor", () => { + beforeAll(() => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const ImageWidget = widgets.find((w) => w.name === "image")!; + expect(ImageWidget).toBeDefined(); + Widgets.registerWidget("image", ImageWidget); + Widgets.registerEditors([ImageEditor]); + }); + beforeEach(() => { jest.spyOn(Dependencies, "getDependencies").mockReturnValue( testDependencies, ); }); - describe("input-number widget", () => { - beforeEach(async () => { - const [InputNumberWidget, InputNumberEditor] = await Promise.all([ - import("@khanacademy/perseus").then((m) => m.InputNumber), - import("../widgets/input-number-editor").then((m) => m.default), - ]); - Widgets.registerWidgets([InputNumberWidget]); - Widgets.registerEditors([InputNumberEditor]); - jest.useRealTimers(); + it("should delete widget if confirmed", async () => { + const onChangeMock = jest.fn(); + jest.spyOn(window, "confirm").mockReturnValue(true); + + // Arrange + render(); + + // Act + userEvent.click( + screen.getByRole("button", {name: "Remove image widget"}), + ); + + // Assert + expect(onChangeMock).toHaveBeenCalledWith({content: ""}); + }); + + it("should NOT delete widget if not confirmed", async () => { + const onChangeMock = jest.fn(); + jest.spyOn(window, "confirm").mockReturnValue(false); + + // Arrange + render(); + + // Act + userEvent.click( + screen.getByRole("button", {name: "Remove image widget"}), + ); + + // Assert + expect(onChangeMock).not.toHaveBeenCalled(); + }); + + test("clicking on the widget editor should open it", async () => { + // Arrange + render(); + + // Act + const widgetDisclosure = screen.getByRole("link", { + name: "image 1", }); + userEvent.click(widgetDisclosure); + + // Assert + const previewImage = screen.getByAltText("Editor preview of image"); + expect(previewImage).toHaveAttribute( + "src", + "http://placekitten.com/200/300", + ); + }); + + it("should update values", async () => { + // Arrange + jest.spyOn(Util, "getImageSizeModern").mockResolvedValue([200, 200]); - test("clicking on the widget editor should open it", async () => { - // Arrange - render( - {}} - />, - ); - await wait(); - - // Act - const widgetDisclosure = screen.getByRole("link", { - name: "input-number 1", - }); - userEvent.click(widgetDisclosure); - const correctAnswerInput = screen.getByLabelText("Correct answer:"); - - // Assert - expect(correctAnswerInput).toHaveValue("0.5"); + const changeFn = jest.fn(); + render(); + + // Act + const widgetDisclosure = screen.getByRole("link", { + name: "image 1", }); + userEvent.click(widgetDisclosure); - it("should update values", async () => { - // Arrange - const changeFn = jest.fn(); - render( - , - ); - await wait(); - - // Act - const widgetDisclosure = screen.getByRole("link", { - name: "input-number 1", - }); - userEvent.click(widgetDisclosure); - const correctAnswerInput = screen.getByLabelText("Correct answer:"); - - userEvent.clear(correctAnswerInput); - userEvent.paste(correctAnswerInput, "0.75"); - userEvent.tab(); // blurring the input triggers onChange to be called - - // Assert - expect(changeFn).toHaveBeenCalledWith( - { - widgets: { - "input-number 1": { - graded: true, - version: {major: 0, minor: 0}, - static: false, - type: "input-number", - options: { - value: 0.75, - simplify: "required", - size: "normal", - inexact: false, - maxError: 0.1, - answerType: "number", - rightAlign: false, - }, - alignment: "default", - }, - }, + const captionInput = screen.getByLabelText(/Caption:/); + + userEvent.clear(captionInput); + userEvent.type(captionInput, "A picture of kittens"); + userEvent.tab(); // blurring the input triggers onChange to be called + jest.runOnlyPendingTimers(); + + // Assert + expect(changeFn).toHaveBeenCalledWith( + { + widgets: { + "image 1": expect.objectContaining({ + type: "image", + graded: true, + options: expect.objectContaining({ + caption: "A picture of kittens", + }), + }), }, - undefined, - undefined, - ); - }); + }, + undefined, + undefined, + ); }); }); diff --git a/packages/perseus-editor/src/editor.tsx b/packages/perseus-editor/src/editor.tsx index 8cd75f286b..007b53fa7d 100644 --- a/packages/perseus-editor/src/editor.tsx +++ b/packages/perseus-editor/src/editor.tsx @@ -293,6 +293,11 @@ class Editor extends React.Component { }; _handleWidgetEditorRemove: (id: string) => void = (id: string) => { + // eslint-disable-next-line no-alert + if (!confirm("Are you sure you want to delete this item?")) { + return; + } + // eslint-disable-next-line react/no-string-refs const textarea = this.refs.textarea; const re = new RegExp(widgetRegExp.replace("{id}", id), "gm"); @@ -930,6 +935,8 @@ class Editor extends React.Component { underlayPieces = []; for (let i = 0; i < pieces.length; i++) { + // We split on widgets so every even-numbered indexed piece is + // text and odd-numbered indexes are the widget references. if (i % 2 === 0) { // Normal text underlayPieces.push(pieces[i]); From 049810636968afac5672f790896768338319810a Mon Sep 17 00:00:00 2001 From: Jeremy Wiebe Date: Mon, 8 Jan 2024 10:29:48 -0800 Subject: [PATCH 2/6] Add confirmation before deleting a hint (#896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: Adds a simple confirmation before proceeding with the hint is deleted. This will hopefully prevent alot of frustration by avoiding losing work. Issue: LC-1591 ## Test plan: Author: jeremywiebe Reviewers: handeyeco, nixterrimus, jeremywiebe, SonicScrewdriver, nedredmond Required Reviewers: Approved By: handeyeco, nixterrimus Checks: ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage, ✅ gerald, ✅ Jest Coverage (ubuntu-latest, 20.x), ⏭ Publish npm snapshot, ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ gerald, ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x) Pull Request URL: https://github.com/Khan/perseus/pull/896 --- .changeset/shiny-pugs-jump.md | 5 ++ .../src/__tests__/hint-editor.test.tsx | 83 +++++++++++++++++++ packages/perseus-editor/src/hint-editor.tsx | 5 ++ 3 files changed, 93 insertions(+) create mode 100644 .changeset/shiny-pugs-jump.md create mode 100644 packages/perseus-editor/src/__tests__/hint-editor.test.tsx diff --git a/.changeset/shiny-pugs-jump.md b/.changeset/shiny-pugs-jump.md new file mode 100644 index 0000000000..0f1f442a88 --- /dev/null +++ b/.changeset/shiny-pugs-jump.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus-editor": minor +--- + +Add a confirmation before deleting a hint in the Exercise Editor diff --git a/packages/perseus-editor/src/__tests__/hint-editor.test.tsx b/packages/perseus-editor/src/__tests__/hint-editor.test.tsx new file mode 100644 index 0000000000..2ed18fde0c --- /dev/null +++ b/packages/perseus-editor/src/__tests__/hint-editor.test.tsx @@ -0,0 +1,83 @@ +import "@testing-library/jest-dom"; +import {render, screen} from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import * as React from "react"; + +import CombinedHintsEditor from "../hint-editor"; + +describe("CombinedHintsEditor", () => { + it("should render", () => { + render( + , + ); + }); + + it("should confirm before removing a hint", () => { + // Arrange + const comfirmSpy = jest.spyOn(window, "confirm").mockReturnValue(false); + render( + , + ); + + // Act + userEvent.click(screen.getAllByText("Remove this hint")[0]); + + // Assert + expect(comfirmSpy).toHaveBeenCalled(); + }); + + it("should not remove the hint if not confirmed", () => { + // Arrange + jest.spyOn(window, "confirm").mockReturnValue(false); + const onChangeMock = jest.fn(); + render( + , + ); + + // Act + userEvent.click(screen.getAllByText("Remove this hint")[0]); + + // Assert + expect(onChangeMock).not.toHaveBeenCalled(); + }); + + it("should remove the hint if confirmed", () => { + // Arrange + jest.spyOn(window, "confirm").mockReturnValue(true); + const onChangeMock = jest.fn(); + render( + , + ); + + // Act + userEvent.click(screen.getAllByText("Remove this hint")[0]); + + // Assert + expect(onChangeMock).toHaveBeenCalledWith({ + hints: [{content: "Ok, the answer is 3", widgets: {}, images: {}}], + }); + }); +}); diff --git a/packages/perseus-editor/src/hint-editor.tsx b/packages/perseus-editor/src/hint-editor.tsx index e785ef83b3..26033aff23 100644 --- a/packages/perseus-editor/src/hint-editor.tsx +++ b/packages/perseus-editor/src/hint-editor.tsx @@ -346,6 +346,11 @@ class CombinedHintsEditor extends React.Component { }; handleHintRemove: (i: number) => void = (i: number) => { + // eslint-disable-next-line no-alert + if (!confirm("Are you sure you want to delete this hint?")) { + return; + } + const hints = _(this.props.hints).clone(); // @ts-expect-error - TS2339 - Property 'splice' does not exist on type 'Hint'. hints.splice(i, 1); From a547933946b8be33b388fa4654d87289734848f0 Mon Sep 17 00:00:00 2001 From: Tamara <60857422+Myranae@users.noreply.github.com> Date: Tue, 16 Jan 2024 09:07:03 -0600 Subject: [PATCH 3/6] Update Perseus' Storybook to use MathJax instead of KaTeX (#917) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: Storybook for Perseus was still using KaTeX for math expressions. This updates it to use MathJax. BEFORE: ![image](https://github.com/Khan/perseus/assets/60857422/c28289ee-615f-42a6-b3a4-dbb1fad02bb9) NOW: image NOTE: There are still references to KaTeX in Perseus. More research is required to make sure MathJax is used everywhere in Perseus or at least to remove all references to KaTeX. Issue: LC-1573 ## Test plan: - Confirm Perseus Storybook stories with math use MathJax instead of KaTex - Confirm all tests pass Author: Myranae Reviewers: jeremywiebe, benchristel Required Reviewers: Approved By: jeremywiebe Checks: ✅ gerald, ✅ codecov/project, ✅ Upload Coverage, ⏭️ Publish npm snapshot, ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ gerald, ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ codecov/patch, ✅ Upload Coverage, ⏭️ Publish npm snapshot, ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: https://github.com/Khan/perseus/pull/917 --- .changeset/perfect-eels-divide.md | 5 ++ .github/workflows/node-ci.yml | 4 ++ packages/perseus/package.json | 1 + testing/test-dependencies.tsx | 6 +-- testing/test-mathjax.tsx | 33 ++++++++++++ testing/test-tex.tsx | 88 ------------------------------- yarn.lock | 61 +++++++++++++++++++++ 7 files changed, 107 insertions(+), 91 deletions(-) create mode 100644 .changeset/perfect-eels-divide.md create mode 100644 testing/test-mathjax.tsx delete mode 100644 testing/test-tex.tsx diff --git a/.changeset/perfect-eels-divide.md b/.changeset/perfect-eels-divide.md new file mode 100644 index 0000000000..5506c856e5 --- /dev/null +++ b/.changeset/perfect-eels-divide.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus": minor +--- + +Update Perseus' Storybook to use MathJax instead of KaTeX diff --git a/.github/workflows/node-ci.yml b/.github/workflows/node-ci.yml index 6b46f714e7..172e389cfc 100644 --- a/.github/workflows/node-ci.yml +++ b/.github/workflows/node-ci.yml @@ -37,6 +37,10 @@ jobs: matchAllGlobs: true # Default is to match any of the globs, which ends up matching all files conjunctive: true # Only match files that match all of the above + - uses: webfactory/ssh-agent@v0.7.0 + with: + ssh-private-key: ${{ secrets.KHAN_ACTIONS_BOT_SSH_PRIVATE_KEY }} + - name: Verify changeset entries uses: Khan/changeset-per-package@v1.0.1 with: diff --git a/packages/perseus/package.json b/packages/perseus/package.json index 4f1416c083..cc48c66221 100644 --- a/packages/perseus/package.json +++ b/packages/perseus/package.json @@ -25,6 +25,7 @@ "@khanacademy/kas": "^0.3.7", "@khanacademy/kmath": "^0.1.8", "@khanacademy/math-input": "^16.5.0", + "@khanacademy/mathjax-renderer": "git+ssh://git@github.com:Khan/mathjax-renderer.git#v1.5.0", "@khanacademy/perseus-core": "1.4.1", "@khanacademy/perseus-linter": "^0.3.10", "@khanacademy/pure-markdown": "^0.2.13", diff --git a/testing/test-dependencies.tsx b/testing/test-dependencies.tsx index 39a948c8ac..7cf38c594f 100644 --- a/testing/test-dependencies.tsx +++ b/testing/test-dependencies.tsx @@ -4,7 +4,7 @@ import * as React from "react"; import {registerAllWidgetsForTesting} from "../packages/perseus/src/util/register-all-widgets-for-testing"; -import {TestTeX} from "./test-tex"; +import {TestMathjax} from "./test-mathjax"; import type {ILogger} from "../packages/perseus/src/logging/log"; import type { @@ -121,7 +121,7 @@ export const testDependenciesV2: PerseusDependenciesV2 = { export const storybookTestDependencies: PerseusDependencies = { ...testDependencies, - TeX: TestTeX, + TeX: TestMathjax, // $FlowIgnore[incompatible-type] staticUrl: (str) => str, }; @@ -133,7 +133,7 @@ export const storybookDependenciesV2: PerseusDependenciesV2 = { export const cypressTestDependencies: PerseusDependencies = { ...testDependencies, - TeX: TestTeX, + TeX: TestMathjax, // $FlowIgnore[incompatible-type] staticUrl: (str) => str, }; diff --git a/testing/test-mathjax.tsx b/testing/test-mathjax.tsx new file mode 100644 index 0000000000..4ba956d7b2 --- /dev/null +++ b/testing/test-mathjax.tsx @@ -0,0 +1,33 @@ +import {MathJaxRenderer} from "@khanacademy/mathjax-renderer"; +import * as React from "react"; +import "@khanacademy/mathjax-renderer/src/css/mathjax.css"; + +// if you want \text{} to look good on Safari: +import "@khanacademy/mathjax-renderer/src/css/safari-hacks.css"; + +// if you want copy-paste support: +import "@khanacademy/mathjax-renderer/src/css/selectable.css"; + +const renderer = new MathJaxRenderer({ + // shouldFixUnicodeLayout ensures that non-ASCII text is correctly + // measured and positioned in e.g. \overbrace and \underbrace expressions. + // Set shouldFixUnicodeLayout to false if you're rendering in an + // environment without a layout engine, e.g. jsdom. + shouldFixUnicodeLayout: true, + fontURL: "https://cdn.kastatic.org/fonts/mathjax", +}); + +type Props = { + children: string; + onRender?: (root?: any) => unknown; +}; + +export function TestMathjax({children: tex, onRender}: Props) { + const {domElement} = renderer.render(tex); + + React.useEffect(() => { + renderer.updateStyles(); + onRender?.(); + }, [tex, onRender]); + return ; +} diff --git a/testing/test-tex.tsx b/testing/test-tex.tsx deleted file mode 100644 index b469f271c4..0000000000 --- a/testing/test-tex.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import {useUniqueIdWithMock} from "@khanacademy/wonder-blocks-core"; -import katex from "katex"; -import renderA11yString from "katex/dist/contrib/render-a11y-string"; -import * as React from "react"; -import "katex/dist/katex.css"; - -import type {PerseusDependencies} from "../packages/perseus/src/types"; -import type {PropsFor} from "@khanacademy/wonder-blocks-core"; - -type Props = PropsFor; - -/** - * A test version of TeX that can be used in tests and doesn't rely on - * any webapp/mobile dependencies. Math is rendered synchronously using - * renderToString/renderA11yString. If KaTeX can't process `children` - * an empty string is rendered instead. - */ -export const TestTeX = (props: Props): React.ReactElement => { - const {children, katexOptions, onRender} = props; - - const katexHtml = React.useMemo(() => { - try { - return katex.renderToString(children, katexOptions || {}); - } catch (e: any) { - return ""; - } - }, [children, katexOptions]); - const katexA11yHtml = React.useMemo(() => { - try { - return renderA11yString(children); - } catch (e: any) { - return ""; - } - }, [children]); - - const ids = useUniqueIdWithMock(); - const describedById = `katex-${ids.get("described-by-id")}`; - - React.useEffect(() => { - if (onRender) { - onRender(); - } - // NOTE(kevinb): We intentionally leave the deps list empty here - // since we want this code to only run once on mount. - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - - - {/* - * If we generated readable english text, it goes here. - * The srOnly styles will prevent it from being displayed - * visually. - */} - - - ); -}; - -const srOnly = { - border: 0, - clip: "rect(0,0,0,0)", - height: "1px", - margin: "-1px", - overflow: "hidden", - padding: 0, - position: "absolute", - width: "1px", -} as const; diff --git a/yarn.lock b/yarn.lock index 01acd5c056..2b363aefd9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2399,6 +2399,13 @@ "@typescript-eslint/utils" "^5.60.1" checksync "^5.0.0" +"@khanacademy/mathjax-renderer@git+ssh://git@github.com:Khan/mathjax-renderer.git#v1.5.0": + version "1.5.0" + resolved "git+ssh://git@github.com:Khan/mathjax-renderer.git#3277aaa03f743942a2f585ea8be76384d723dbba" + dependencies: + mathjax-full "3.2.2" + mu-lambda "^0.0.3" + "@khanacademy/wonder-blocks-banner@^3.0.33": version "3.0.34" resolved "https://registry.yarnpkg.com/@khanacademy/wonder-blocks-banner/-/wonder-blocks-banner-3.0.34.tgz#b19e7b6757d9ce94eb0882189a75f94d15b9aa16" @@ -6892,6 +6899,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9" + integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w== + commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -8602,6 +8614,11 @@ eslint@^8.40.0: strip-ansi "^6.0.1" text-table "^0.2.0" +esm@^3.2.25: + version "3.2.25" + resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" + integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== + espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" @@ -12332,6 +12349,16 @@ markdown-to-jsx@^7.1.8: resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.3.2.tgz#f286b4d112dad3028acc1e77dfe1f653b347e131" integrity sha512-B+28F5ucp83aQm+OxNrPkS8z0tMKaeHiy0lHJs3LqCyDQFtWuenaIrkaVTgAm1pf1AU85LXltva86hlaT17i8Q== +mathjax-full@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/mathjax-full/-/mathjax-full-3.2.2.tgz#43f02e55219db393030985d2b6537ceae82f1fa7" + integrity sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w== + dependencies: + esm "^3.2.25" + mhchemparser "^4.1.0" + mj-context-menu "^0.6.1" + speech-rule-engine "^4.0.6" + "mathquill@git+https://git@github.com/Khan/mathquill.git#48410e80d760bbd5105544d4a4ab459a28dc2cbc": version "0.10.1" resolved "git+https://git@github.com/Khan/mathquill.git#48410e80d760bbd5105544d4a4ab459a28dc2cbc" @@ -12428,6 +12455,11 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +mhchemparser@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/mhchemparser/-/mhchemparser-4.2.1.tgz#d73982e66bc06170a85b1985600ee9dabe157cb0" + integrity sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ== + micromatch@^3.1.10: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -12646,6 +12678,11 @@ mixme@^0.5.1: resolved "https://registry.yarnpkg.com/mixme/-/mixme-0.5.4.tgz#8cb3bd0cd32a513c161bf1ca99d143f0bcf2eff3" integrity sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw== +mj-context-menu@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/mj-context-menu/-/mj-context-menu-0.6.1.tgz#a043c5282bf7e1cf3821de07b13525ca6f85aa69" + integrity sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA== + mkdirp-classic@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" @@ -12683,6 +12720,11 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mu-lambda@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/mu-lambda/-/mu-lambda-0.0.3.tgz#3b4f1a5bc8f6cf3e6d3a3f3d35df91d4c09651ce" + integrity sha512-t5mnn/RizL/UCERDxqFQyIEMhjAbq+xohNW/hZzL40NRxkhmXIlDyjK59tj41ltPgXOtpE/w1wAiqvnOhF13og== + multicast-dns@^7.2.5: version "7.2.5" resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" @@ -15696,6 +15738,15 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" +speech-rule-engine@^4.0.6: + version "4.0.7" + resolved "https://registry.yarnpkg.com/speech-rule-engine/-/speech-rule-engine-4.0.7.tgz#b655dacbad3dae04acc0f7665e26ef258397dd09" + integrity sha512-sJrL3/wHzNwJRLBdf6CjJWIlxC04iYKkyXvYSVsWVOiC2DSkHmxsqOhEeMsBA9XK+CHuNcsdkbFDnoUfAsmp9g== + dependencies: + commander "9.2.0" + wicked-good-xpath "1.3.0" + xmldom-sre "0.1.31" + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" @@ -17207,6 +17258,11 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" +wicked-good-xpath@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz#81b0e95e8650e49c94b22298fff8686b5553cf6c" + integrity sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw== + wide-align@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" @@ -17351,6 +17407,11 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmldom-sre@0.1.31: + version "0.1.31" + resolved "https://registry.yarnpkg.com/xmldom-sre/-/xmldom-sre-0.1.31.tgz#10860d5bab2c603144597d04bf2c4980e98067f4" + integrity sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw== + xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" From 6b146bfe196e3aeba370f18e6d981e9ea8ce6045 Mon Sep 17 00:00:00 2001 From: Khan Actions Bot <56267880+khan-actions-bot@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:08:49 -0500 Subject: [PATCH 4/6] Version Packages (#924) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## @khanacademy/perseus@17.8.0 ### Minor Changes - [#917](https://github.com/Khan/perseus/pull/917) [`a5479339`](https://github.com/Khan/perseus/commit/a547933946b8be33b388fa4654d87289734848f0) Thanks [@Myranae](https://github.com/Myranae)! - Update Perseus' Storybook to use MathJax instead of KaTeX ## @khanacademy/perseus-editor@2.17.0 ### Minor Changes - [#894](https://github.com/Khan/perseus/pull/894) [`49d5c821`](https://github.com/Khan/perseus/commit/49d5c821a2ad07aadf31f09f2814859de2c0f157) Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add a confirmation before deleting a configured widget in the Exercise Editor - [#896](https://github.com/Khan/perseus/pull/896) [`04981063`](https://github.com/Khan/perseus/commit/049810636968afac5672f790896768338319810a) Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add a confirmation before deleting a hint in the Exercise Editor ### Patch Changes - Updated dependencies \[[`a5479339`](https://github.com/Khan/perseus/commit/a547933946b8be33b388fa4654d87289734848f0)]: - @khanacademy/perseus@17.8.0 Author: khan-actions-bot Reviewers: jeremywiebe Required Reviewers: Approved By: jeremywiebe Checks: ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage, ⏭ Publish npm snapshot, ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: https://github.com/Khan/perseus/pull/924 --- .changeset/perfect-eels-divide.md | 5 ----- .changeset/proud-roses-sneeze.md | 5 ----- .changeset/shiny-pugs-jump.md | 5 ----- packages/perseus-editor/CHANGELOG.md | 13 +++++++++++++ packages/perseus-editor/package.json | 4 ++-- packages/perseus/CHANGELOG.md | 6 ++++++ packages/perseus/package.json | 2 +- 7 files changed, 22 insertions(+), 18 deletions(-) delete mode 100644 .changeset/perfect-eels-divide.md delete mode 100644 .changeset/proud-roses-sneeze.md delete mode 100644 .changeset/shiny-pugs-jump.md diff --git a/.changeset/perfect-eels-divide.md b/.changeset/perfect-eels-divide.md deleted file mode 100644 index 5506c856e5..0000000000 --- a/.changeset/perfect-eels-divide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@khanacademy/perseus": minor ---- - -Update Perseus' Storybook to use MathJax instead of KaTeX diff --git a/.changeset/proud-roses-sneeze.md b/.changeset/proud-roses-sneeze.md deleted file mode 100644 index d658f14810..0000000000 --- a/.changeset/proud-roses-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@khanacademy/perseus-editor": minor ---- - -Add a confirmation before deleting a configured widget in the Exercise Editor diff --git a/.changeset/shiny-pugs-jump.md b/.changeset/shiny-pugs-jump.md deleted file mode 100644 index 0f1f442a88..0000000000 --- a/.changeset/shiny-pugs-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@khanacademy/perseus-editor": minor ---- - -Add a confirmation before deleting a hint in the Exercise Editor diff --git a/packages/perseus-editor/CHANGELOG.md b/packages/perseus-editor/CHANGELOG.md index 3a1270d0c2..68756a9128 100644 --- a/packages/perseus-editor/CHANGELOG.md +++ b/packages/perseus-editor/CHANGELOG.md @@ -1,5 +1,18 @@ # @khanacademy/perseus-editor +## 2.17.0 + +### Minor Changes + +- [#894](https://github.com/Khan/perseus/pull/894) [`49d5c821`](https://github.com/Khan/perseus/commit/49d5c821a2ad07aadf31f09f2814859de2c0f157) Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add a confirmation before deleting a configured widget in the Exercise Editor + +* [#896](https://github.com/Khan/perseus/pull/896) [`04981063`](https://github.com/Khan/perseus/commit/049810636968afac5672f790896768338319810a) Thanks [@jeremywiebe](https://github.com/jeremywiebe)! - Add a confirmation before deleting a hint in the Exercise Editor + +### Patch Changes + +- Updated dependencies [[`a5479339`](https://github.com/Khan/perseus/commit/a547933946b8be33b388fa4654d87289734848f0)]: + - @khanacademy/perseus@17.8.0 + ## 2.16.2 ### Patch Changes diff --git a/packages/perseus-editor/package.json b/packages/perseus-editor/package.json index 6abe76d0d2..25f7d90e67 100644 --- a/packages/perseus-editor/package.json +++ b/packages/perseus-editor/package.json @@ -3,7 +3,7 @@ "description": "Perseus editors", "author": "Khan Academy", "license": "MIT", - "version": "2.16.2", + "version": "2.17.0", "publishConfig": { "access": "public" }, @@ -25,7 +25,7 @@ "@khanacademy/kas": "^0.3.7", "@khanacademy/kmath": "^0.1.8", "@khanacademy/math-input": "^16.5.0", - "@khanacademy/perseus": "^17.7.0", + "@khanacademy/perseus": "^17.8.0", "@khanacademy/perseus-core": "1.4.1" }, "devDependencies": { diff --git a/packages/perseus/CHANGELOG.md b/packages/perseus/CHANGELOG.md index 166ce126a1..18a4efcb06 100644 --- a/packages/perseus/CHANGELOG.md +++ b/packages/perseus/CHANGELOG.md @@ -1,5 +1,11 @@ # @khanacademy/perseus +## 17.8.0 + +### Minor Changes + +- [#917](https://github.com/Khan/perseus/pull/917) [`a5479339`](https://github.com/Khan/perseus/commit/a547933946b8be33b388fa4654d87289734848f0) Thanks [@Myranae](https://github.com/Myranae)! - Update Perseus' Storybook to use MathJax instead of KaTeX + ## 17.7.0 ### Minor Changes diff --git a/packages/perseus/package.json b/packages/perseus/package.json index cc48c66221..6471f3f674 100644 --- a/packages/perseus/package.json +++ b/packages/perseus/package.json @@ -3,7 +3,7 @@ "description": "Core Perseus API (includes renderers and widgets)", "author": "Khan Academy", "license": "MIT", - "version": "17.7.0", + "version": "17.8.0", "publishConfig": { "access": "public" }, From 4c2c2abc9c8dbe57a0036ff7873926ef5ecdd6e6 Mon Sep 17 00:00:00 2001 From: Ned Redmond Date: Thu, 18 Jan 2024 16:50:42 -0500 Subject: [PATCH 5/6] Add generated labels to MathJax in Storybook (#926) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds generated labels to MathJax in Storybook so that we can effectively test accessibility without involving webapp. Issue: LC-1635 Author: nedredmond Reviewers: benchristel, nedredmond, Myranae, jeremywiebe Required Reviewers: Approved By: benchristel Checks: ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage, ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ gerald, ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x) Pull Request URL: https://github.com/Khan/perseus/pull/926 --- .changeset/red-beans-dress.md | 5 +++++ packages/perseus/package.json | 2 +- testing/test-mathjax.tsx | 17 +++++++++++++++-- yarn.lock | 6 +++--- 4 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 .changeset/red-beans-dress.md diff --git a/.changeset/red-beans-dress.md b/.changeset/red-beans-dress.md new file mode 100644 index 0000000000..b72eaf0a7e --- /dev/null +++ b/.changeset/red-beans-dress.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/perseus": patch +--- + +Upgrade MathJax diff --git a/packages/perseus/package.json b/packages/perseus/package.json index 6471f3f674..3d96c4d756 100644 --- a/packages/perseus/package.json +++ b/packages/perseus/package.json @@ -25,7 +25,6 @@ "@khanacademy/kas": "^0.3.7", "@khanacademy/kmath": "^0.1.8", "@khanacademy/math-input": "^16.5.0", - "@khanacademy/mathjax-renderer": "git+ssh://git@github.com:Khan/mathjax-renderer.git#v1.5.0", "@khanacademy/perseus-core": "1.4.1", "@khanacademy/perseus-linter": "^0.3.10", "@khanacademy/pure-markdown": "^0.2.13", @@ -33,6 +32,7 @@ "@khanacademy/wonder-blocks-banner": "^3.0.33" }, "devDependencies": { + "@khanacademy/mathjax-renderer": "git+ssh://git@github.com:Khan/mathjax-renderer.git#v1.5.1", "@khanacademy/wonder-blocks-button": "^6.2.5", "@khanacademy/wonder-blocks-clickable": "^4.0.12", "@khanacademy/wonder-blocks-color": "^3.0.0", diff --git a/testing/test-mathjax.tsx b/testing/test-mathjax.tsx index 4ba956d7b2..581fce3111 100644 --- a/testing/test-mathjax.tsx +++ b/testing/test-mathjax.tsx @@ -23,11 +23,24 @@ type Props = { }; export function TestMathjax({children: tex, onRender}: Props) { - const {domElement} = renderer.render(tex); + const ref = React.useRef(null); + const {domElement, addLabelWhenPresentational} = React.useMemo( + () => renderer.render(tex), + [tex], + ); + + React.useLayoutEffect(() => { + if (ref.current) { + addLabelWhenPresentational(ref.current); + ref.current.innerHTML = ""; + ref.current.appendChild(domElement); + } + }); React.useEffect(() => { renderer.updateStyles(); onRender?.(); }, [tex, onRender]); - return ; + + return ; } diff --git a/yarn.lock b/yarn.lock index 2b363aefd9..50530bd42d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2399,9 +2399,9 @@ "@typescript-eslint/utils" "^5.60.1" checksync "^5.0.0" -"@khanacademy/mathjax-renderer@git+ssh://git@github.com:Khan/mathjax-renderer.git#v1.5.0": - version "1.5.0" - resolved "git+ssh://git@github.com:Khan/mathjax-renderer.git#3277aaa03f743942a2f585ea8be76384d723dbba" +"@khanacademy/mathjax-renderer@git+ssh://git@github.com:Khan/mathjax-renderer.git#v1.5.1": + version "1.5.1" + resolved "git+ssh://git@github.com:Khan/mathjax-renderer.git#17e5f540f20a717779824a42912ad8284ce04db2" dependencies: mathjax-full "3.2.2" mu-lambda "^0.0.3" From 1e179194e9674b267be11c280f80faa5cc671d91 Mon Sep 17 00:00:00 2001 From: Ben Christel Date: Thu, 18 Jan 2024 14:54:17 -0800 Subject: [PATCH 6/6] Delete unused code from tex.ts (#927) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: There was a lot of code in this file related to our old KaTeX+MathJax2 renderer. Now that we have switched to MathJax 3, we can simplify things. I've also deleted a couple functions that simply weren't used anywhere. I changed the type of `processMath`'s `text` param to `string | number` because the code that generates Graphie labels sometimes passes a number. Issue: none Test plan: Review storybook stories that use TeX labels: - Grapher widget - Interactive Graph widget - Number Line widget The graph labels should display in the correct place. Author: benchristel Reviewers: benchristel, jeremywiebe Required Reviewers: Approved By: jeremywiebe Checks: ✅ codecov/project, ✅ codecov/patch, ✅ Upload Coverage, ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Extract i18n strings (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x), ✅ Cypress (ubuntu-latest, 20.x), ✅ Jest Coverage (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ gerald Pull Request URL: https://github.com/Khan/perseus/pull/927 --- .changeset/proud-donkeys-sip.md | 6 + packages/perseus/src/util/tex.ts | 95 +---- .../__snapshots__/grapher.test.ts.snap | 360 ++++-------------- .../__snapshots__/interaction.test.ts.snap | 25 +- .../interactive-graph.test.ts.snap | 160 ++------ .../__snapshots__/number-line.test.ts.snap | 110 ++---- .../__snapshots__/plotter.test.tsx.snap | 60 +-- 7 files changed, 160 insertions(+), 656 deletions(-) create mode 100644 .changeset/proud-donkeys-sip.md diff --git a/.changeset/proud-donkeys-sip.md b/.changeset/proud-donkeys-sip.md new file mode 100644 index 0000000000..2dd6eac5ec --- /dev/null +++ b/.changeset/proud-donkeys-sip.md @@ -0,0 +1,6 @@ +--- +"@khanacademy/perseus": patch +--- + +Remove unused code related to KaTeX and MathJax 2. It's no longer needed +because all callers have upgraded to MathJax 3. diff --git a/packages/perseus/src/util/tex.ts b/packages/perseus/src/util/tex.ts index 77aca6e094..cb46519141 100644 --- a/packages/perseus/src/util/tex.ts +++ b/packages/perseus/src/util/tex.ts @@ -6,8 +6,6 @@ import {getDependencies} from "../dependencies"; import KhanMath from "./math"; import reactRender from "./react-render"; -declare const MathJax: any; - function findChildOrAdd(elem: any, className: string) { const $child = $(elem).find("." + className); if ($child.length === 0) { @@ -16,27 +14,6 @@ function findChildOrAdd(elem: any, className: string) { return $child; } -function doCallback( - elem: HTMLElement, - callback: (() => unknown) | (() => void), -) { - let tries = 0; - (function check() { - const height = elem.scrollHeight; - // Heuristic to guess if the font has kicked in - // so we have box metrics (magic number ick, - // but this seems to work mostly-consistently) - if (height > 18 || tries >= 10) { - callback(); - } else { - tries++; - // TODO(jeff, CP-3128): Use Wonder Blocks Timing API - // eslint-disable-next-line no-restricted-syntax - setTimeout(check, 100); - } - })(); -} - export default { // Process a node and add math inside of it. This attempts to use KaTeX to // format the math, and if that fails it falls back to MathJax. @@ -55,7 +32,7 @@ export default { // processed processMath: async function ( elem: HTMLElement, - text: string, + text: string | number, force?: boolean, callback?: () => unknown, ) { @@ -63,29 +40,14 @@ export default { // Only process if it hasn't been done before, or it is forced if ($elem.attr("data-math-formula") == null || force) { - const $katexHolder = findChildOrAdd($elem, "katex-holder"); - const $mathjaxHolder = findChildOrAdd($elem, "mathjax-holder"); - - // Search for MathJax-y script tags inside of the node. These are - // used by MathJax to denote the formula to be typeset. Before, we - // would update the formula by updating the contents of the script - // tag, which shouldn't happen any more, but we manage them just in - // case. - const script: HTMLElement | undefined = $mathjaxHolder.find( - "script[type='math/tex']", - )[0]; - - // If text wasn't provided, we look in two places - if (text == null) { - if ($elem.attr("data-math-formula")) { - // The old typeset formula - // @ts-expect-error - TS2322 - Type 'string | undefined' is not assignable to type 'string'. - text = $elem.attr("data-math-formula"); - } else if (script) { - // The contents of the