Skip to content

Commit 22f13d5

Browse files
committed
Migrate content from monorepo
1 parent 672ae78 commit 22f13d5

19 files changed

+5982
-0
lines changed

Diff for: .gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,6 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
# Remove built assets
107+
lib/

Diff for: README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# @nteract/actions
2+
3+
This package contains two main components, `<MathJax.Context>` and `<MathJax.Node>`. The `<MathJax.Context>` component loads MathJax and makes it available to children elements via the React Context API. `<MathJax.Node>` takes raw text for rendering and uses MathJax to render formatted math.
4+
5+
## Installation
6+
7+
```
8+
$ yarn add @nteract/mathjax
9+
```
10+
11+
```
12+
$ npm install --save @nteract/mathjax
13+
```
14+
15+
## Usage
16+
17+
The Redux reducer below shows how we can leverage the actions and action types in this package to create a reducer for managing the status of a save event.
18+
19+
```javascript
20+
import MathJax from "@nteract/mathjax";
21+
22+
export default text => {
23+
return (
24+
<MathJax.Context>
25+
<MathJax.Node>{`x^2 + y^2 = z^2`}</MathJax.Node>
26+
<MathJax.Node>{text}</MathJax.Node>
27+
</MathJax.Context>
28+
);
29+
};
30+
```
31+
32+
## Documentation
33+
34+
You can view the reference documentation for `@nteract/mathjax` in the the [examples documentation](./examples.md).
35+
36+
## Support
37+
38+
If you experience an issue while using this package or have a feature request, please file an issue on the [issue board](https://github.com/nteract/mathjax/issues/new/choose).
39+
40+
## License
41+
42+
[BSD-3-Clause](https://choosealicense.com/licenses/bsd-3-clause/)

Diff for: __tests__/__snapshots__/index.spec.tsx.snap

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`MathJax Node can be renderered without provider 1`] = `
4+
<MathJaxNode
5+
inline={false}
6+
onRender={null}
7+
>
8+
<Provider
9+
delay={0}
10+
didFinishTypeset={null}
11+
input="tex"
12+
loading={null}
13+
noGate={false}
14+
onError={[Function]}
15+
onLoad={null}
16+
options={Object {}}
17+
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"
18+
>
19+
<MathJaxNode
20+
inline={false}
21+
onRender={null}
22+
/>
23+
</Provider>
24+
</MathJaxNode>
25+
`;
26+
27+
exports[`MathJax Nodes use existing provider 1`] = `
28+
<Provider
29+
delay={0}
30+
didFinishTypeset={null}
31+
input="tex"
32+
loading={null}
33+
noGate={false}
34+
onError={[Function]}
35+
onLoad={null}
36+
options={Object {}}
37+
src="script-src"
38+
>
39+
<MathJaxNode
40+
inline={false}
41+
onRender={null}
42+
/>
43+
<MathJaxNode
44+
inline={false}
45+
onRender={null}
46+
/>
47+
</Provider>
48+
`;
49+
50+
exports[`MathJax Text node renders LaTeX text 1`] = `
51+
<MathJaxText
52+
onRender={null}
53+
>
54+
<Provider
55+
delay={0}
56+
didFinishTypeset={null}
57+
input="tex"
58+
loading={null}
59+
noGate={false}
60+
onError={[Function]}
61+
onLoad={null}
62+
options={Object {}}
63+
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"
64+
>
65+
<MathJaxText
66+
onRender={null}
67+
/>
68+
</Provider>
69+
</MathJaxText>
70+
`;

Diff for: __tests__/index.spec.tsx

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { mount } from "enzyme";
2+
import toJson from "enzyme-to-json";
3+
import * as React from "react";
4+
5+
jest.mock("load-script");
6+
import loadScript from "load-script";
7+
import { Node, Provider, Text } from "../src";
8+
9+
const mathJaxUrl =
10+
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML";
11+
12+
describe("MathJax", () => {
13+
test("Node can be renderered without provider", () => {
14+
const wrapper = mount(<Node>x^2 + y = 3</Node>);
15+
expect(loadScript).toHaveBeenLastCalledWith(
16+
mathJaxUrl,
17+
expect.any(Function)
18+
);
19+
expect(toJson(wrapper)).toMatchSnapshot();
20+
});
21+
22+
test("Nodes use existing provider", () => {
23+
const wrapper = mount(
24+
<Provider src="script-src">
25+
<Node>x^2 + y = 3</Node>
26+
<Node>x^3 + y = 2</Node>
27+
</Provider>
28+
);
29+
expect(loadScript).toHaveBeenLastCalledWith(
30+
"script-src",
31+
expect.any(Function)
32+
);
33+
expect(toJson(wrapper)).toMatchSnapshot();
34+
});
35+
36+
test("Text node renders LaTeX text", () => {
37+
const wrapper = mount(<Text>This is a LaTeX equation $x^2 + y = 3$</Text>);
38+
expect(loadScript).toHaveBeenLastCalledWith(
39+
mathJaxUrl,
40+
expect.any(Function)
41+
);
42+
expect(toJson(wrapper)).toMatchSnapshot();
43+
});
44+
});

Diff for: __tests__/node.spec.tsx

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { mount } from "enzyme";
2+
import React from "react";
3+
4+
import { MathJaxNode_ } from "../src/node";
5+
6+
jest.useFakeTimers();
7+
8+
const MathJaxContextMock = {
9+
Hub: {
10+
Register: {
11+
StartupHook: (str: string, cb: () => void) => {},
12+
MessageHook: (str: string, cb: (msg: string) => void) => {}
13+
},
14+
processSectionDelay: 20,
15+
getJaxFor: (node: HTMLElement) => ({ Remove: jest.fn() }),
16+
Config: (options: object) => {},
17+
Queue: (elements: any[], onRender?: () => void) => {}
18+
}
19+
};
20+
21+
describe("MathJaxNode_", () => {
22+
it("typesets when mounted", () => {
23+
const typeset = jest.spyOn(MathJaxNode_.prototype, "typeset");
24+
const component = mount(
25+
<MathJaxNode_ inline MathJax={MathJaxContextMock} input={"tex"}>
26+
$x^2 + y = 3$
27+
</MathJaxNode_>
28+
);
29+
jest.runAllTimers();
30+
component.update();
31+
32+
expect(typeset).toBeCalled();
33+
});
34+
it("clears typesetting when unmounted", () => {
35+
const clear = jest.spyOn(MathJaxNode_.prototype, "clear");
36+
const component = mount(
37+
<MathJaxNode_ inline MathJax={MathJaxContextMock} input={"tex"}>
38+
$x^2 + y = 3$
39+
</MathJaxNode_>
40+
);
41+
jest.runAllTimers();
42+
component.update();
43+
component.unmount();
44+
45+
expect(clear).toBeCalled();
46+
});
47+
it("typesets with force update when props change", () => {
48+
const typeset = jest.spyOn(MathJaxNode_.prototype, "typeset");
49+
const component = mount(
50+
<MathJaxNode_ inline MathJax={MathJaxContextMock} input="tex">
51+
$x^2 + y = 3$
52+
</MathJaxNode_>
53+
);
54+
jest.runAllTimers();
55+
component.setProps({ inline: false });
56+
57+
expect(typeset).toBeCalledWith(true);
58+
});
59+
});

Diff for: __tests__/provider.spec.tsx

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { shallow } from "enzyme";
2+
import React from "react";
3+
4+
import MathJaxContext from "../src/context";
5+
import MathJaxProvider from "../src/provider";
6+
7+
describe("MathJaxProvider", () => {
8+
it("renders without crashing", () => {
9+
const component = shallow(<MathJaxProvider>$x^2 + y = 3$</MathJaxProvider>);
10+
expect(component.find(MathJaxContext.Provider)).toHaveLength(1);
11+
});
12+
});

Diff for: __tests__/text.spec.tsx

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { mount } from "enzyme";
2+
import React from "react";
3+
4+
import { MathJaxText_ } from "../src/text";
5+
6+
const MathJaxContextMock = {
7+
Hub: {
8+
Register: {
9+
StartupHook: (str: string, cb: () => void) => {},
10+
MessageHook: (str: string, cb: (msg: string) => void) => {}
11+
},
12+
processSectionDelay: 20,
13+
getJaxFor: (node: HTMLElement) => ({ Remove: jest.fn() }),
14+
Config: (options: object) => {},
15+
Queue: (elements: any[], onRender?: () => void) => {}
16+
}
17+
};
18+
19+
describe("MathJaxText_", () => {
20+
it("typesets when mounted", () => {
21+
const typeset = jest.spyOn(MathJaxText_.prototype, "typeset");
22+
const component = mount(
23+
<MathJaxText_ MathJax={MathJaxContextMock} input={"tex"}>
24+
$x^2 + y = 3$
25+
</MathJaxText_>
26+
);
27+
28+
expect(typeset).toBeCalled();
29+
});
30+
it("typesets on component update", () => {
31+
const typeset = jest.spyOn(MathJaxText_.prototype, "typeset");
32+
const component = mount(
33+
<MathJaxText_ MathJax={MathJaxContextMock} input={"tex"}>
34+
$x^2 + y = 3$
35+
</MathJaxText_>
36+
);
37+
jest.runAllTimers();
38+
component.update();
39+
40+
expect(typeset).toBeCalledTimes(2);
41+
});
42+
});

Diff for: examples.md

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
The MathJax component provides a way to both load MathJax on the page and render MathJax Nodes. Many people love ❤️ beautifully typeset mathematics, and these components are the way to provide it.
2+
3+
```jsx
4+
const { Provider, Node } = require("@nteract/mathjax");
5+
6+
const tex = String.raw`f(x) = \int_{-\infty}^\infty
7+
\hat f(\xi)\,e^{2 \pi i \xi x}
8+
\,d\xi`;
9+
10+
<Provider>
11+
<p>
12+
This is an inline math formula: <Node inline>a = b</Node>
13+
<span> and a block one:</span>
14+
<Node>{tex}</Node>
15+
</p>
16+
</Provider>;
17+
```
18+
19+
The components are written in a React 16+ way to both load mathjax through a `<Provider />` and render individual MathJax nodes with `<Node />`. React does the heavy lifting of knowing what changed and the `<Node>` component triggers having MathJax do what it's good at — _typesetting mathematics_!
20+
21+
This semi-contrived example shows
22+
23+
```jsx
24+
const { Provider, Node } = require("@nteract/mathjax");
25+
26+
const verbs = ["do", "can", "should", "will"];
27+
28+
class CleanUpdates extends React.Component {
29+
constructor(props) {
30+
super(props);
31+
this.state = {
32+
exponent: 1,
33+
verb: "can"
34+
};
35+
}
36+
37+
componentDidMount() {
38+
this.intervals = [
39+
setInterval(() => {
40+
this.setState(state => ({
41+
exponent: (state.exponent + 1) % 10
42+
}));
43+
}, 3001), // Prime
44+
45+
setInterval(() => {
46+
this.setState(state => ({
47+
verb: verbs[Math.floor(Math.random() * verbs.length)]
48+
}));
49+
}, 557) // Also prime
50+
];
51+
}
52+
53+
componentWillUnmount() {
54+
this.intervals.map(id => clearInterval(id));
55+
}
56+
57+
render() {
58+
return (
59+
<Provider options={{ messageStyle: "none" }}>
60+
<p>
61+
We{" "}
62+
<span
63+
style={{
64+
backgroundColor: "#7ee77e",
65+
padding: "5px",
66+
margin: "5px",
67+
width: "42px",
68+
display: "inline-block",
69+
textAlign: "center"
70+
}}
71+
>
72+
{this.state.verb}
73+
</span>{" "}
74+
update
75+
<Node inline>{"n^" + this.state.exponent}</Node> pieces of a paragraph
76+
without triggering a MathJax re-render.
77+
</p>
78+
</Provider>
79+
);
80+
}
81+
}
82+
83+
<CleanUpdates />;
84+
```
85+
86+
If you use `<Node />` with no provider, a `<Provider />` is created for you automatically.
87+
88+
```jsx
89+
const { Node } = require("@nteract/mathjax");
90+
91+
<Node>a = b</Node>;
92+
```

Diff for: jest.config.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
timers: "fake",
3+
transform: {
4+
"^.+\\.(ts|tsx)$": "ts-jest"
5+
},
6+
setupFilesAfterEnv: ["./test-setup.js"]
7+
};

0 commit comments

Comments
 (0)