@teamturing/react-native-tex 1.1.6 → 1.1.7

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.
@@ -2,486 +2,493 @@
2
2
  const text = ({ fontSize }: { fontSize: number } = { fontSize: 13 }) => String.raw`
3
3
  <!DOCTYPE html>
4
4
  <html lang="ko">
5
- <head>
6
- <title>MathKing</title>
7
- <meta
8
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
9
- name="viewport"
10
- id="latex_viewport"
11
- charset="UTF-8"
12
- />
13
-
14
- <script async src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
15
- <link
16
- rel="stylesheet"
17
- href="https://cdn.jsdelivr.net/npm/@teamturing/katex-utils@2.19.0/dist/mathking-katex.css"
18
- crossorigin="anonymous"
19
- />
20
-
21
- <style>
5
+ <head>
6
+ <title>MathKing</title>
7
+ <meta
8
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
9
+ name="viewport"
10
+ id="latex_viewport"
11
+ charset="UTF-8"
12
+ />
13
+
14
+ <script async src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
15
+ <link
16
+ rel="stylesheet"
17
+ href="https://cdn.jsdelivr.net/npm/@teamturing/katex-utils@2.19.0/dist/mathking-katex.css"
18
+ crossorigin="anonymous"
19
+ />
20
+
21
+ <style>
22
22
  ._cms_content-frame {
23
- font-size: ${fontSize}px;
23
+ font-size: ${fontSize}px;
24
24
  }
25
- </style>
26
-
27
- <style>
25
+ </style>
26
+
27
+ <style>
28
28
  *,
29
29
  *::after,
30
30
  *::before {
31
- -webkit-user-select: none;
32
- -webkit-user-drag: none;
33
- cursor: default;
34
- -webkit-touch-callout: none;
35
- -moz-user-select: none;
36
- -ms-user-select: none;
37
- user-select: none;
31
+ -webkit-user-select: none;
32
+ -webkit-user-drag: none;
33
+ cursor: default;
34
+ -webkit-touch-callout: none;
35
+ -moz-user-select: none;
36
+ -ms-user-select: none;
37
+ user-select: none;
38
38
  }
39
39
 
40
40
  html {
41
- padding: 0 0;
42
- margin: 0;
41
+ padding: 0 0;
42
+ margin: 0;
43
43
  }
44
44
 
45
45
  body {
46
- padding: 0;
47
- margin: 0 0 0 0;
48
- position: relative;
46
+ padding: 0;
47
+ margin: 0 0 0 0;
48
+ position: relative;
49
49
  }
50
- </style>
51
- <style>
50
+ </style>
51
+ <style>
52
52
  #container {
53
- background-color: white;
54
- width: 100%;
53
+ background-color: white;
54
+ width: 100%;
55
55
  }
56
56
 
57
57
  #shadow-animation-container {
58
- visibility: hidden;
58
+ visibility: hidden;
59
59
  }
60
60
 
61
61
  @keyframes fade-in {
62
- to {
63
- opacity: 1;
64
- }
65
- from {
66
- opacity: 0;
67
- }
62
+ to {
63
+ opacity: 1;
64
+ }
65
+ from {
66
+ opacity: 0;
67
+ }
68
68
  }
69
69
 
70
70
  @keyframes cursor-blink {
71
- 0% {
72
- opacity: 0;
73
- }
74
- 50% {
75
- opacity: 1;
76
- }
77
- 100% {
78
- opacity: 0;
79
- }
71
+ 0% {
72
+ opacity: 0;
73
+ }
74
+ 50% {
75
+ opacity: 1;
76
+ }
77
+ 100% {
78
+ opacity: 0;
79
+ }
80
80
  }
81
81
 
82
82
  .typewriter-cursor {
83
- border-radius: 1px;
84
- width: 1.5px;
85
- height: 14px;
86
- /*border: 1px solid black;*/
87
- background: black;
88
- visibility: hidden;
89
- position: absolute;
83
+ border-radius: 1px;
84
+ width: 1.5px;
85
+ height: 14px;
86
+ /*border: 1px solid black;*/
87
+ background: black;
88
+ visibility: hidden;
89
+ position: absolute;
90
90
  }
91
- </style>
92
- </head>
93
- <body>
94
- <div id="container" onmousedown="return false;"></div>
95
- <div id="shadow-animation-container" onmousedown="return false;" aria-hidden="true"></div>
96
- <div class="typewriter-cursor"></div>
97
- <script>
98
- const CONTENT_FRAME_CLASS = '_cms_content-frame';
99
-
100
- const documentResizeObserver = new ResizeObserver(() => {
101
- onDocumentResized();
102
- });
103
- documentResizeObserver.observe(document.getElementById('container'));
104
-
105
- const renderChoiceLayout = (container) => {
106
- const choiceBox = container.querySelector('._cms_choice-box');
107
- if (!choiceBox) return;
108
-
109
- const choiceBoxWidth = choiceBox.getBoundingClientRect().width;
110
- choiceBox.classList.remove('strip');
111
- choiceBox.classList.remove('third');
112
- choiceBox.classList.remove('half');
113
- choiceBox.classList.remove('full');
114
-
115
- const maxChoiceWidth = Array.from(choiceBox.querySelectorAll('._cms_choice')).reduce((pre, choice) => {
116
- const width = choice.getBoundingClientRect().width;
117
- return pre > width ? pre : width;
118
- }, 0);
119
-
120
- if (maxChoiceWidth > (choiceBoxWidth / 100) * 50) {
121
- choiceBox.classList.add('full');
122
- } else if (maxChoiceWidth > (choiceBoxWidth / 100) * 33) {
123
- choiceBox.classList.add('half');
124
- } else if (maxChoiceWidth > (choiceBoxWidth / 100) * 25) {
125
- choiceBox.classList.add('third');
126
- } else if (maxChoiceWidth < (choiceBoxWidth / 100) * 20) {
127
- choiceBox.classList.add('strip');
128
- } else {
129
- choiceBox.classList.add('third');
130
- }
131
- };
132
-
133
- function relayout() {
134
- try {
135
- const container = document.getElementById('container');
136
- if (container) renderChoiceLayout(container);
137
- } catch (e) {
138
- reportErrorWithSlackWebhook(e);
139
- }
91
+ </style>
92
+ </head>
93
+ <body>
94
+ <div id="container" onmousedown="return false;"></div>
95
+ <div id="shadow-animation-container" onmousedown="return false;" aria-hidden="true"></div>
96
+ <div class="typewriter-cursor"></div>
97
+ <script>
98
+ const CONTENT_FRAME_CLASS = "_cms_content-frame";
99
+
100
+ const documentResizeObserver = new ResizeObserver(() => {
101
+ onDocumentResized();
102
+ });
103
+ documentResizeObserver.observe(document.getElementById("container"));
104
+
105
+ const renderChoiceLayout = (container) => {
106
+ const choiceBox = container.querySelector("._cms_choice-box");
107
+ if (!choiceBox) return;
108
+
109
+ const choiceBoxWidth = choiceBox.getBoundingClientRect().width;
110
+ choiceBox.classList.remove("strip");
111
+ choiceBox.classList.remove("third");
112
+ choiceBox.classList.remove("half");
113
+ choiceBox.classList.remove("full");
114
+
115
+ const maxChoiceWidth = Array.from(choiceBox.querySelectorAll("._cms_choice")).reduce((pre, choice) => {
116
+ const width = choice.getBoundingClientRect().width;
117
+ return pre > width ? pre : width;
118
+ }, 0);
119
+
120
+ if (maxChoiceWidth > (choiceBoxWidth / 100) * 50) {
121
+ choiceBox.classList.add("full");
122
+ } else if (maxChoiceWidth > (choiceBoxWidth / 100) * 33) {
123
+ choiceBox.classList.add("half");
124
+ } else if (maxChoiceWidth > (choiceBoxWidth / 100) * 25) {
125
+ choiceBox.classList.add("third");
126
+ } else if (maxChoiceWidth < (choiceBoxWidth / 100) * 20) {
127
+ choiceBox.classList.add("strip");
128
+ } else {
129
+ choiceBox.classList.add("third");
130
+ }
131
+ };
132
+
133
+ function relayout () {
134
+ try {
135
+ const container = document.getElementById("container");
136
+ if (container) renderChoiceLayout(container);
137
+ } catch (e) {
138
+ reportErrorWithSlackWebhook(e);
139
+ }
140
+ }
141
+
142
+ const onRenderSuccess = () => {
143
+ window.ReactNativeWebView.postMessage(JSON.stringify({ event: "render-success" }));
144
+ };
145
+ const onRenderFailed = () => {
146
+ window.ReactNativeWebView.postMessage(JSON.stringify({ event: "render-fail" }));
147
+ };
148
+ const onPhantomBoxCountChanged = (count) => {
149
+ window.ReactNativeWebView.postMessage(JSON.stringify({ event: "phantom-box-count-changed", count }));
150
+ };
151
+ const onPhantomBoxPressed = (index) => {
152
+ window.ReactNativeWebView.postMessage(JSON.stringify({ event: "phantom-box-pressed", index }));
153
+ };
154
+ let lastScrollHeight = 0;
155
+ let lastScrollWidth = 0;
156
+ let lastClientWidth = 0;
157
+ const onDocumentResized = () => {
158
+ const container = document.getElementById("container");
159
+ if (container && Math.abs(lastScrollHeight - container.scrollHeight) +
160
+ Math.abs(lastScrollWidth - container.scrollWidth) + Math.abs(lastClientWidth - container.clientWidth) >= 15) {
161
+ lastScrollHeight = container.scrollHeight;
162
+ lastScrollWidth = container.scrollWidth;
163
+ lastClientWidth = container.clientWidth;
164
+ window.ReactNativeWebView.postMessage(
165
+ JSON.stringify({
166
+ event: "set-layout",
167
+ scrollHeight: container.scrollHeight,
168
+ scrollWidth: container.scrollWidth,
169
+ clientWidth: container.clientWidth
170
+ })
171
+ );
172
+ }
173
+ };
174
+
175
+ const scrollToTop = () => {
176
+ window.scrollTo(0, 0);
177
+ };
178
+
179
+ const setPhantomBoxVisibility = (index, state) => {
180
+ const box = document.getElementById("phantom-box-" + index);
181
+ const border = document.getElementById("phantom-box-border-" + index);
182
+ if (box && border) {
183
+ box.classList.remove("_cms_phantom_box_invisible", "_cms_phantom_box_visible", "_cms_phantom_no_box");
184
+ border.classList.remove("_cms_phantom_border_visible", "_cms_phantom_border_invisible");
185
+ if (state === "box_visible") {
186
+ box.classList.add("_cms_phantom_box_visible");
187
+ border.classList.add("_cms_phantom_border_visible");
188
+ } else if (state === "box_invisible") {
189
+ box.classList.add("_cms_phantom_box_invisible");
190
+ border.classList.add("_cms_phantom_border_visible");
191
+ } else {
192
+ box.classList.add("_cms_phantom_no_box");
193
+ border.classList.add("_cms_phantom_border_invisible");
140
194
  }
141
-
142
- const onRenderSuccess = () => {
143
- window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'render-success' }));
144
- };
145
- const onRenderFailed = () => {
146
- window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'render-fail' }));
147
- };
148
- const onPhantomBoxCountChanged = (count) => {
149
- window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'phantom-box-count-changed', count }));
150
- };
151
- const onPhantomBoxPressed = (index) => {
152
- window.ReactNativeWebView.postMessage(JSON.stringify({ event: 'phantom-box-pressed', index }));
153
- };
154
- const onDocumentResized = () => {
155
- const container = document.getElementById('container');
156
- if (container) {
157
- window.ReactNativeWebView.postMessage(
158
- JSON.stringify({
159
- event: 'set-layout',
160
- scrollHeight: container.scrollHeight,
161
- scrollWidth: container.scrollWidth,
162
- clientWidth: container.clientWidth,
163
- }),
164
- );
165
- }
166
- };
167
-
168
- const scrollToTop = () => {
169
- window.scrollTo(0, 0);
170
- };
171
-
172
- const setPhantomBoxVisibility = (index, state) => {
173
- const box = document.getElementById('phantom-box-' + index);
174
- const border = document.getElementById('phantom-box-border-' + index);
195
+ }
196
+ };
197
+
198
+ const togglePhantomBoxVisibility = (index) => {
199
+ const box = document.getElementById("phantom-box-" + index);
200
+ if (box) {
201
+ if (box.classList.contains("_cms_phantom_box_invisible")) {
202
+ setPhantomBoxVisibility(index, "box_visible");
203
+ } else if (box.classList.contains("_cms_phantom_box_visible")) {
204
+ setPhantomBoxVisibility(index, "box_invisible");
205
+ } else {
206
+ // if no_box state, do nothing
207
+ }
208
+ }
209
+ };
210
+
211
+ const initializePhantomBoxes = (initialPhantomBoxVisibility, isPhantomBoxClickable) => {
212
+ let count = 0;
213
+ iteratePhantomBoxes((box, border, i) => {
214
+ count += 1;
215
+ initializeBox(box, border, i);
216
+ });
217
+ onPhantomBoxCountChanged(count);
218
+
219
+ function initializeBox (box, border, index) {
220
+ setPhantomBoxVisibility(index, initialPhantomBoxVisibility || "box_invisible");
221
+ if (isPhantomBoxClickable) {
222
+ box.onclick = () => {
223
+ togglePhantomBoxVisibility(index);
224
+ onPhantomBoxPressed(index);
225
+ };
226
+ }
227
+ }
228
+ };
229
+
230
+ const iteratePhantomBoxes = (callback) => {
231
+ try {
232
+ for (let i = 0; ; i++) {
233
+ const box = document.getElementById("phantom-box-" + i);
234
+ const border = document.getElementById("phantom-box-border-" + i);
175
235
  if (box && border) {
176
- box.classList.remove('_cms_phantom_box_invisible', '_cms_phantom_box_visible', '_cms_phantom_no_box');
177
- border.classList.remove('_cms_phantom_border_visible', '_cms_phantom_border_invisible');
178
- if (state === 'box_visible') {
179
- box.classList.add('_cms_phantom_box_visible');
180
- border.classList.add('_cms_phantom_border_visible');
181
- } else if (state === 'box_invisible') {
182
- box.classList.add('_cms_phantom_box_invisible');
183
- border.classList.add('_cms_phantom_border_visible');
184
- } else {
185
- box.classList.add('_cms_phantom_no_box');
186
- border.classList.add('_cms_phantom_border_invisible');
187
- }
188
- }
189
- };
190
-
191
- const togglePhantomBoxVisibility = (index) => {
192
- const box = document.getElementById('phantom-box-' + index);
193
- if (box) {
194
- if (box.classList.contains('_cms_phantom_box_invisible')) {
195
- setPhantomBoxVisibility(index, 'box_visible');
196
- } else if (box.classList.contains('_cms_phantom_box_visible')) {
197
- setPhantomBoxVisibility(index, 'box_invisible');
198
- } else {
199
- // if no_box state, do nothing
200
- }
201
- }
202
- };
203
-
204
- const initializePhantomBoxes = (initialPhantomBoxVisibility, isPhantomBoxClickable) => {
205
- let count = 0;
206
- iteratePhantomBoxes((box, border, i) => {
207
- count += 1;
208
- initializeBox(box, border, i);
209
- });
210
- onPhantomBoxCountChanged(count);
211
-
212
- function initializeBox(box, border, index) {
213
- setPhantomBoxVisibility(index, initialPhantomBoxVisibility || 'box_invisible');
214
- if (isPhantomBoxClickable) {
215
- box.onclick = () => {
216
- togglePhantomBoxVisibility(index);
217
- onPhantomBoxPressed(index);
218
- };
219
- }
236
+ callback(box, border, i);
237
+ } else {
238
+ break;
220
239
  }
221
- };
222
-
223
- const iteratePhantomBoxes = (callback) => {
224
- try {
225
- for (let i = 0; ; i++) {
226
- const box = document.getElementById('phantom-box-' + i);
227
- const border = document.getElementById('phantom-box-border-' + i);
228
- if (box && border) {
229
- callback(box, border, i);
240
+ }
241
+ } catch (e) {}
242
+ };
243
+
244
+ const renderLaTex = ({
245
+ html,
246
+ paddingHorizontal,
247
+ initialPhantomBoxVisibility,
248
+ isPhantomBoxClickable,
249
+ paddingBottom,
250
+ paddingTop,
251
+ isAiAnimationEnable
252
+ }) => {
253
+ const container = document.getElementById("container");
254
+ const shadowContainer = document.getElementById("shadow-animation-container");
255
+
256
+ let delayHandler = -1;
257
+
258
+ function setPaddingForContentFrame (element) {
259
+ if (element instanceof HTMLElement) {
260
+ const paddingStyle =
261
+ (paddingTop || 0) +
262
+ "px " +
263
+ (paddingHorizontal || 0) +
264
+ "px " +
265
+ (paddingBottom || "0") +
266
+ "px " +
267
+ (paddingHorizontal || 0) +
268
+ "px";
269
+
270
+ element.style.padding = paddingStyle;
271
+ }
272
+ }
273
+
274
+ function renderContainer () {
275
+ container.innerHTML = html;
276
+ container.style.visibility = "visible";
277
+ shadowContainer.innerHTML = "";
278
+ clearTimeout(delayHandler);
279
+ setPaddingForContentFrame(container.querySelector("." + CONTENT_FRAME_CLASS));
280
+ setTimeout(function() {
281
+ relayout();
282
+ }, 100);
283
+ initializePhantomBoxes(initialPhantomBoxVisibility, isPhantomBoxClickable);
284
+ onRenderSuccess();
285
+ }
286
+
287
+ function onAiAnimationRenderFailed () {
288
+ clearTimeout(delayHandler);
289
+ shadowContainer.innerHTML = "";
290
+ /** @type {HTMLDivElement} */
291
+ const cursor = document.querySelector(".typewriter-cursor");
292
+ if (cursor) {
293
+ cursor.style.visibility = "hidden";
294
+ }
295
+ renderContainer();
296
+ }
297
+
298
+ function renderContainerWithAiAnimation () {
299
+ try {
300
+ container.innerHTML = "";
301
+ const mockedContentFrame = document.createElement("div");
302
+ mockedContentFrame.className = CONTENT_FRAME_CLASS;
303
+ setPaddingForContentFrame(mockedContentFrame);
304
+ container.appendChild(mockedContentFrame);
305
+ shadowContainer.innerHTML = html;
306
+ const root = shadowContainer.querySelector("." + CONTENT_FRAME_CLASS);
307
+ if (root) {
308
+ root.style.visibility = "hidden";
309
+ /** @type {Node[]} */
310
+ const replacedElements = [];
311
+ /** @type {HTMLElement[]} */
312
+ const animatedElements = [];
313
+
314
+ for (let node = root.firstChild; node; node = node.nextSibling) {
315
+ if (node.nodeType === 3 /* text */ && typeof node.textContent === "string" && node.textContent.trim()) {
316
+ for (let i = 0; i < node.textContent.length; i++) {
317
+ /** @type {HTMLSpanElement} */
318
+ const newSpan = document.createElement("span");
319
+ newSpan.textContent = node.textContent.charAt(i);
320
+ newSpan.style.visibility = "hidden";
321
+ newSpan.className += " splitted-text";
322
+ animatedElements.push(newSpan);
323
+ replacedElements.push(newSpan);
324
+ }
325
+ } else if (
326
+ node.firstChild &&
327
+ node.firstChild.firstChild &&
328
+ node.firstChild.firstChild.classList.contains("base")
329
+ ) {
330
+ /** @type {HTMLElement} */
331
+ const katexHtml = node.firstChild;
332
+ for (let i = 0; i < katexHtml.children.length; i++) {
333
+ /** @type {HTMLElement} */
334
+ const baseElement = katexHtml.children[i];
335
+ if (baseElement.classList.contains("base")) {
336
+ baseElement.style.visibility = "hidden";
337
+ animatedElements.push(baseElement);
338
+ }
339
+ }
340
+ replacedElements.push(node);
230
341
  } else {
231
- break;
342
+ if (node.nodeType === 1 /* element */) {
343
+ node.style.visibility = "hidden";
344
+ animatedElements.push(node);
345
+ }
346
+ replacedElements.push(node);
232
347
  }
233
348
  }
234
- } catch (e) {}
235
- };
236
-
237
- const renderLaTex = ({
238
- html,
239
- paddingHorizontal,
240
- initialPhantomBoxVisibility,
241
- isPhantomBoxClickable,
242
- paddingBottom,
243
- paddingTop,
244
- isAiAnimationEnable,
245
- }) => {
246
- const container = document.getElementById('container');
247
- const shadowContainer = document.getElementById('shadow-animation-container');
248
-
249
- let delayHandler = -1;
250
-
251
- function setPaddingForContentFrame(element) {
252
- if (element instanceof HTMLElement) {
253
- const paddingStyle =
254
- (paddingTop || 0) +
255
- 'px ' +
256
- (paddingHorizontal || 0) +
257
- 'px ' +
258
- (paddingBottom || '0') +
259
- 'px ' +
260
- (paddingHorizontal || 0) +
261
- 'px';
262
-
263
- element.style.padding = paddingStyle;
349
+ root.innerHTML = "";
350
+ for (const el of replacedElements) {
351
+ root.appendChild(el);
264
352
  }
265
- }
266
-
267
- function renderContainer() {
268
- container.innerHTML = html;
269
- container.style.visibility = 'visible';
270
- shadowContainer.innerHTML = '';
271
- clearTimeout(delayHandler);
272
- setPaddingForContentFrame(container.querySelector('.' + CONTENT_FRAME_CLASS));
273
- setTimeout(function () {
274
- relayout();
275
- }, 100);
276
- initializePhantomBoxes(initialPhantomBoxVisibility, isPhantomBoxClickable);
277
- onRenderSuccess();
278
- }
279
353
 
280
- function onAiAnimationRenderFailed() {
281
- clearTimeout(delayHandler);
282
- shadowContainer.innerHTML = '';
283
- /** @type {HTMLDivElement} */
284
- const cursor = document.querySelector('.typewriter-cursor');
285
- if (cursor) {
286
- cursor.style.visibility = 'hidden';
287
- }
288
- renderContainer();
289
- }
290
-
291
- function renderContainerWithAiAnimation() {
292
- try {
293
- container.innerHTML = '';
294
- const mockedContentFrame = document.createElement('div');
295
- mockedContentFrame.className = CONTENT_FRAME_CLASS;
296
- setPaddingForContentFrame(mockedContentFrame);
297
- container.appendChild(mockedContentFrame);
298
- shadowContainer.innerHTML = html;
299
- const root = shadowContainer.querySelector('.' + CONTENT_FRAME_CLASS);
300
- if (root) {
301
- root.style.visibility = 'hidden';
302
- /** @type {Node[]} */
303
- const replacedElements = [];
304
- /** @type {HTMLElement[]} */
305
- const animatedElements = [];
306
-
307
- for (let node = root.firstChild; node; node = node.nextSibling) {
308
- if (node.nodeType === 3 /* text */ && typeof node.textContent === 'string' && node.textContent.trim()) {
309
- for (let i = 0; i < node.textContent.length; i++) {
310
- /** @type {HTMLSpanElement} */
311
- const newSpan = document.createElement('span');
312
- newSpan.textContent = node.textContent.charAt(i);
313
- newSpan.style.visibility = 'hidden';
314
- newSpan.className += ' splitted-text';
315
- animatedElements.push(newSpan);
316
- replacedElements.push(newSpan);
317
- }
318
- } else if (
319
- node.firstChild &&
320
- node.firstChild.firstChild &&
321
- node.firstChild.firstChild.classList.contains('base')
322
- ) {
323
- /** @type {HTMLElement} */
324
- const katexHtml = node.firstChild;
325
- for (let i = 0; i < katexHtml.children.length; i++) {
326
- /** @type {HTMLElement} */
327
- const baseElement = katexHtml.children[i];
328
- if (baseElement.classList.contains('base')) {
329
- baseElement.style.visibility = 'hidden';
330
- animatedElements.push(baseElement);
331
- }
332
- }
333
- replacedElements.push(node);
334
- } else {
335
- if (node.nodeType === 1 /* element */) {
336
- node.style.visibility = 'hidden';
337
- animatedElements.push(node);
338
- }
339
- replacedElements.push(node);
340
- }
354
+ // 구성된 root를 contianer에 넣어준다.
355
+ mockedContentFrame.appendChild(root);
356
+ shadowContainer.innerHTML = "";
357
+
358
+ /** @type {number[]} */
359
+ const durations = [];
360
+ for (let i = 0, j = 0, k = 0; i < animatedElements.length; i++) {
361
+ const el = animatedElements[i];
362
+ if (el.className && el.className.includes("splitted-text")) {
363
+ k++;
364
+ if (el.textContent === " " && k % 10 === 0 && Math.random() < 0.5) {
365
+ durations.push(400 + Math.random() * 200 - 200);
366
+ } else {
367
+ durations.push(20 + Math.random() * 10 - 10);
341
368
  }
342
- root.innerHTML = '';
343
- for (const el of replacedElements) {
344
- root.appendChild(el);
345
- }
346
-
347
- // 구성된 root를 contianer에 넣어준다.
348
- mockedContentFrame.appendChild(root);
349
- shadowContainer.innerHTML = '';
350
-
351
- /** @type {number[]} */
352
- const durations = [];
353
- for (let i = 0, j = 0, k = 0; i < animatedElements.length; i++) {
354
- const el = animatedElements[i];
355
- if (el.className && el.className.includes('splitted-text')) {
356
- k++;
357
- if (el.textContent === ' ' && k % 10 === 0 && Math.random() < 0.5) {
358
- durations.push(400 + Math.random() * 200 - 200);
359
- } else {
360
- durations.push(20 + Math.random() * 10 - 10);
361
- }
362
- } else {
363
- j++;
364
- if (j % 20 === 0 && Math.random() < 0.5) {
365
- durations.push(250);
366
- } else {
367
- durations.push(80 + Math.random() * 40 - 40);
368
- }
369
- }
369
+ } else {
370
+ j++;
371
+ if (j % 20 === 0 && Math.random() < 0.5) {
372
+ durations.push(250);
373
+ } else {
374
+ durations.push(80 + Math.random() * 40 - 40);
370
375
  }
371
- const runAnimation = (index) => {
372
- if (animatedElements.length <= index || animatedElements.length !== durations.length) {
373
- // setContainerVisible(false);
374
- // clearTimeout(delayHandler.current);
375
- onAiAnimationRenderFailed();
376
- return;
377
- }
378
- const el = animatedElements[index];
376
+ }
377
+ }
378
+ const runAnimation = (index) => {
379
+ if (animatedElements.length <= index || animatedElements.length !== durations.length) {
380
+ // setContainerVisible(false);
381
+ // clearTimeout(delayHandler.current);
382
+ onAiAnimationRenderFailed();
383
+ return;
384
+ }
385
+ const el = animatedElements[index];
379
386
 
380
- el.style.visibility = 'visible';
381
- if (el.tagName === 'IMG') {
382
- el.style.animation = '.5s fade-in ease-in';
383
- }
387
+ el.style.visibility = "visible";
388
+ if (el.tagName === "IMG") {
389
+ el.style.animation = ".5s fade-in ease-in";
390
+ }
384
391
 
385
- /** @type {HTMLDivElement} */
386
- const cursor = document.querySelector('.typewriter-cursor');
387
- if (cursor && el.tagName === 'SPAN') {
388
- cursor.style.visibility = 'visible';
389
- const rect = el.getBoundingClientRect();
390
- cursor.style.top = rect.y + (rect.height - 14) / 2 + 'px';
391
- cursor.style.left = rect.right + 4 + 'px';
392
- }
392
+ /** @type {HTMLDivElement} */
393
+ const cursor = document.querySelector(".typewriter-cursor");
394
+ if (cursor && el.tagName === "SPAN") {
395
+ cursor.style.visibility = "visible";
396
+ const rect = el.getBoundingClientRect();
397
+ cursor.style.top = rect.y + (rect.height - 14) / 2 + "px";
398
+ cursor.style.left = rect.right + 4 + "px";
399
+ }
393
400
 
394
- if (index === durations.length - 1) {
395
- // 애니메이션 종료
396
- clearTimeout(delayHandler);
397
- if (cursor) {
398
- const anim = cursor.animate([{ opacity: 0 }, { opacity: 1 }], {
399
- duration: 500,
400
- iterations: Infinity,
401
- direction: 'alternate-reverse',
402
- easing: 'ease-in-out',
403
- });
404
- delayHandler = setTimeout(() => {
405
- anim.cancel();
406
- cursor.style.visibility = 'hidden';
407
- cursor.style.animation = '';
408
- }, 1500);
409
- }
410
- } else {
411
- // 다음 요소 애니메이션
412
- delayHandler = setTimeout(() => {
413
- runAnimation(index + 1);
414
- }, durations[index]);
415
- }
416
- };
417
- runAnimation(0);
401
+ if (index === durations.length - 1) {
402
+ // 애니메이션 종료
403
+ clearTimeout(delayHandler);
404
+ if (cursor) {
405
+ const anim = cursor.animate([{ opacity: 0 }, { opacity: 1 }], {
406
+ duration: 500,
407
+ iterations: Infinity,
408
+ direction: "alternate-reverse",
409
+ easing: "ease-in-out"
410
+ });
411
+ delayHandler = setTimeout(() => {
412
+ anim.cancel();
413
+ cursor.style.visibility = "hidden";
414
+ cursor.style.animation = "";
415
+ }, 1500);
416
+ }
418
417
  } else {
419
- onAiAnimationRenderFailed();
418
+ // 다음 요소 애니메이션
419
+ delayHandler = setTimeout(() => {
420
+ runAnimation(index + 1);
421
+ }, durations[index]);
420
422
  }
421
- } catch (e) {
422
- onAiAnimationRenderFailed();
423
- }
423
+ };
424
+ runAnimation(0);
425
+ } else {
426
+ onAiAnimationRenderFailed();
424
427
  }
428
+ } catch (e) {
429
+ onAiAnimationRenderFailed();
430
+ }
431
+ }
425
432
 
426
- try {
427
- if (isAiAnimationEnable) {
428
- renderContainerWithAiAnimation();
429
- } else {
430
- renderContainer();
431
- }
432
- } catch (e) {
433
- reportErrorWithSlackWebhook(e);
434
- onRenderFailed();
435
- }
436
- };
437
-
438
- function reportErrorWithSlackWebhook(e) {
439
- fetch('https://hooks.slack.com/services/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', {
440
- method: 'POST',
441
- headers: {
442
- 'Content-type': 'application/json',
443
- },
444
- body: JSON.stringify({
445
- text: '*Tex Rendering Issue*\`\`\`' + ('' + e) + '\n\`\`\`',
446
- }),
433
+ try {
434
+ if (isAiAnimationEnable) {
435
+ renderContainerWithAiAnimation();
436
+ } else {
437
+ renderContainer();
438
+ }
439
+ } catch (e) {
440
+ reportErrorWithSlackWebhook(e);
441
+ onRenderFailed();
442
+ }
443
+ };
444
+
445
+ function reportErrorWithSlackWebhook (e) {
446
+ fetch("https://hooks.slack.com/services/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", {
447
+ method: "POST",
448
+ headers: {
449
+ "Content-type": "application/json"
450
+ },
451
+ body: JSON.stringify({
452
+ text: "*Tex Rendering Issue*\`\`\`" + ("" + e) + "\n\`\`\`"
453
+ })
454
+ });
455
+ }
456
+
457
+ const MessageTypes = ["render_tex", "set_phantom_boxes_visibility", "scroll_to_top"];
458
+
459
+ const checkIsValidArgument = (type) => {
460
+ return MessageTypes.includes(type);
461
+ };
462
+
463
+ const handleMessage = ({ type, data }) => {
464
+ if (!checkIsValidArgument(type)) return;
465
+
466
+ try {
467
+ if (type === "render_tex") {
468
+ renderLaTex(data);
469
+ } else if (type === "set_phantom_boxes_visibility") {
470
+ iteratePhantomBoxes((box, border, i) => {
471
+ setPhantomBoxVisibility(i, data.visibility);
447
472
  });
473
+ } else if (type === "scroll_to_top") {
474
+ scrollToTop();
448
475
  }
449
-
450
- const MessageTypes = ['render_tex', 'set_phantom_boxes_visibility', 'scroll_to_top'];
451
-
452
- const checkIsValidArgument = (type) => {
453
- return MessageTypes.includes(type);
454
- };
455
-
456
- const handleMessage = ({ type, data }) => {
457
- if (!checkIsValidArgument(type)) return;
458
-
459
- try {
460
- if (type === 'render_tex') {
461
- renderLaTex(data);
462
- } else if (type === 'set_phantom_boxes_visibility') {
463
- iteratePhantomBoxes((box, border, i) => {
464
- setPhantomBoxVisibility(i, data.visibility);
465
- });
466
- } else if (type === 'scroll_to_top') {
467
- scrollToTop();
468
- }
469
- } catch (e) {}
470
- };
471
-
472
- /**
473
- * For Android, use document and use window for iOS
474
- * @link https://github.com/react-native-community/react-native-webview/issues/356#issuecomment-467430141
475
- */
476
- document.addEventListener('message', (event) => {
477
- handleMessage(event.data);
478
- });
479
-
480
- window.addEventListener('message', (event) => {
481
- handleMessage(event.data);
482
- });
483
- </script>
484
- </body>
476
+ } catch (e) {}
477
+ };
478
+
479
+ /**
480
+ * For Android, use document and use window for iOS
481
+ * @link https://github.com/react-native-community/react-native-webview/issues/356#issuecomment-467430141
482
+ */
483
+ document.addEventListener("message", (event) => {
484
+ handleMessage(event.data);
485
+ });
486
+
487
+ window.addEventListener("message", (event) => {
488
+ handleMessage(event.data);
489
+ });
490
+ </script>
491
+ </body>
485
492
  </html>
486
493
  `
487
494
  export default text;