@zzish/math-rich-input 0.1.49 → 0.1.51
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/dist/index.js +171 -33
- package/dist/math-rich-input.css +1 -1
- package/dist/standalone.js +1 -1
- package/package.json +1 -1
- package/src/EquationEditor.css +168 -160
- package/src/EquationEditorModal.css +143 -105
- package/src/EquationEditorModal.jsx +165 -24
- package/src/MathRichInput.jsx +1 -0
- package/src/SymbolButton.css +1 -0
- package/src/standalone.js +413 -56
|
@@ -1,163 +1,201 @@
|
|
|
1
1
|
.EquationEditorModal-background {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
position: fixed;
|
|
3
|
+
top: 0;
|
|
4
|
+
left: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
background: black;
|
|
8
|
+
z-index: 999998;
|
|
9
|
+
/* Start transparent */
|
|
10
|
+
opacity: 0;
|
|
11
|
+
animation: 0.3s shade cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
12
|
+
animation-fill-mode: forwards;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
@keyframes shade {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
00% {
|
|
17
|
+
opacity: 0;
|
|
18
|
+
}
|
|
19
|
+
100% {
|
|
20
|
+
opacity: 0.6;
|
|
21
|
+
}
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
.EquationEditorModal {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
background: white;
|
|
26
|
+
border: 1px solid #808080;
|
|
27
|
+
border-radius: 10px;
|
|
28
|
+
box-shadow: 0px 2px 5px 1px #a0a0a0;
|
|
29
|
+
position: fixed;
|
|
30
|
+
max-width: 500px;
|
|
31
|
+
width: 98%;
|
|
32
|
+
top: 50%;
|
|
33
|
+
left: 50%;
|
|
34
|
+
/* Start invisible to prevent flash, animation will make it visible */
|
|
35
|
+
transform: translate(-50%, 100%);
|
|
36
|
+
opacity: 0;
|
|
37
|
+
z-index: 999999;
|
|
38
|
+
animation: 0.3s rise cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
39
|
+
animation-fill-mode: forwards;
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
@keyframes rise {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
00% {
|
|
44
|
+
transform: translate(-50%, 100%);
|
|
45
|
+
opacity: 0;
|
|
46
|
+
}
|
|
47
|
+
100% {
|
|
48
|
+
transform: translate(-50%, -50%);
|
|
49
|
+
opacity: 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Svelte-friendly alternative: disable animation when needed */
|
|
54
|
+
.EquationEditorModal.no-animation {
|
|
55
|
+
animation: none !important;
|
|
56
|
+
transform: translate(-50%, -50%) !important;
|
|
57
|
+
opacity: 1 !important;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.EquationEditorModal-mobile.no-animation {
|
|
61
|
+
animation: none !important;
|
|
62
|
+
transform: translate(-50%, 1px) !important;
|
|
63
|
+
opacity: 1 !important;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* Disable background animation too when modal is no-animation */
|
|
67
|
+
.EquationEditorModal-background.no-animation {
|
|
68
|
+
animation: none !important;
|
|
69
|
+
opacity: 0.6 !important;
|
|
47
70
|
}
|
|
48
71
|
|
|
49
72
|
.EquationEditorModal-mobile {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
73
|
+
background: white;
|
|
74
|
+
border: 1px solid #808080;
|
|
75
|
+
border-radius: 10px;
|
|
76
|
+
box-shadow: 0px 2px 5px 1px #a0a0a0;
|
|
77
|
+
position: fixed;
|
|
78
|
+
max-width: 500px;
|
|
79
|
+
width: 99%;
|
|
80
|
+
top: 0%;
|
|
81
|
+
left: 50%;
|
|
82
|
+
/* Start off-screen for animation */
|
|
83
|
+
transform: translate(-50%, -100%);
|
|
84
|
+
opacity: 0;
|
|
85
|
+
z-index: 999999;
|
|
86
|
+
animation: 0.3s riseFromTop cubic-bezier(0.2, 0, 0.38, 0.9);
|
|
87
|
+
animation-fill-mode: forwards;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@keyframes riseFromTop {
|
|
91
|
+
00% {
|
|
92
|
+
transform: translate(-50%, -100%);
|
|
93
|
+
opacity: 0;
|
|
94
|
+
}
|
|
95
|
+
100% {
|
|
59
96
|
transform: translate(-50%, 1px);
|
|
60
|
-
|
|
97
|
+
opacity: 1;
|
|
98
|
+
}
|
|
61
99
|
}
|
|
62
100
|
|
|
63
101
|
.EquationEditorModal .title {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
102
|
+
display: flex;
|
|
103
|
+
justify-content: space-between;
|
|
104
|
+
font-size: 14px;
|
|
105
|
+
color: #404040;
|
|
106
|
+
text-align: left;
|
|
107
|
+
background: #e0e0e0;
|
|
108
|
+
border: 0px;
|
|
109
|
+
border-radius: 5px 5px 0px 0px;
|
|
110
|
+
padding: 15px;
|
|
111
|
+
margin: 0px;
|
|
74
112
|
}
|
|
75
113
|
|
|
76
114
|
.EquationEditorModal-mobile .title {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
115
|
+
display: flex;
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
font-size: 14px;
|
|
118
|
+
color: #404040;
|
|
119
|
+
text-align: left;
|
|
120
|
+
background: #e0e0e0;
|
|
121
|
+
border: 0px;
|
|
122
|
+
border-radius: 5px 5px 0px 0px;
|
|
123
|
+
height: 30px;
|
|
124
|
+
padding: 15px;
|
|
125
|
+
margin: 0px;
|
|
88
126
|
}
|
|
89
127
|
|
|
90
128
|
.expertModeSwitch {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
129
|
+
display: flex;
|
|
130
|
+
flex-direction: row;
|
|
131
|
+
align-items: center;
|
|
94
132
|
}
|
|
95
133
|
|
|
96
134
|
.EquationEditorModal .expertModeSwitch .switch {
|
|
97
|
-
|
|
135
|
+
margin-left: 10px;
|
|
98
136
|
}
|
|
99
137
|
|
|
100
138
|
/* The switch - the box around the slider */
|
|
101
139
|
.EquationEditorModal .switch {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
140
|
+
position: relative;
|
|
141
|
+
display: inline-block;
|
|
142
|
+
width: 35px;
|
|
143
|
+
height: 22px;
|
|
144
|
+
margin-bottom: 0;
|
|
145
|
+
padding: 0;
|
|
108
146
|
}
|
|
109
147
|
|
|
110
148
|
/* Hide default HTML checkbox */
|
|
111
149
|
.EquationEditorModal .switch input {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
150
|
+
opacity: 0;
|
|
151
|
+
width: 0;
|
|
152
|
+
height: 0;
|
|
115
153
|
}
|
|
116
154
|
|
|
117
155
|
/* The slider */
|
|
118
156
|
.EquationEditorModal .slider {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
157
|
+
position: absolute;
|
|
158
|
+
cursor: pointer;
|
|
159
|
+
top: 0;
|
|
160
|
+
left: 0;
|
|
161
|
+
right: 0;
|
|
162
|
+
bottom: 0;
|
|
163
|
+
background-color: #ccc;
|
|
164
|
+
-webkit-transition: 0.4s;
|
|
165
|
+
transition: 0.4s;
|
|
128
166
|
}
|
|
129
167
|
|
|
130
168
|
.EquationEditorModal .slider:before {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
169
|
+
position: absolute;
|
|
170
|
+
content: "";
|
|
171
|
+
height: 14px;
|
|
172
|
+
width: 14px;
|
|
173
|
+
left: 4px;
|
|
174
|
+
bottom: 4px;
|
|
175
|
+
background-color: white;
|
|
176
|
+
-webkit-transition: 0.4s;
|
|
177
|
+
transition: 0.4s;
|
|
140
178
|
}
|
|
141
179
|
|
|
142
180
|
.EquationEditorModal input:checked + .slider {
|
|
143
|
-
|
|
181
|
+
background-color: #663676;
|
|
144
182
|
}
|
|
145
183
|
|
|
146
184
|
.EquationEditorModal input:focus + .slider {
|
|
147
|
-
|
|
185
|
+
box-shadow: 0 0 1px #2196f3;
|
|
148
186
|
}
|
|
149
187
|
|
|
150
188
|
.EquationEditorModal input:checked + .slider:before {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
189
|
+
-webkit-transform: translateX(13px);
|
|
190
|
+
-ms-transform: translateX(13px);
|
|
191
|
+
transform: translateX(13px);
|
|
154
192
|
}
|
|
155
193
|
|
|
156
194
|
/* Rounded sliders */
|
|
157
195
|
.EquationEditorModal .slider.round {
|
|
158
|
-
|
|
196
|
+
border-radius: 18px;
|
|
159
197
|
}
|
|
160
198
|
|
|
161
199
|
.EquationEditorModal .slider.round:before {
|
|
162
|
-
|
|
200
|
+
border-radius: 50%;
|
|
163
201
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import ReactDOM from "react-dom";
|
|
2
3
|
import EquationEditor from "./EquationEditor.jsx";
|
|
3
4
|
|
|
4
5
|
import "./EquationEditorModal.css";
|
|
@@ -11,6 +12,7 @@ export default class EquationEditorModal extends React.Component {
|
|
|
11
12
|
|
|
12
13
|
this.state = {
|
|
13
14
|
useExpertMode: GLOBAL_lastSelectedExpertMode,
|
|
15
|
+
animationReady: false,
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
this.handleCloseCallback = props.handleClose;
|
|
@@ -26,14 +28,114 @@ export default class EquationEditorModal extends React.Component {
|
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
componentDidMount() {
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Store current scroll position to prevent jumping
|
|
32
|
+
this.originalScrollTop =
|
|
33
|
+
window.pageYOffset || document.documentElement.scrollTop;
|
|
34
|
+
|
|
35
|
+
// Create portal container if it doesn't exist
|
|
36
|
+
this.ensurePortalContainer();
|
|
37
|
+
|
|
38
|
+
// Lock body scroll to prevent jumping in transform containers
|
|
39
|
+
this.lockBodyScroll();
|
|
40
|
+
|
|
41
|
+
// Enable animation after portal is ready (ensures smooth slide-in)
|
|
42
|
+
// Need multiple RAF frames for proper CSS animation timing
|
|
43
|
+
requestAnimationFrame(() => {
|
|
44
|
+
requestAnimationFrame(() => {
|
|
45
|
+
this.setState({ animationReady: true }, () => {
|
|
46
|
+
// Auto-focus after animation completes (0.3s CSS animation + buffer)
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
this.focusEquationEditor();
|
|
49
|
+
}, 400); // Wait for animation to complete
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
componentWillUnmount() {
|
|
56
|
+
// Hide portal immediately to prevent flash
|
|
57
|
+
if (this.portalContainer) {
|
|
58
|
+
this.portalContainer.style.visibility = "hidden";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Unlock body scroll and restore original scroll position
|
|
62
|
+
this.unlockBodyScroll();
|
|
63
|
+
|
|
64
|
+
// Clean up portal container after a small delay
|
|
65
|
+
if (this.createdPortalContainer && this.portalContainer) {
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
if (this.portalContainer && this.portalContainer.parentNode) {
|
|
68
|
+
document.body.removeChild(this.portalContainer);
|
|
69
|
+
}
|
|
70
|
+
}, 100);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
lockBodyScroll() {
|
|
75
|
+
// Store original overflow styles and scroll position
|
|
76
|
+
this.originalBodyOverflow = document.body.style.overflow;
|
|
77
|
+
this.originalDocumentOverflow = document.documentElement.style.overflow;
|
|
78
|
+
this.originalBodyPosition = document.body.style.position;
|
|
79
|
+
this.originalBodyTop = document.body.style.top;
|
|
80
|
+
this.originalBodyWidth = document.body.style.width;
|
|
81
|
+
|
|
82
|
+
// Get current scroll position
|
|
83
|
+
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
84
|
+
|
|
85
|
+
// Apply position: fixed to prevent scrolling while preserving position
|
|
86
|
+
document.body.style.position = "fixed";
|
|
87
|
+
document.body.style.top = `-${scrollTop}px`;
|
|
88
|
+
document.body.style.width = "100%";
|
|
89
|
+
document.body.style.overflow = "hidden";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
unlockBodyScroll() {
|
|
93
|
+
// Get the scroll position from the fixed top value
|
|
94
|
+
const scrollTop = Math.abs(parseInt(document.body.style.top) || 0);
|
|
95
|
+
|
|
96
|
+
// Restore original styles
|
|
97
|
+
document.body.style.position = this.originalBodyPosition || "";
|
|
98
|
+
document.body.style.top = this.originalBodyTop || "";
|
|
99
|
+
document.body.style.width = this.originalBodyWidth || "";
|
|
100
|
+
document.body.style.overflow = this.originalBodyOverflow || "";
|
|
101
|
+
document.documentElement.style.overflow =
|
|
102
|
+
this.originalDocumentOverflow || "";
|
|
103
|
+
|
|
104
|
+
// Restore scroll position smoothly
|
|
105
|
+
if (scrollTop > 0) {
|
|
106
|
+
window.scrollTo(0, scrollTop);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
ensurePortalContainer() {
|
|
111
|
+
// Look for existing portal container
|
|
112
|
+
this.portalContainer = document.getElementById(
|
|
113
|
+
"math-rich-input-modal-portal"
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if (!this.portalContainer) {
|
|
117
|
+
// Create new portal container
|
|
118
|
+
this.portalContainer = document.createElement("div");
|
|
119
|
+
this.portalContainer.id = "math-rich-input-modal-portal";
|
|
120
|
+
// Portal container should not interfere with content positioning
|
|
121
|
+
// Start invisible until animation is ready
|
|
122
|
+
this.portalContainer.style.cssText =
|
|
123
|
+
"position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 999990; visibility: hidden;";
|
|
124
|
+
document.body.appendChild(this.portalContainer);
|
|
125
|
+
this.createdPortalContainer = true;
|
|
126
|
+
}
|
|
34
127
|
}
|
|
35
128
|
|
|
36
129
|
componentDidUpdate(prevProps, prevState) {
|
|
130
|
+
// Show portal container when animation is ready
|
|
131
|
+
if (
|
|
132
|
+
!prevState.animationReady &&
|
|
133
|
+
this.state.animationReady &&
|
|
134
|
+
this.portalContainer
|
|
135
|
+
) {
|
|
136
|
+
this.portalContainer.style.visibility = "visible";
|
|
137
|
+
}
|
|
138
|
+
|
|
37
139
|
// Re-focus when expert mode changes
|
|
38
140
|
if (prevState.useExpertMode !== this.state.useExpertMode) {
|
|
39
141
|
setTimeout(() => {
|
|
@@ -46,25 +148,44 @@ export default class EquationEditorModal extends React.Component {
|
|
|
46
148
|
console.log("🔍 Focusing equation editor...");
|
|
47
149
|
if (this.equationEditor) {
|
|
48
150
|
console.log("🔍 EquationEditor ref found");
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
151
|
+
|
|
152
|
+
// Prevent scroll jumping during focus
|
|
153
|
+
const currentScrollTop =
|
|
154
|
+
window.pageYOffset || document.documentElement.scrollTop;
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
if (this.state.useExpertMode) {
|
|
158
|
+
// Focus textarea in expert mode
|
|
159
|
+
console.log("🔍 Expert mode - focusing latexInput");
|
|
160
|
+
if (this.equationEditor.latexInput) {
|
|
161
|
+
// Use preventScroll option if available
|
|
162
|
+
this.equationEditor.latexInput.focus({ preventScroll: true });
|
|
163
|
+
console.log("✅ LatexInput focused");
|
|
164
|
+
} else {
|
|
165
|
+
console.log("❌ LatexInput not found");
|
|
166
|
+
}
|
|
64
167
|
} else {
|
|
65
|
-
|
|
168
|
+
// Focus MathQuill in normal mode
|
|
169
|
+
console.log("🔍 Normal mode - focusing mathQuill");
|
|
170
|
+
if (this.equationEditor.mathQuill) {
|
|
171
|
+
this.equationEditor.mathQuill.focus();
|
|
172
|
+
console.log("✅ MathQuill focused");
|
|
173
|
+
} else {
|
|
174
|
+
console.log("❌ MathQuill not found");
|
|
175
|
+
}
|
|
66
176
|
}
|
|
177
|
+
} catch (error) {
|
|
178
|
+
console.warn("🔍 Focus failed:", error);
|
|
67
179
|
}
|
|
180
|
+
|
|
181
|
+
// Ensure scroll position hasn't changed
|
|
182
|
+
setTimeout(() => {
|
|
183
|
+
const newScrollTop =
|
|
184
|
+
window.pageYOffset || document.documentElement.scrollTop;
|
|
185
|
+
if (newScrollTop !== currentScrollTop) {
|
|
186
|
+
window.scrollTo(0, currentScrollTop);
|
|
187
|
+
}
|
|
188
|
+
}, 10);
|
|
68
189
|
} else {
|
|
69
190
|
console.log("❌ EquationEditor ref not found");
|
|
70
191
|
}
|
|
@@ -86,13 +207,25 @@ export default class EquationEditorModal extends React.Component {
|
|
|
86
207
|
let useClass = "EquationEditorModal";
|
|
87
208
|
if (this.isMobile()) useClass = "EquationEditorModal-mobile";
|
|
88
209
|
|
|
89
|
-
|
|
210
|
+
// Add support for disabling animations (useful for Svelte transitions)
|
|
211
|
+
if (this.props.disableAnimation) {
|
|
212
|
+
useClass += " no-animation";
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const modalContent = (
|
|
90
216
|
<>
|
|
91
217
|
<div
|
|
92
|
-
className=
|
|
218
|
+
className={`EquationEditorModal-background${
|
|
219
|
+
this.props.disableAnimation ? " no-animation" : ""
|
|
220
|
+
}`}
|
|
93
221
|
onClick={this.handleClose}
|
|
222
|
+
style={{ pointerEvents: "auto" }}
|
|
94
223
|
></div>
|
|
95
|
-
<div
|
|
224
|
+
<div
|
|
225
|
+
className={useClass}
|
|
226
|
+
ref={(r) => (this.modalDiv = r)}
|
|
227
|
+
style={{ pointerEvents: "auto" }}
|
|
228
|
+
>
|
|
96
229
|
{!this.isMobile() && (
|
|
97
230
|
<div className="title">
|
|
98
231
|
Equation Editor
|
|
@@ -120,5 +253,13 @@ export default class EquationEditorModal extends React.Component {
|
|
|
120
253
|
</div>
|
|
121
254
|
</>
|
|
122
255
|
);
|
|
256
|
+
|
|
257
|
+
// Use portal to render modal outside of parent container stacking context
|
|
258
|
+
if (this.portalContainer && this.state.animationReady) {
|
|
259
|
+
return ReactDOM.createPortal(modalContent, this.portalContainer);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Show nothing until portal and animation are ready (prevents flash)
|
|
263
|
+
return null;
|
|
123
264
|
}
|
|
124
265
|
}
|
package/src/MathRichInput.jsx
CHANGED
|
@@ -3115,6 +3115,7 @@ export default class MathRichInput extends React.Component {
|
|
|
3115
3115
|
handleClose={this.handleEquationEditorClose}
|
|
3116
3116
|
handleInsert={this.handleEquationEditorInsert}
|
|
3117
3117
|
latex={this.state.equationEditorLatex}
|
|
3118
|
+
disableAnimation={this.props.disableAnimation}
|
|
3118
3119
|
/>
|
|
3119
3120
|
)}
|
|
3120
3121
|
</>
|