rapier-math 1.0.2 → 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/README.md +23 -93
- package/dist/classic.d.ts +4 -0
- package/dist/delimiters.d.ts +8 -0
- package/dist/delimiters.mjs +39 -0
- package/dist/index.d.ts +43 -0
- package/{index.mjs → dist/index.mjs} +43 -15
- package/dist/integration.d.ts +9 -0
- package/dist/integration.mjs +28 -0
- package/dist/markdown-it.d.ts +6 -0
- package/dist/markdown-it.mjs +45 -0
- package/dist/markdown-rules.mjs +65 -0
- package/{rapier-math-1.0.2.js → dist/rapier-math.js} +43 -15
- package/dist/rehype.d.ts +6 -0
- package/dist/rehype.mjs +37 -0
- package/dist/stream.d.ts +14 -0
- package/dist/stream.mjs +46 -0
- package/docs/api.md +210 -0
- package/{math-components.json → docs/math-components.json} +7 -7
- package/docs/math-resources.json +290 -0
- package/examples/README.md +25 -0
- package/examples/browser.html +10 -0
- package/examples/browser.mjs +24 -0
- package/examples/formula.mjs +12 -0
- package/examples/markdown.mjs +9 -0
- package/examples/react.tsx +19 -0
- package/examples/stream.mjs +19 -0
- package/examples/unified.mjs +26 -0
- package/examples/worker.mjs +7 -0
- package/package.json +68 -19
- package/src/math/api.js +35 -13
- package/src/math/browser.js +7 -1
- package/src/math/layout.js +1 -1
- package/src/math/package-build.mjs +0 -13
- package/src/math/package-layout.mjs +17 -0
- package/src/math/package-readme.mjs +45 -0
- package/src/tools/build-math.mjs +48 -13
- package/tests/adoption.mjs +149 -0
- package/{check.mjs → tests/check.mjs} +29 -8
- package/tests/verify.mjs +46 -0
- package/LICENSE-MIT +0 -21
- package/math-LICENSE.txt +0 -21
- package/math-font-LICENSE.txt +0 -457
- package/src/math/package-verify.mjs +0 -40
- package/src/package.json +0 -9
- package/src/shell/math-resources.json +0 -105
- package/verify.mjs +0 -40
- /package/{src/math/FONT-SOURCE.md → docs/font-source.md} +0 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle": "rapier-math-1.1.1.js",
|
|
3
|
+
"packageBundle": "dist/rapier-math.js",
|
|
4
|
+
"version": "1.1.1",
|
|
5
|
+
"license": "MIT AND LicenseRef-GUST-Font-License",
|
|
6
|
+
"bytes": 714051,
|
|
7
|
+
"gzipBytes": 442525,
|
|
8
|
+
"sha256": "050f4ebfb7c78beaefb01c9d6aa62192fd03757fc677134850bdb1f090033b81",
|
|
9
|
+
"sha384": "FnVbul5Kp18nd2S1SdMQlMPJtulZiY5ZqrRtJ8APYoP6reF9w0JRjF/qrmH9l9s0",
|
|
10
|
+
"sources": [
|
|
11
|
+
{
|
|
12
|
+
"file": "math/font.js",
|
|
13
|
+
"packageFile": "src/math/font.js",
|
|
14
|
+
"bytes": 558719,
|
|
15
|
+
"sha256": "1263135501cb049efb087975db43c0fa6d131e5deee4282d982995d4ab0884c4"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"file": "math/symbols.js",
|
|
19
|
+
"packageFile": "src/math/symbols.js",
|
|
20
|
+
"bytes": 8415,
|
|
21
|
+
"sha256": "80f485e8023afe3783d30c4616709e0a3b0ed0ba8a238bd818085cdd107f03ad"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"file": "math/parser.js",
|
|
25
|
+
"packageFile": "src/math/parser.js",
|
|
26
|
+
"bytes": 69355,
|
|
27
|
+
"sha256": "067594e1b1391a7c29b71ff51e0e812f16785e14a863dbc04069627760435633"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"file": "math/layout.js",
|
|
31
|
+
"packageFile": "src/math/layout.js",
|
|
32
|
+
"bytes": 37632,
|
|
33
|
+
"sha256": "84f0abeb24907f370754e30e5cf0576cb2346b941815494c9958892f3d1cc939"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"file": "math/fallbacks.js",
|
|
37
|
+
"packageFile": "src/math/fallbacks.js",
|
|
38
|
+
"bytes": 7953,
|
|
39
|
+
"sha256": "400c5771756d5a4d4cf431d471b33c280791ce4aa276a0fd2615d91ee88ae8ce"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"file": "math/responsive.js",
|
|
43
|
+
"packageFile": "src/math/responsive.js",
|
|
44
|
+
"bytes": 13566,
|
|
45
|
+
"sha256": "387e2952317ba8124bd7f56a71feb9555f3cb6081de687d79eb4c9e6cab4b6ed"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"file": "math/browser.js",
|
|
49
|
+
"packageFile": "src/math/browser.js",
|
|
50
|
+
"bytes": 10048,
|
|
51
|
+
"sha256": "5a9b1ee1b8c55a5560058b0fcfb5d6623f7de74e49bcb4281acdf7c97b235101"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"file": "math/api.js",
|
|
55
|
+
"packageFile": "src/math/api.js",
|
|
56
|
+
"bytes": 7245,
|
|
57
|
+
"sha256": "0ad779d91a760c5dd908caf8f037df8b6db82d69cefab42bd8b5493d68f30b4e"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"recipe": [
|
|
61
|
+
{
|
|
62
|
+
"file": "math/build-font.py",
|
|
63
|
+
"packageFile": "src/math/build-font.py",
|
|
64
|
+
"bytes": 33369,
|
|
65
|
+
"sha256": "d54dba7b83d945da4bdeeac6a262c45d0b8f531c0801114451ac3f3d8dab9d35"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"file": "math/FONT-SOURCE.md",
|
|
69
|
+
"packageFile": "docs/font-source.md",
|
|
70
|
+
"bytes": 10357,
|
|
71
|
+
"sha256": "84ab319b1f9342fa08b421231965dd685063d8fd6bb8a071e1f1c186848dcdd9"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"file": "math/FONT-LICENSE.txt",
|
|
75
|
+
"packageFile": "src/math/FONT-LICENSE.txt",
|
|
76
|
+
"bytes": 21246,
|
|
77
|
+
"sha256": "91ded9a2a371cbeff028bfaf3bd3e97fddfb68af6f186aa261bfaff35baf800c"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"file": "math/package-verify.mjs",
|
|
81
|
+
"packageFile": "tests/verify.mjs",
|
|
82
|
+
"bytes": 2972,
|
|
83
|
+
"sha256": "bb28e7ea37021ea191bd858a18beb97bb8ca14b52015dfe1e49d7d07dea60b48"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"file": "tools/build-math.mjs",
|
|
87
|
+
"packageFile": "src/tools/build-math.mjs",
|
|
88
|
+
"bytes": 8668,
|
|
89
|
+
"sha256": "06c6d4f0d56de87b8869bf04433b7ff8cea6f7f19e4dc7ea6a2e21279f9cb50e"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"file": "math/LICENSE-MIT",
|
|
93
|
+
"packageFile": "src/math/LICENSE-MIT",
|
|
94
|
+
"bytes": 1071,
|
|
95
|
+
"sha256": "a3bc5d619ab9159f4eef2924e48dfb935556f4bc163f5ea61610b66a5915de70"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"file": "math/adoption-verify.mjs",
|
|
99
|
+
"packageFile": "tests/adoption.mjs",
|
|
100
|
+
"bytes": 8254,
|
|
101
|
+
"sha256": "15179557c7d1bdd76ae7a06956f8be65b375f7f187940e5227baa0d4930b3b63"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"file": "math/package-build.mjs",
|
|
105
|
+
"packageFile": "src/math/package-build.mjs",
|
|
106
|
+
"bytes": 989,
|
|
107
|
+
"sha256": "9cbe11960f0190375c3d086e731078aab5acaaf8a5a77f83f3395ff3ba0291de"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"file": "math/package-layout.mjs",
|
|
111
|
+
"packageFile": "src/math/package-layout.mjs",
|
|
112
|
+
"bytes": 681,
|
|
113
|
+
"sha256": "a8f5bfe84dde4745c7c6fbfffa7b80766d39ec1adf727c2de59be9596711b320"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"file": "math/package-check.mjs",
|
|
117
|
+
"packageFile": "tests/check.mjs",
|
|
118
|
+
"bytes": 7455,
|
|
119
|
+
"sha256": "4df4f81251c66473a2ea491072364c68761da7313fff36a19e82e3313220ce26"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"file": "math/package-readme.mjs",
|
|
123
|
+
"packageFile": "src/math/package-readme.mjs",
|
|
124
|
+
"bytes": 1853,
|
|
125
|
+
"sha256": "9408728370c81d463794ef67380c587748ed1b1633b56b1d1a2b33d9a95b3986"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"file": "math/README.md",
|
|
129
|
+
"packageFile": "docs/api.md",
|
|
130
|
+
"bytes": 14103,
|
|
131
|
+
"sha256": "83368017d04a50a3d13e6e2e070322a5eef4bf8f54f521bd7ff061e186afc3f5"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"components": [
|
|
135
|
+
{
|
|
136
|
+
"name": "Latin Modern Math",
|
|
137
|
+
"version": "1.959",
|
|
138
|
+
"license": "LicenseRef-GUST-Font-License",
|
|
139
|
+
"source": "https://mirror.apps.cam.ac.uk/pub/tex-archive/fonts/lm-math/opentype/latinmodern-math.otf",
|
|
140
|
+
"sha256": "6075562b771f8b82f0c179e363389684f2dd09de30038269e2628e504bd7be0f"
|
|
141
|
+
}
|
|
142
|
+
],
|
|
143
|
+
"font": {
|
|
144
|
+
"name": "Latin Modern Math",
|
|
145
|
+
"version": "1.959",
|
|
146
|
+
"license": "LicenseRef-GUST-Font-License",
|
|
147
|
+
"licenseName": "GUST Font License",
|
|
148
|
+
"source": "https://mirror.apps.cam.ac.uk/pub/tex-archive/fonts/lm-math/opentype/latinmodern-math.otf",
|
|
149
|
+
"sourceSha256": "6075562b771f8b82f0c179e363389684f2dd09de30038269e2628e504bd7be0f",
|
|
150
|
+
"copyright": "Copyright 2012--2014 for Latin Modern Math OTF by B. Jackowski, P. Strzelczyk and P. Pianowski (on behalf of TeX users groups). This work is released under the GUST Font License -- see http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt for details.",
|
|
151
|
+
"licenseSource": "https://mirror.apps.cam.ac.uk/pub/tex-archive/fonts/lm-math/doc/GUST-FONT-LICENSE.txt",
|
|
152
|
+
"licenseFile": "math/FONT-LICENSE.txt",
|
|
153
|
+
"licenseSha256": "91ded9a2a371cbeff028bfaf3bd3e97fddfb68af6f186aa261bfaff35baf800c",
|
|
154
|
+
"licenseBytes": 21246
|
|
155
|
+
},
|
|
156
|
+
"adoption": [
|
|
157
|
+
{
|
|
158
|
+
"file": "math/delimiters.mjs",
|
|
159
|
+
"packageFile": "dist/delimiters.mjs",
|
|
160
|
+
"bytes": 1945,
|
|
161
|
+
"sha256": "2847d23ba78534b32348d5e642ded601e4f6fd9c41e10d80c46955d440d24eba"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"file": "math/markdown-rules.mjs",
|
|
165
|
+
"packageFile": "dist/markdown-rules.mjs",
|
|
166
|
+
"bytes": 3255,
|
|
167
|
+
"sha256": "3c2c1660f669eac88fbee4259e83f9227ed651e2e4bb228a861c5a1d8518f6a7"
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"file": "math/integration.mjs",
|
|
171
|
+
"packageFile": "dist/integration.mjs",
|
|
172
|
+
"bytes": 1493,
|
|
173
|
+
"sha256": "5bd61aa59e78cbab37219b9a569f3b5ad9c5a7723800abc7f3fe7af6b82ae7a6"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"file": "math/markdown-it.mjs",
|
|
177
|
+
"packageFile": "dist/markdown-it.mjs",
|
|
178
|
+
"bytes": 2113,
|
|
179
|
+
"sha256": "d57abc5dc3e5a31b6be4507b2f5c57df8431763b8d88feaadbf242cb09af6c9d"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"file": "math/rehype.mjs",
|
|
183
|
+
"packageFile": "dist/rehype.mjs",
|
|
184
|
+
"bytes": 2017,
|
|
185
|
+
"sha256": "7cc9c9d2e7c9b9667368cfc1a5a4f5f86d218b7c8a1acb8d2e12334d41e83bc8"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"file": "math/stream.mjs",
|
|
189
|
+
"packageFile": "dist/stream.mjs",
|
|
190
|
+
"bytes": 2530,
|
|
191
|
+
"sha256": "2b26a895e531906be931af6f9f3764297d1ff98bf56875e9df457f82938fc03d"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"file": "math/index.d.ts",
|
|
195
|
+
"packageFile": "dist/index.d.ts",
|
|
196
|
+
"bytes": 1698,
|
|
197
|
+
"sha256": "bc14a284cd5caffdf5bfe6825c49c360d313e693bbc0280aa924fd9fc594beb3"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"file": "math/classic.d.ts",
|
|
201
|
+
"packageFile": "dist/classic.d.ts",
|
|
202
|
+
"bytes": 123,
|
|
203
|
+
"sha256": "dfc82014f54ed7364171cb73cc8bc118aba4a5929349f762da82988977f1593d"
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"file": "math/delimiters.d.ts",
|
|
207
|
+
"packageFile": "dist/delimiters.d.ts",
|
|
208
|
+
"bytes": 479,
|
|
209
|
+
"sha256": "db74cfb4fdd6d87e7f47a5de8ee3a4b78f409a4fe3cd2edeaa8e77660a489617"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"file": "math/integration.d.ts",
|
|
213
|
+
"packageFile": "dist/integration.d.ts",
|
|
214
|
+
"bytes": 370,
|
|
215
|
+
"sha256": "4b3c53b01b34de3b328ef609e65aa3aa530fabc3522238bde335cb8c839cdda3"
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"file": "math/markdown-it.d.ts",
|
|
219
|
+
"packageFile": "dist/markdown-it.d.ts",
|
|
220
|
+
"bytes": 383,
|
|
221
|
+
"sha256": "bafce277328ba397bddbbb5101cc2545ba8b8c15830b47f2dc1f05af85de4b1d"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"file": "math/rehype.d.ts",
|
|
225
|
+
"packageFile": "dist/rehype.d.ts",
|
|
226
|
+
"bytes": 340,
|
|
227
|
+
"sha256": "8f6b230284e64fb483d1ed2c6ed9420958cf1d7e609f71aee62322cabe56339b"
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"file": "math/stream.d.ts",
|
|
231
|
+
"packageFile": "dist/stream.d.ts",
|
|
232
|
+
"bytes": 630,
|
|
233
|
+
"sha256": "1b12bc176fdd243db75d247ff4dbb9b4787945167a033154a0d222ad68da4ff0"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"file": "math/examples/formula.mjs",
|
|
237
|
+
"packageFile": "examples/formula.mjs",
|
|
238
|
+
"bytes": 619,
|
|
239
|
+
"sha256": "43e3708d50737d1eac74f5132146838b58b733c5b0315b50d6eecd594ecb9e7d"
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"file": "math/examples/markdown.mjs",
|
|
243
|
+
"packageFile": "examples/markdown.mjs",
|
|
244
|
+
"bytes": 375,
|
|
245
|
+
"sha256": "6dc4789538861d478f9afba403574b3f88928db4e9d4e4def88db87af8561641"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"file": "math/examples/stream.mjs",
|
|
249
|
+
"packageFile": "examples/stream.mjs",
|
|
250
|
+
"bytes": 841,
|
|
251
|
+
"sha256": "4b1feb25d38024a6f8531bb3353d0eea993628dcd1f97e736d42c9e076ec655b"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"file": "math/examples/unified.mjs",
|
|
255
|
+
"packageFile": "examples/unified.mjs",
|
|
256
|
+
"bytes": 1103,
|
|
257
|
+
"sha256": "9002f3f1f7cbbec2f8f9a4b3cdbde2f418fece7b8395e942441448b7f785ee9b"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"file": "math/examples/browser.html",
|
|
261
|
+
"packageFile": "examples/browser.html",
|
|
262
|
+
"bytes": 566,
|
|
263
|
+
"sha256": "c671541b4a3f1a4cb9e2b2ef2945778db825590f08a11ad48b768d132b5df96f"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"file": "math/examples/browser.mjs",
|
|
267
|
+
"packageFile": "examples/browser.mjs",
|
|
268
|
+
"bytes": 945,
|
|
269
|
+
"sha256": "569e66078bce60debc6aeb4d70efa3fdc67eabdf9b349822f1a7117a28311235"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"file": "math/examples/react.tsx",
|
|
273
|
+
"packageFile": "examples/react.tsx",
|
|
274
|
+
"bytes": 899,
|
|
275
|
+
"sha256": "bfcbeb5219ce776a9c33f841c0aad222be9b6ceddffe0eb89f344bed170e0765"
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
"file": "math/examples/worker.mjs",
|
|
279
|
+
"packageFile": "examples/worker.mjs",
|
|
280
|
+
"bytes": 370,
|
|
281
|
+
"sha256": "1e9de25f8b636d14d065b0d2b2febbeeed9600fc595a12c09f94ba58f3791de6"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"file": "math/examples/README.md",
|
|
285
|
+
"packageFile": "examples/README.md",
|
|
286
|
+
"bytes": 1858,
|
|
287
|
+
"sha256": "c462b51cae9435336debca87e7e6407400ff06df3126ac8aeb4becc091cd31bf"
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Run the installed examples
|
|
2
|
+
|
|
3
|
+
From a consumer directory, install `rapier-math`, then run
|
|
4
|
+
`node node_modules/rapier-math/examples/formula.mjs`.
|
|
5
|
+
|
|
6
|
+
For Markdown and streaming, also install `markdown-it` and run `markdown.mjs` or `stream.mjs`.
|
|
7
|
+
For unified, install `unified remark-parse remark-math remark-rehype rehype-sanitize rehype-stringify hast-util-from-html`
|
|
8
|
+
and run `unified.mjs`. The remark example uses remark's syntax; it does not recognize backslash delimiters.
|
|
9
|
+
|
|
10
|
+
Serve the package directory over HTTP and open `examples/browser.html`. Its external module imports the
|
|
11
|
+
installed ESM renderer, fits the output and releases observation before replacement and on page exit.
|
|
12
|
+
Start `new Worker('./worker.mjs', {type: 'module'})` from this directory and post `{id, source}`.
|
|
13
|
+
Use an id owned by the current message and ignore stale replies. Workers render SVG; they do not call `observe`.
|
|
14
|
+
|
|
15
|
+
`react.tsx` is a small React 19/SSR component to copy into an existing TypeScript application. Install
|
|
16
|
+
`react react-dom` and the development types `@types/react @types/react-dom`. No framework is required by the core.
|
|
17
|
+
|
|
18
|
+
For streamed UTF-8, use `TextDecoderStream` or `decoder.decode(bytes, {stream: true})` and flush the decoder
|
|
19
|
+
at EOF. Feed decoded strings into one stream per message. Append incoming chunks to a text node for immediate
|
|
20
|
+
literal progress, and replace the whole preview when `write` returns a snapshot. Replace it with `finish()` at EOF.
|
|
21
|
+
Do not concatenate transport data into HTML. On cancellation call `abort`; on replacement cancel the old producer
|
|
22
|
+
before `reset`. A producer that still runs needs its own generation check before calling `write`.
|
|
23
|
+
|
|
24
|
+
The examples retain the original source as the editable/copyable authority. Markdown hosts can normalize
|
|
25
|
+
newlines or escapes in their syntax nodes; an HTML serialization is not an exact source archive.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<meta charset="utf-8">
|
|
3
|
+
<meta name="viewport" content="width=device-width">
|
|
4
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src-attr 'unsafe-inline'; style-src-elem 'none'; worker-src 'self'; connect-src 'none'; base-uri 'none'">
|
|
5
|
+
<title>Rapier Math example</title>
|
|
6
|
+
<label>TeX <textarea id="source">\frac{-b\pm\sqrt{b^2-4ac}}{2a}</textarea></label>
|
|
7
|
+
<button id="render" type="button">Render</button>
|
|
8
|
+
<main id="equation"></main>
|
|
9
|
+
<pre id="errors"></pre>
|
|
10
|
+
<script type="module" src="./browser.mjs"></script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import {render, observe} from '../dist/index.mjs';
|
|
3
|
+
const container = document.querySelector('#equation');
|
|
4
|
+
const source = document.querySelector('#source');
|
|
5
|
+
let stop = () => {};
|
|
6
|
+
function update() {
|
|
7
|
+
stop();
|
|
8
|
+
try {
|
|
9
|
+
const result = render(source.value, {displayMode: true});
|
|
10
|
+
document.querySelector('#errors').textContent = JSON.stringify(result.errors);
|
|
11
|
+
if (result.errors.length) container.replaceChildren(document.createTextNode(source.value));
|
|
12
|
+
else {
|
|
13
|
+
// Only this renderer's freshly returned SVG reaches the HTML sink.
|
|
14
|
+
container.innerHTML = result.svg;
|
|
15
|
+
stop = observe(container);
|
|
16
|
+
}
|
|
17
|
+
} catch (error) {
|
|
18
|
+
container.replaceChildren(document.createTextNode(source.value));
|
|
19
|
+
document.querySelector('#errors').textContent = error.message;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
document.querySelector('#render').addEventListener('click', update);
|
|
23
|
+
window.addEventListener('pagehide', () => stop());
|
|
24
|
+
update();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import {render, renderToString} from 'rapier-math';
|
|
3
|
+
|
|
4
|
+
// Works in Node/SSR: the result needs no browser JavaScript or remote font.
|
|
5
|
+
const source = String.raw`\frac{-b\pm\sqrt{b^2-4ac}}{2a}`;
|
|
6
|
+
const result = render(source, {displayMode: true});
|
|
7
|
+
if (result.errors.length) throw new Error(JSON.stringify(result.errors));
|
|
8
|
+
console.log(result.svg);
|
|
9
|
+
console.log(renderToString('E=mc^2'));
|
|
10
|
+
const failure = render(String.raw`\unsupported{x}`);
|
|
11
|
+
console.error({source: String.raw`\unsupported{x}`, errors: failure.errors});
|
|
12
|
+
// Retain the original source for editing/copying, even if admission throws.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import MarkdownIt from 'markdown-it';
|
|
3
|
+
import rapierMath from 'rapier-math/markdown-it';
|
|
4
|
+
|
|
5
|
+
export const md = new MarkdownIt({html: false}).use(rapierMath);
|
|
6
|
+
const source = 'It costs $5 and $10. Code: `$$x$$`. Math: \\(x^2\\).\n\n$$\\frac{1}{2}$$\n';
|
|
7
|
+
const env = {};
|
|
8
|
+
console.log(md.render(source, env));
|
|
9
|
+
console.error(env.rapierMathErrors || []);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import {useEffect, useMemo, useRef} from 'react';
|
|
3
|
+
import {render, observe} from 'rapier-math';
|
|
4
|
+
|
|
5
|
+
export function Equation({source, displayMode = false}: {source: string; displayMode?: boolean}) {
|
|
6
|
+
const ref = useRef<HTMLSpanElement>(null);
|
|
7
|
+
const result = useMemo(() => {
|
|
8
|
+
try { return render(source, {displayMode}); }
|
|
9
|
+
catch { return null; }
|
|
10
|
+
}, [source, displayMode]);
|
|
11
|
+
const svg = result && result.errors.length === 0 ? result.svg : null;
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (ref.current && svg) return observe(ref.current);
|
|
14
|
+
}, [svg]); // Cleanup runs before replacement setup and on unmount.
|
|
15
|
+
if (!svg) return <code>{source}</code>;
|
|
16
|
+
// The server and initial client render use identical source/options. Fit only
|
|
17
|
+
// after hydration; never pass authored HTML to dangerouslySetInnerHTML.
|
|
18
|
+
return <span ref={ref} dangerouslySetInnerHTML={{__html: svg}} />;
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import MarkdownIt from 'markdown-it';
|
|
3
|
+
import rapierMath from 'rapier-math/markdown-it';
|
|
4
|
+
import {createMarkdownStream} from 'rapier-math/stream';
|
|
5
|
+
|
|
6
|
+
const md = new MarkdownIt({html: false}).use(rapierMath);
|
|
7
|
+
const stream = createMarkdownStream(source => md.render(source, {}), {previewEvery: 16});
|
|
8
|
+
for (const chunk of ['The answer is \\(', '\\frac{1}', '{2}', '\\)', '. Code: `$$x$$`.']) {
|
|
9
|
+
const preview = stream.write(chunk);
|
|
10
|
+
if (preview) console.log({phase: 'preview', ...preview});
|
|
11
|
+
}
|
|
12
|
+
const final = stream.finish();
|
|
13
|
+
console.log({phase: 'complete', ...final});
|
|
14
|
+
if (final.html !== md.render(final.source, {})) throw new Error('Batch mismatch');
|
|
15
|
+
|
|
16
|
+
// One stream per message. On replacement: cancel its transport, reset, write.
|
|
17
|
+
stream.reset();
|
|
18
|
+
stream.write('Replacement \\(y\\).');
|
|
19
|
+
console.log(stream.finish());
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import {unified} from 'unified';
|
|
3
|
+
import remarkParse from 'remark-parse';
|
|
4
|
+
import remarkMath from 'remark-math';
|
|
5
|
+
import remarkRehype from 'remark-rehype';
|
|
6
|
+
import rehypeSanitize, {defaultSchema} from 'rehype-sanitize';
|
|
7
|
+
import rehypeRapierMath from 'rapier-math/rehype';
|
|
8
|
+
import rehypeStringify from 'rehype-stringify';
|
|
9
|
+
import {pathToFileURL} from 'node:url';
|
|
10
|
+
|
|
11
|
+
export const processor = unified().use(remarkParse)
|
|
12
|
+
.use(remarkMath, {singleDollarTextMath: false}).use(remarkRehype)
|
|
13
|
+
.use(rehypeSanitize, {
|
|
14
|
+
...defaultSchema,
|
|
15
|
+
attributes: {...defaultSchema.attributes, code: [
|
|
16
|
+
...(defaultSchema.attributes.code || []).filter(rule => !(Array.isArray(rule) && rule[0] === 'className')),
|
|
17
|
+
['className', 'language-math', 'math-inline', 'math-display'],
|
|
18
|
+
]},
|
|
19
|
+
})
|
|
20
|
+
.use(rehypeRapierMath).use(rehypeStringify);
|
|
21
|
+
|
|
22
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
23
|
+
const file = await processor.process('Price $5. Code `$$x$$`. Math $$x^2$$.\n\n$$\n\\frac{1}{2}\n$$');
|
|
24
|
+
console.log(String(file));
|
|
25
|
+
console.error(file.messages);
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
import {render} from '../dist/index.mjs';
|
|
3
|
+
self.onmessage = ({data: {id, source}}) => {
|
|
4
|
+
try { self.postMessage({id, source, result: render(source)}); }
|
|
5
|
+
catch (error) { self.postMessage({id, source, error: {code: error.code, message: error.message}}); }
|
|
6
|
+
};
|
|
7
|
+
// Keep a request id per message; install a reply only if it is still current.
|
package/package.json
CHANGED
|
@@ -1,29 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rapier-math",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Self-contained
|
|
3
|
+
"version": "1.1.1",
|
|
4
|
+
"description": "Self-contained offline LaTeX-to-SVG rendering with Latin Modern outlines, optional Markdown integrations and streaming helpers.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./index.mjs",
|
|
6
|
+
"main": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"sideEffects": [
|
|
9
|
+
"./dist/rapier-math.js"
|
|
10
|
+
],
|
|
7
11
|
"exports": {
|
|
8
|
-
".":
|
|
9
|
-
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"./delimiters": {
|
|
17
|
+
"types": "./dist/delimiters.d.ts",
|
|
18
|
+
"default": "./dist/delimiters.mjs"
|
|
19
|
+
},
|
|
20
|
+
"./markdown-it": {
|
|
21
|
+
"types": "./dist/markdown-it.d.ts",
|
|
22
|
+
"default": "./dist/markdown-it.mjs"
|
|
23
|
+
},
|
|
24
|
+
"./rehype": {
|
|
25
|
+
"types": "./dist/rehype.d.ts",
|
|
26
|
+
"default": "./dist/rehype.mjs"
|
|
27
|
+
},
|
|
28
|
+
"./stream": {
|
|
29
|
+
"types": "./dist/stream.d.ts",
|
|
30
|
+
"default": "./dist/stream.mjs"
|
|
31
|
+
},
|
|
32
|
+
"./classic": {
|
|
33
|
+
"types": "./dist/classic.d.ts",
|
|
34
|
+
"default": "./dist/rapier-math.js"
|
|
35
|
+
},
|
|
10
36
|
"./package.json": "./package.json"
|
|
11
37
|
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"markdown-it": "^14.1.0 || ^15.0.0",
|
|
40
|
+
"@types/markdown-it": "^14.1.0",
|
|
41
|
+
"hast-util-from-html": "^2.0.0",
|
|
42
|
+
"@types/hast": "^3.0.0",
|
|
43
|
+
"vfile": "^6.0.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependenciesMeta": {
|
|
46
|
+
"markdown-it": {
|
|
47
|
+
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"@types/markdown-it": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"hast-util-from-html": {
|
|
53
|
+
"optional": true
|
|
54
|
+
},
|
|
55
|
+
"@types/hast": {
|
|
56
|
+
"optional": true
|
|
57
|
+
},
|
|
58
|
+
"vfile": {
|
|
59
|
+
"optional": true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
12
62
|
"files": [
|
|
13
|
-
"
|
|
14
|
-
"
|
|
63
|
+
"dist",
|
|
64
|
+
"src",
|
|
65
|
+
"docs",
|
|
66
|
+
"examples",
|
|
67
|
+
"tests",
|
|
15
68
|
"LICENSE",
|
|
16
|
-
"
|
|
17
|
-
"math-LICENSE.txt",
|
|
18
|
-
"math-font-LICENSE.txt",
|
|
19
|
-
"math-components.json",
|
|
20
|
-
"README.md",
|
|
21
|
-
"verify.mjs",
|
|
22
|
-
"check.mjs",
|
|
23
|
-
"src/math",
|
|
24
|
-
"src/tools/build-math.mjs",
|
|
25
|
-
"src/shell/math-resources.json",
|
|
26
|
-
"src/package.json"
|
|
69
|
+
"README.md"
|
|
27
70
|
],
|
|
28
71
|
"license": "SEE LICENSE IN LICENSE",
|
|
29
72
|
"author": "Jack Skipworth",
|
|
@@ -41,6 +84,12 @@
|
|
|
41
84
|
"latex",
|
|
42
85
|
"svg",
|
|
43
86
|
"typesetting",
|
|
44
|
-
"latin-modern"
|
|
87
|
+
"latin-modern",
|
|
88
|
+
"markdown",
|
|
89
|
+
"markdown-it",
|
|
90
|
+
"rehype",
|
|
91
|
+
"unified",
|
|
92
|
+
"offline",
|
|
93
|
+
"math-rendering"
|
|
45
94
|
]
|
|
46
95
|
}
|
package/src/math/api.js
CHANGED
|
@@ -7,23 +7,27 @@ function mathSvg(box,source,error,utf16,options={}) {
|
|
|
7
7
|
const opacity=options.screen?.dark ? .94 : 1;
|
|
8
8
|
if (![width,height,depth,left,...viewBox].every(Number.isFinite)) throw new Error('Mathematical dimensions are not finite');
|
|
9
9
|
const escapedSource=mathEscape(source);
|
|
10
|
-
|
|
10
|
+
// A group exposes authored links to accessibility APIs; an image would hide them.
|
|
11
|
+
const svg='<svg xmlns="http://www.w3.org/2000/svg" role="'+(box.svg.includes('<a ')?'group':'img')+'" aria-label="'+escapedSource+'"'+
|
|
11
12
|
' data-rapier-math="'+(options.displayMode?'display':'inline')+'" data-math-lines="'+(box.lines || 1)+'"'+
|
|
12
13
|
' data-math-natural-width="'+mathNumber(options.naturalWidth ?? width)+'"'+
|
|
13
14
|
(options.screen?' data-math-screen="'+mathNumber(options.screen.fontSize)+'|'+mathNumber(options.screen.pixelRatio)+'|'+options.screen.dark+'"':'')+
|
|
14
15
|
(options.maxWidth?' data-math-max-width="'+mathNumber(options.maxWidth)+'"':'')+
|
|
15
16
|
(utf16?' data-tex-utf16="'+utf16+'"':'')+
|
|
17
|
+
(error?.sourceOmitted?' data-math-source-omitted="true"':'')+
|
|
16
18
|
(error?' data-math-error="'+mathEscape(error.code)+'"':'')+' width="'+mathNumber(width)+'em" height="'+mathNumber(height+depth)+'em"'+
|
|
17
19
|
' viewBox="'+viewBox.map(mathNumber).join(' ')+'"'+
|
|
18
20
|
' style="font-size:'+mathNumber(mathFontRatio)+'em;max-width:100%;height:auto;vertical-align:-'+mathNumber(depth)+'em;'+
|
|
19
21
|
'fill-opacity:'+opacity+';stroke-opacity:'+opacity+'" fill="currentColor">'+
|
|
20
22
|
'<title>'+escapedSource+'</title>'+(error?'<desc>'+mathEscape(error.message)+'</desc>':'')+
|
|
21
23
|
'<g transform="scale(1000)">'+box.svg+'</g></svg>';
|
|
24
|
+
if(svg.length>24*1024*1024)throw Object.assign(new Error('The complete formula markup exceeds its output budget.'),{code:'resource-limit'});
|
|
22
25
|
return {svg,width,height,depth,lines:box.lines || 1,fitted:!!box.fitted,errors:error?[error]:[]};
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function mathSourceAlternative(source) {
|
|
26
|
-
|
|
29
|
+
const alternatives=[],parts=[];
|
|
30
|
+
let first=-1,kept=0;
|
|
27
31
|
for(let i=0;i<source.length;i++) {
|
|
28
32
|
const code=source.charCodeAt(i);
|
|
29
33
|
if(code>=0xd800 && code<=0xdbff && i+1<source.length) {
|
|
@@ -32,19 +36,32 @@ function mathSourceAlternative(source) {
|
|
|
32
36
|
}
|
|
33
37
|
if((code>=0x20 && code<=0xd7ff) || (code>=0xe000 && code<=0xfffd) || code===9 || code===10 || code===13)continue;
|
|
34
38
|
if(first<0)first=i;
|
|
35
|
-
|
|
39
|
+
if(i>kept)parts.push(source.slice(kept,i));
|
|
40
|
+
parts.push('\\u'+code.toString(16).toUpperCase().padStart(4,'0'));kept=i+1;
|
|
41
|
+
// Flatten small batches instead of retaining one rope node per bad code unit.
|
|
42
|
+
if(parts.length>=1024) {alternatives.push(parts.join(''));parts.length=0;}
|
|
36
43
|
}
|
|
37
44
|
if(first<0)return {alternative:source};
|
|
38
|
-
|
|
45
|
+
parts.push(source.slice(kept));alternatives.push(parts.join(''));
|
|
39
46
|
// Only malformed XML text needs a separate carrier; each four hex digits keep one original code unit.
|
|
40
|
-
|
|
41
|
-
for(let i=0;i<source.length;i++)
|
|
42
|
-
|
|
47
|
+
const encoded=[];parts.length=0;
|
|
48
|
+
for(let i=0;i<source.length;i++) {
|
|
49
|
+
parts.push(source.charCodeAt(i).toString(16).padStart(4,'0'));
|
|
50
|
+
if(parts.length===1024) {encoded.push(parts.join(''));parts.length=0;}
|
|
51
|
+
}
|
|
52
|
+
encoded.push(parts.join(''));
|
|
53
|
+
return {alternative:alternatives.join(''),utf16:encoded.join(''),error:{code:'invalid-source-character',offset:first,
|
|
43
54
|
message:'A source character cannot be embedded in SVG. The text alternative shows Unicode escapes; data-tex-utf16 keeps the original source.'}};
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
function renderMath(source,options={}) {
|
|
47
|
-
const text=String(source ?? '')
|
|
58
|
+
const text=String(source ?? '');
|
|
59
|
+
// Reject before scanning, escaping or parsing. Keep the diagnostic-return
|
|
60
|
+
// contract, but explicitly omit refused source instead of expanding it.
|
|
61
|
+
const safe=text.length>1000000?{alternative:'Formula source omitted: source limit exceeded.',error:{
|
|
62
|
+
code:'resource-limit',offset:0,sourceOmitted:true,
|
|
63
|
+
message:'This formula is too long to render safely. Its source was not embedded; retain the original input.'
|
|
64
|
+
}}:mathSourceAlternative(text),context={size:1,level:0,variant:'normal',cramped:false,display:!!options?.displayMode,cache:new WeakMap(),budget:{nodes:0,outlineBytes:0}};
|
|
48
65
|
try {
|
|
49
66
|
if(safe.error)throw safe.error;
|
|
50
67
|
if(options?.screen!==undefined) {
|
|
@@ -61,11 +78,16 @@ function renderMath(source,options={}) {
|
|
|
61
78
|
return mathSvg(box,safe.alternative,undefined,undefined,{displayMode:context.display,maxWidth,naturalWidth:mathInkWidth(natural)+.05,screen:context.screen});
|
|
62
79
|
}
|
|
63
80
|
catch (cause) {
|
|
64
|
-
const
|
|
65
|
-
|
|
81
|
+
const message=String(cause.message || cause);
|
|
82
|
+
const error={code:cause.code || 'invalid-tex',message:message.length>1024?message.slice(0,1024).replace(/[\ud800-\udbff]$/,'')+'…':message,offset:Number.isFinite(cause.offset)?cause.offset:0};
|
|
83
|
+
if(message.length>1024)error.messageTruncated=true;
|
|
84
|
+
if(cause.sourceOmitted)error.sourceOmitted=true;
|
|
85
|
+
if(cause.command) {
|
|
86
|
+
error.command=String(cause.command).slice(0,128);
|
|
87
|
+
if(cause.command.length>128)error.commandTruncated=true;
|
|
88
|
+
}
|
|
66
89
|
// A diagnostic is visible, but remains distinct from a successfully typeset formula.
|
|
67
|
-
//
|
|
68
|
-
// while the visible notice stays finite and can render after the formula exhausted its budget.
|
|
90
|
+
// Diagnostics have an explicit bound. Exact input stays in the source alternative.
|
|
69
91
|
const label=error.message.length>240?'This formula could not be rendered. The complete diagnostic is in its text description.':error.message.replace(/[^\x20-\x7e]/g,'?');
|
|
70
92
|
const diagnostic={...context,variant:'roman',size:0.8,budget:{nodes:0,outlineBytes:0}};
|
|
71
93
|
try {
|
|
@@ -78,7 +100,7 @@ function renderMath(source,options={}) {
|
|
|
78
100
|
}
|
|
79
101
|
|
|
80
102
|
globalThis.RapierMath=Object.freeze({
|
|
81
|
-
version:'1.
|
|
103
|
+
version:'1.1.1',
|
|
82
104
|
parse:parseMathTex,
|
|
83
105
|
render:renderMath,
|
|
84
106
|
fit:mathFit,
|