Skip to content

Commit

Permalink
Add micromark-extension-math to enable TeX block in Markdown (#5332)
Browse files Browse the repository at this point in the history
* Add `micromark-extension-math`

* Add entry

* Add screenshot

* Add link

* Add tests

* Change to approx

* Whitelist transform for math
  • Loading branch information
compulim authored Oct 25, 2024
1 parent 8356902 commit 51385f7
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Notes: web developers are advised to use [`~` (tilde range)](https://github.com/
- Added new style options `borderAnimationColor1`, `borderAnimationColor2`, and `borderAnimationColor3` for customizing decorator colors, in PR [#5312](https://github.com/microsoft/BotFramework-WebChat/pull/5312)
- Added `styleOptions.bubbleAttachmentMaxWidth`/`bubbleAttachmentMinWidth` and `styleOptions.bubbleMessageMaxWidth`/`bubbleMessageMinWidth`, in PR [#5321](https://github.com/microsoft/BotFramework-WebChat/pull/5321), by [@compulim](https://github.com/compulim)
- (Experimental) Added more CSS variables support, in PR [#5321](https://github.com/microsoft/BotFramework-WebChat/pull/5321), by [@compulim](https://github.com/compulim)
- Added MathML/TeX block support in Markdown via [`micromark-extension-math`](https://npmjs.com/package/micromark-extension-math) and [`katex`](https://katex.org/), in PR [#5332](https://github.com/microsoft/BotFramework-WebChat/pull/5332), by [@compulim](https://github.com/compulim)

### Changed

Expand Down
68 changes: 68 additions & 0 deletions __tests__/html2/markdown/math.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
</head>

<body>
<main id="webchat"></main>
<script>
run(async function () {
await host.windowSize(640, 720, document.getElementById('webchat'));

const {
WebChat: { renderWebChat }
} = window; // Imports in UMD fashion.

const { directLine, store } = testHelpers.createDirectLineEmulator();

renderWebChat({ directLine, store }, document.getElementById('webchat'));

await pageConditions.uiConnected();

await directLine.emulateIncomingActivity({
text: `On January 1, 2018, the closing stock price of Microsoft was **$85.95**. On December 1, 2021, the closing stock price was **$330.08**.
Using these prices, here's how you can calculate the value of your investment:
1. Determine the number of shares you could buy on 1/1/2018:
$$
\\text{Number of shares} = \\frac{\\text{Investment amount}}{\\text{Stock price purchase date}} = \\frac{1000}{85.95}
$$
2. Calculate the total value when selling the shares on 12/1/2021:
$$
\\text{Total value} = \\text{Number of shares} \\times \\text{Stock price on sale date}
$$
Let's do the math:
1. Number of shares you could buy on 1/1/2018:
$$
\\text{Number of shares} = \\frac{1000}{85.95} \\approx 11.63\\text{ shares}
$$
2. Total value when selling the shares on 12/1/2021:
$$
\\text{Total value} = 11.63 \\times 330.08 \\approx \\$3839.63
$$
So, if you invested $1000 in Microsoft on January 1, 2018, and sold the shares on December 1, 2021, your investment would be worth approximately **$3839.63**. Please note that this calculation does not account for dividends, taxes, or transaction fees, which could affect the final amount. If you need a more precise calculation including these factors, I recommend consulting a financial advisor or using a detailed investment calculator.
`,
type: 'message'
});

await pageConditions.numActivitiesShown(1);

await host.snapshot('local');
});
</script>
</body>
</html>
Binary file added __tests__/html2/markdown/math.html.snap-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions __tests__/html2/markdown/math2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!doctype html>
<html lang="en-US">
<head>
<link href="/assets/index.css" rel="stylesheet" type="text/css" />
<script crossorigin="anonymous" src="/test-harness.js"></script>
<script crossorigin="anonymous" src="/test-page-object.js"></script>
<script crossorigin="anonymous" src="/__dist__/webchat-es5.js"></script>
</head>

<body>
<main id="webchat"></main>
<script>
run(async function () {
await host.windowSize(640, 720, document.getElementById('webchat'));

const {
WebChat: { renderWebChat }
} = window; // Imports in UMD fashion.

const { directLine, store } = testHelpers.createDirectLineEmulator();

renderWebChat({ directLine, store }, document.getElementById('webchat'));

await pageConditions.uiConnected();

await directLine.emulateIncomingActivity({
text: `I've graphed the parametric equations you provided. Here's the result:
$$
x = \\sin(t)(e^{\\cos(t)}-2\\cos(4t)-\\sin^{5}(\\frac{t}{12}))
$$
$$
y = \\cos(t)(e^{\\cos(t)}-2\\cos(4t)-\\sin^{5}(\\frac{t}{12}))
$$
The graph is a representation of these equations plotted over a range of ( t ) values from 0 to ( 2\\pi ).`,
type: 'message'
});

await pageConditions.numActivitiesShown(1);

await host.snapshot('local');
});
</script>
</body>
</html>
Binary file added __tests__/html2/markdown/math2.html.snap-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions jest.legacy.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const TRANSFORM_IGNORE_PACKAGES = [
'micromark-extension-gfm-table',
'micromark-extension-gfm-tagfilter',
'micromark-extension-gfm-task-list-item',
'micromark-extension-math',
'micromark-factory-destination',
'micromark-factory-label',
'micromark-factory-space',
Expand Down
51 changes: 51 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/bundle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@
"memoize-one": "6.0.0",
"micromark": "^4.0.0",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-math": "^3.1.0",
"microsoft-cognitiveservices-speech-sdk": "1.17.0",
"prop-types": "15.8.1",
"punycode": "2.3.1",
Expand Down
44 changes: 40 additions & 4 deletions packages/bundle/src/markdown/renderMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import {
} from 'botframework-webchat-component/internal';
import { micromark } from 'micromark';
import { gfm, gfmHtml } from 'micromark-extension-gfm';
import { pre as respectCRLFPre } from './private/respectCRLF';
import { math, mathHtml } from 'micromark-extension-math';
import betterLinkDocumentMod, { BetterLinkDocumentModDecoration } from './private/betterLinkDocumentMod';
import iterateLinkDefinitions from './private/iterateLinkDefinitions';
import { pre as respectCRLFPre } from './private/respectCRLF';

const SANITIZE_HTML_OPTIONS = Object.freeze({
allowedAttributes: {
Expand Down Expand Up @@ -56,7 +57,38 @@ const SANITIZE_HTML_OPTIONS = Object.freeze({
'th',
'thead',
'tr',
'ul'
'ul',

// Followings are for MathML elements, from https://developer.mozilla.org/en-US/docs/Web/MathML.
'annotation-xml',
'annotation',
'math',
'merror',
'mfrac',
'mi',
'mmultiscripts',
'mn',
'mo',
'mover',
'mpadded',
'mphantom',
'mprescripts',
'mroot',
'mrow',
'ms',
'mspace',
'msqrt',
'mstyle',
'msub',
'msubsup',
'msup',
'mtable',
'mtd',
'mtext',
'mtr',
'munder',
'munderover',
'semantics'
],
// Bug of https://github.com/apostrophecms/sanitize-html/issues/633.
// They should not remove `alt=""` even though it is empty.
Expand Down Expand Up @@ -145,8 +177,12 @@ export default function render(
// We need to handle links like cite:1 or other URL handlers.
// And we will remove dangerous protocol during sanitization.
allowDangerousProtocol: true,
extensions: [gfm()],
htmlExtensions: [gfmHtml()]
extensions: [
gfm(),
// Disabling single dollar inline math block to prevent easy collision.
math({ singleDollarTextMath: false })
],
htmlExtensions: [gfmHtml(), mathHtml({ output: 'mathml' })]
});

// TODO: [P1] In some future, we should apply "better link" and "sanitization" outside of the Markdown engine.
Expand Down
6 changes: 6 additions & 0 deletions packages/component/src/Styles/StyleSet/RenderMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ export default function createMarkdownStyle() {

'& .webchat__render-markdown__pure-identifier::before': {
content: "'['"
},

'& math': {
alignItems: 'center',
display: 'flex',
flexDirection: 'column'
}
}
};
Expand Down

0 comments on commit 51385f7

Please sign in to comment.