@barocss/math-editor 0.5.0 → 0.6.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/API-SESSION.md +25 -1
- package/CHANGELOG.md +48 -0
- package/CLIPBOARD.md +54 -0
- package/EDITING-SCENARIOS.md +55 -20
- package/GETTING-STARTED.md +54 -0
- package/IMPLEMENTATION.md +10 -0
- package/KEYBOARD.md +41 -0
- package/LATEX-GUIDE.md +30 -2
- package/README.md +52 -10
- package/RELEASING.md +22 -8
- package/ROADMAP.md +106 -1
- package/STYLING.md +28 -1
- package/TEXT-EDITORS.md +157 -0
- package/VALIDATION.md +102 -0
- package/dist/dom/caret-geometry.js +1 -1
- package/dist/dom/help.d.ts +5 -0
- package/dist/dom/help.js +104 -0
- package/dist/dom/menu-position.js +4 -3
- package/dist/dom/readable-layout.d.ts +3 -0
- package/dist/dom/readable-layout.js +52 -0
- package/dist/dom/toolbar-catalog.d.ts +1 -1
- package/dist/dom/toolbar.d.ts +2 -0
- package/dist/dom/toolbar.js +8 -1
- package/dist/dom.d.ts +11 -1
- package/dist/dom.js +138 -15
- package/dist/enter-policy.js +1 -1
- package/dist/lines.d.ts +2 -0
- package/dist/lines.js +15 -0
- package/dist/locales/en.js +21 -3
- package/dist/locales/en.json +21 -3
- package/dist/locales/ko.js +21 -3
- package/dist/locales/ko.json +21 -3
- package/dist/math-editor-toolbar.js +2 -1
- package/dist/math-editor.d.ts +1 -0
- package/dist/math-editor.js +135 -39
- package/dist/model.d.ts +2 -0
- package/dist/model.js +23 -1
- package/dist/range.d.ts +10 -2
- package/dist/range.js +31 -6
- package/dist/selection-shortcuts.d.ts +13 -0
- package/dist/selection-shortcuts.js +35 -0
- package/dist/session.d.ts +1 -0
- package/dist/session.js +1 -1
- package/dist/symbols.d.ts +1 -1
- package/dist/symbols.js +1 -0
- package/dist/vertical-navigation.d.ts +5 -0
- package/dist/vertical-navigation.js +33 -0
- package/package.json +1 -1
- package/src/style.css +227 -57
package/dist/dom.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { followReadableMathLayout } from './dom/readable-layout.js';
|
|
2
|
+
import { attachMathHelp, requestMathHelp } from './dom/help.js';
|
|
1
3
|
import { mathRunSpacing } from './math-spacing.js';
|
|
2
4
|
import { mathLayout } from './math-layout.js';
|
|
5
|
+
import { wrapSelectionShortcut } from './selection-shortcuts.js';
|
|
3
6
|
import { transformRoot } from './root-transform.js';
|
|
4
7
|
import { structureEditingContext, changeContextFence } from './context-tools.js';
|
|
5
8
|
import { focusContextAction } from './dom/context-keyboard.js';
|
|
@@ -16,16 +19,16 @@ import { mountMathToolbar } from './dom/toolbar.js';
|
|
|
16
19
|
export { mountMathToolbar } from './dom/toolbar.js';
|
|
17
20
|
import { createMathSession, } from './session.js';
|
|
18
21
|
import { translate, mathLocaleDirection } from './i18n.js';
|
|
19
|
-
import { documentRows, isLiteralText, textNodes, setText, moveCaret, unwrapPrevious, unwrapEmptySlot, gridDeletionTarget, removeGrid, isGrid, toLatex, } from './model.js';
|
|
22
|
+
import { documentRows, isLiteralText, textNodes, setText, moveCaret, unwrapPrevious, unwrapNext, unwrapEmptySlot, gridDeletionTarget, removeGrid, isGrid, toLatex, } from './model.js';
|
|
20
23
|
import { activeGrid, activeMatrix, resizeMatrix } from './matrix.js';
|
|
21
24
|
import { MATH_MATRIX_CLIPBOARD_TYPE, parseMatrixFragment, matrixFragment, matrixFromTSV, matrixRangeBetween, resolveMatrixRange, extendMatrixRange, focusMatrixCell, } from './matrix-range.js';
|
|
22
|
-
import { joinPreviousLine } from './lines.js';
|
|
23
|
-
import {
|
|
25
|
+
import { joinPreviousLine, joinNextLine } from './lines.js';
|
|
26
|
+
import { createVerticalNavigation } from './vertical-navigation.js';
|
|
24
27
|
import { renderedCaretGeometry } from './dom/caret-geometry.js';
|
|
25
28
|
import { extendsMathSelection, nativeSelectionAnchor, createSelectionMenuState, textSelectionBounds, } from './dom/selection.js';
|
|
26
|
-
import { acceptSuggestion, findStateSuggestions, mathStructures } from './suggestions.js';
|
|
29
|
+
import { acceptSuggestion, findStateSuggestions, mathStructures, } from './suggestions.js';
|
|
27
30
|
import { tokenizeMathText, tokenIndexAt } from './tokens.js';
|
|
28
|
-
import { fragmentLatex, parseFragment, MATH_CLIPBOARD_TYPE, extendKeyboardRange, collapseKeyboardRange, resolveRange, copyRange, wrappingKinds, } from './range.js';
|
|
31
|
+
import { fragmentLatex, parseFragment, MATH_CLIPBOARD_TYPE, extendKeyboardRange, isTokenNavigationKey, collapseKeyboardRange, resolveRange, copyRange, wrappingKinds, } from './range.js';
|
|
29
32
|
/** Native DOM renderer. No React or framework runtime is imported by this module. */
|
|
30
33
|
export function mountMathEditor(host, initial = {}) {
|
|
31
34
|
const doc = host.ownerDocument;
|
|
@@ -75,6 +78,7 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
75
78
|
onClose: closeLatex,
|
|
76
79
|
});
|
|
77
80
|
};
|
|
81
|
+
const stopHelp = attachMathHelp(root, () => session.getSnapshot().locale);
|
|
78
82
|
const t = (value) => translate(session.getSnapshot().locale, value);
|
|
79
83
|
const currentInput = () => surface.querySelector('input');
|
|
80
84
|
const cancelDrag = () => {
|
|
@@ -87,6 +91,7 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
87
91
|
const notify = (key) => {
|
|
88
92
|
status.textContent = t(key);
|
|
89
93
|
};
|
|
94
|
+
const verticalNavigation = createVerticalNavigation();
|
|
90
95
|
const apply = (next) => {
|
|
91
96
|
editing = true;
|
|
92
97
|
selectedGrid = undefined;
|
|
@@ -102,12 +107,15 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
102
107
|
const candidates = () => {
|
|
103
108
|
const snapshot = session.getSnapshot(), state = snapshot.state, active = textNodes(state.document).find((n) => n.id === state.caret.id);
|
|
104
109
|
const result = findStateSuggestions(state, snapshot.locale);
|
|
105
|
-
if (
|
|
110
|
+
if (options.suggestionMenu === false ||
|
|
111
|
+
!editing ||
|
|
106
112
|
isLiteralText(state.document, state.caret.id) ||
|
|
107
113
|
snapshot.range ||
|
|
108
114
|
snapshot.matrixRange ||
|
|
109
115
|
dismissed === `${active.id}:${active.text}:${state.caret.start}`)
|
|
110
116
|
result.candidates = [];
|
|
117
|
+
else if (options.filterSuggestions)
|
|
118
|
+
result.candidates = [...options.filterSuggestions(result.candidates, result.query, state)];
|
|
111
119
|
return result;
|
|
112
120
|
};
|
|
113
121
|
const choose = (index) => {
|
|
@@ -167,12 +175,18 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
167
175
|
const itemRect = option.getBoundingClientRect();
|
|
168
176
|
const listRect = list.getBoundingClientRect();
|
|
169
177
|
const scaleY = listRect.height / list.offsetHeight || 1;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
178
|
+
list.scrollTop +=
|
|
179
|
+
(itemRect.top + itemRect.height / 2 - listRect.top) / scaleY -
|
|
180
|
+
list.clientTop -
|
|
181
|
+
list.clientHeight / 2;
|
|
174
182
|
};
|
|
175
183
|
const renderMenu = () => {
|
|
184
|
+
if (options.suggestionMenu === false) {
|
|
185
|
+
menu.hidden = true;
|
|
186
|
+
menu.replaceChildren();
|
|
187
|
+
currentInput()?.setAttribute('aria-expanded', 'false');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
176
190
|
syncMathTheme(root, menu);
|
|
177
191
|
const result = candidates(), input = currentInput();
|
|
178
192
|
menu.replaceChildren();
|
|
@@ -201,8 +215,9 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
201
215
|
const list = element('div', 'me-suggestions');
|
|
202
216
|
list.setAttribute('role', 'listbox');
|
|
203
217
|
list.setAttribute('aria-label', t('selection.toolbar'));
|
|
204
|
-
for (const item of mathStructures.filter((item) => wrappingKinds.includes(item.kind)
|
|
205
|
-
|
|
218
|
+
for (const item of mathStructures.filter((item) => wrappingKinds.includes(item.kind) &&
|
|
219
|
+
(!options.selectionKinds || options.selectionKinds.includes(item.kind)))) {
|
|
220
|
+
const button = suggestionButton(item.glyph, t(item.kind === 'fraction' ? 'selection.asNumerator' : item.label), t(item.detail));
|
|
206
221
|
button.setAttribute('aria-selected', String(list.children.length === candidateIndex));
|
|
207
222
|
button.disabled = !canWrap;
|
|
208
223
|
button.setAttribute('aria-label', translate(snapshot.locale, 'selection.wrap', { kind: t(item.label) }));
|
|
@@ -212,6 +227,18 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
212
227
|
perform({ type: 'structure', kind: item.kind });
|
|
213
228
|
};
|
|
214
229
|
list.append(button);
|
|
230
|
+
if (item.kind === 'fraction') {
|
|
231
|
+
const denominator = suggestionButton('□/▧', t('selection.asDenominator'), t(item.detail));
|
|
232
|
+
denominator.setAttribute('aria-selected', String(list.children.length === candidateIndex));
|
|
233
|
+
denominator.setAttribute('aria-label', t('selection.asDenominator'));
|
|
234
|
+
denominator.disabled = !canWrap;
|
|
235
|
+
denominator.onclick = () => {
|
|
236
|
+
if (!snapshot.range)
|
|
237
|
+
session.selectRange(selectedRange);
|
|
238
|
+
perform({ type: 'structure', kind: 'fraction', fractionSlot: 'denominator' });
|
|
239
|
+
};
|
|
240
|
+
list.append(denominator);
|
|
241
|
+
}
|
|
215
242
|
}
|
|
216
243
|
menu.append(list);
|
|
217
244
|
const selected = surface.querySelectorAll('.me-dom-selected, .me-range-highlight');
|
|
@@ -475,7 +502,12 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
475
502
|
dismissed = '';
|
|
476
503
|
apply(replaceToken());
|
|
477
504
|
});
|
|
478
|
-
input.onkeydown =
|
|
505
|
+
input.onkeydown = (event) => {
|
|
506
|
+
// Native arrow movement can precede select/keyup, especially during key repeat.
|
|
507
|
+
// Read the live caret before testing token and structure boundaries.
|
|
508
|
+
syncCaret();
|
|
509
|
+
keydown(event);
|
|
510
|
+
};
|
|
479
511
|
run.append(input);
|
|
480
512
|
}
|
|
481
513
|
else {
|
|
@@ -663,6 +695,38 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
663
695
|
}
|
|
664
696
|
return false;
|
|
665
697
|
}
|
|
698
|
+
function tokenNavigation(event) {
|
|
699
|
+
if (composing || !isTokenNavigationKey(event, win.navigator.platform))
|
|
700
|
+
return false;
|
|
701
|
+
const snapshot = session.getSnapshot();
|
|
702
|
+
if (snapshot.matrixRange)
|
|
703
|
+
return false;
|
|
704
|
+
event.preventDefault();
|
|
705
|
+
const state = snapshot.state;
|
|
706
|
+
const selection = snapshot.range ??
|
|
707
|
+
(state.caret.start !== state.caret.end
|
|
708
|
+
? {
|
|
709
|
+
anchor: { id: state.caret.id, offset: state.caret.start },
|
|
710
|
+
focus: { id: state.caret.id, offset: state.caret.end },
|
|
711
|
+
}
|
|
712
|
+
: undefined);
|
|
713
|
+
if (event.shiftKey) {
|
|
714
|
+
session.selectRange(extendKeyboardRange(state, selection, event.key, 'token'));
|
|
715
|
+
surface.focus();
|
|
716
|
+
}
|
|
717
|
+
else {
|
|
718
|
+
const point = collapseKeyboardRange(state.document, selection, event.key) ??
|
|
719
|
+
extendKeyboardRange(state, undefined, event.key, 'token').focus;
|
|
720
|
+
editing = true;
|
|
721
|
+
session.select({
|
|
722
|
+
id: point.id,
|
|
723
|
+
start: point.offset,
|
|
724
|
+
end: point.offset,
|
|
725
|
+
affinity: event.key === 'ArrowLeft' ? 'forward' : 'backward',
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
return true;
|
|
729
|
+
}
|
|
666
730
|
function keyboardSelect(event) {
|
|
667
731
|
if (composing ||
|
|
668
732
|
event.isComposing ||
|
|
@@ -678,6 +742,18 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
678
742
|
surface.focus();
|
|
679
743
|
return true;
|
|
680
744
|
}
|
|
745
|
+
function directSelectionKey(event) {
|
|
746
|
+
if (composing || event.isComposing)
|
|
747
|
+
return false;
|
|
748
|
+
const snapshot = session.getSnapshot();
|
|
749
|
+
const next = wrapSelectionShortcut(snapshot.state, snapshot.range, event);
|
|
750
|
+
if (!next)
|
|
751
|
+
return false;
|
|
752
|
+
event.preventDefault();
|
|
753
|
+
if (next !== snapshot.state)
|
|
754
|
+
apply(next);
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
681
757
|
function selectionMenuKey(event) {
|
|
682
758
|
if (menu.hidden ||
|
|
683
759
|
menu.dataset.kind !== 'selection' ||
|
|
@@ -713,6 +789,12 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
713
789
|
return true;
|
|
714
790
|
}
|
|
715
791
|
function keydown(event) {
|
|
792
|
+
if (!['ArrowUp', 'ArrowDown', 'Escape'].includes(event.key) ||
|
|
793
|
+
event.shiftKey ||
|
|
794
|
+
event.altKey ||
|
|
795
|
+
event.ctrlKey ||
|
|
796
|
+
event.metaKey)
|
|
797
|
+
verticalNavigation.reset();
|
|
716
798
|
event.stopPropagation();
|
|
717
799
|
if (event.isComposing || composing)
|
|
718
800
|
return;
|
|
@@ -739,7 +821,9 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
739
821
|
return;
|
|
740
822
|
}
|
|
741
823
|
if (matrixSelectionKey(event) ||
|
|
824
|
+
tokenNavigation(event) ||
|
|
742
825
|
keyboardSelect(event) ||
|
|
826
|
+
directSelectionKey(event) ||
|
|
743
827
|
selectionMenuKey(event) ||
|
|
744
828
|
keyboardCollapse(event))
|
|
745
829
|
return;
|
|
@@ -789,6 +873,17 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
789
873
|
}
|
|
790
874
|
return;
|
|
791
875
|
}
|
|
876
|
+
const acceptsSuggestion = event.key === 'Enter' &&
|
|
877
|
+
!event.shiftKey &&
|
|
878
|
+
result.candidates.length > 0 &&
|
|
879
|
+
((!result.candidates[0].wrapOperand &&
|
|
880
|
+
!result.candidates[0].transformRootId &&
|
|
881
|
+
!result.candidates[0].transformFenceId) ||
|
|
882
|
+
operandMenuKey === `${active.id}:${active.text}:${c.start}`);
|
|
883
|
+
if (options.onEditKeyDown?.(event, snapshot, acceptsSuggestion)) {
|
|
884
|
+
event.preventDefault();
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
792
887
|
if (event.key === 'Enter') {
|
|
793
888
|
event.preventDefault();
|
|
794
889
|
const action = mathEnterAction({
|
|
@@ -819,7 +914,7 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
819
914
|
if (activeGrid(state) &&
|
|
820
915
|
event.altKey &&
|
|
821
916
|
event.shiftKey &&
|
|
822
|
-
['ArrowUp', '
|
|
917
|
+
['ArrowUp', 'Backspace'].includes(event.key)) {
|
|
823
918
|
event.preventDefault();
|
|
824
919
|
apply(resizeMatrix(state, event.key === 'ArrowUp' ? 'row' : 'column', 'delete'));
|
|
825
920
|
return;
|
|
@@ -858,7 +953,7 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
858
953
|
}
|
|
859
954
|
if (!event.shiftKey && ['ArrowUp', 'ArrowDown'].includes(event.key)) {
|
|
860
955
|
const direction = event.key === 'ArrowUp' ? -1 : 1;
|
|
861
|
-
const next =
|
|
956
|
+
const next = verticalNavigation.move(state, direction, renderedCaretGeometry(surface));
|
|
862
957
|
if (next !== state) {
|
|
863
958
|
event.preventDefault();
|
|
864
959
|
session.select(next.caret);
|
|
@@ -896,6 +991,14 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
896
991
|
}
|
|
897
992
|
return;
|
|
898
993
|
}
|
|
994
|
+
if (event.key === 'Delete' && c.end === active.text.length) {
|
|
995
|
+
const joined = joinNextLine(state);
|
|
996
|
+
const next = joined !== state ? joined : unwrapNext(state);
|
|
997
|
+
if (next !== state) {
|
|
998
|
+
event.preventDefault();
|
|
999
|
+
apply(next);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
899
1002
|
if (event.key === 'Backspace' && c.start === 0) {
|
|
900
1003
|
const joined = joinPreviousLine(state), next = joined !== state ? joined : unwrapPrevious(state);
|
|
901
1004
|
if (next !== state) {
|
|
@@ -945,6 +1048,7 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
945
1048
|
};
|
|
946
1049
|
};
|
|
947
1050
|
surface.onpointerdown = (event) => {
|
|
1051
|
+
verticalNavigation.reset();
|
|
948
1052
|
if (event.button || composing || drag || event.target.closest('.me-line-number'))
|
|
949
1053
|
return;
|
|
950
1054
|
const point = pointAt(event.clientX, event.clientY);
|
|
@@ -1050,6 +1154,8 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1050
1154
|
doc.addEventListener('pointercancel', cancelPointer, true);
|
|
1051
1155
|
win.addEventListener('blur', cancelDrag);
|
|
1052
1156
|
surface.onkeydown = (event) => {
|
|
1157
|
+
if (event.target !== currentInput())
|
|
1158
|
+
verticalNavigation.reset();
|
|
1053
1159
|
if (event.target === currentInput())
|
|
1054
1160
|
return;
|
|
1055
1161
|
event.stopPropagation();
|
|
@@ -1063,7 +1169,9 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1063
1169
|
return;
|
|
1064
1170
|
}
|
|
1065
1171
|
if (matrixSelectionKey(event) ||
|
|
1172
|
+
tokenNavigation(event) ||
|
|
1066
1173
|
keyboardSelect(event) ||
|
|
1174
|
+
directSelectionKey(event) ||
|
|
1067
1175
|
selectionMenuKey(event) ||
|
|
1068
1176
|
keyboardCollapse(event))
|
|
1069
1177
|
return;
|
|
@@ -1129,6 +1237,12 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1129
1237
|
if (composing)
|
|
1130
1238
|
return;
|
|
1131
1239
|
const data = event.clipboardData, fragment = parseFragment(data?.getData(MATH_CLIPBOARD_TYPE) ?? ''), text = data?.getData('text/plain') ?? '';
|
|
1240
|
+
if (data?.getData(MATH_CLIPBOARD_TYPE) && !fragment) {
|
|
1241
|
+
event.preventDefault();
|
|
1242
|
+
event.stopPropagation();
|
|
1243
|
+
notify('clipboard.invalid');
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1132
1246
|
const matrixSource = data?.getData(MATH_MATRIX_CLIPBOARD_TYPE) ?? '';
|
|
1133
1247
|
const matrix = matrixSource ? parseMatrixFragment(matrixSource) : matrixFromTSV(text);
|
|
1134
1248
|
const snapshot = session.getSnapshot();
|
|
@@ -1189,6 +1303,8 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1189
1303
|
toolbar?.setDisabled(composing);
|
|
1190
1304
|
};
|
|
1191
1305
|
const unsubscribe = session.subscribe((snapshot, changed) => {
|
|
1306
|
+
if (changed)
|
|
1307
|
+
verticalNavigation.reset();
|
|
1192
1308
|
if (changed) {
|
|
1193
1309
|
cancelDrag();
|
|
1194
1310
|
selectionMenu.reset();
|
|
@@ -1197,6 +1313,7 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1197
1313
|
if (changed)
|
|
1198
1314
|
options.onChange?.(snapshot.state.document, snapshot.latex);
|
|
1199
1315
|
});
|
|
1316
|
+
const stopReadableLayout = followReadableMathLayout(surface);
|
|
1200
1317
|
const stopPosition = followMathMenuPosition(root, () => {
|
|
1201
1318
|
if (!menu.hidden)
|
|
1202
1319
|
drawMenu();
|
|
@@ -1205,6 +1322,10 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1205
1322
|
render();
|
|
1206
1323
|
return {
|
|
1207
1324
|
session,
|
|
1325
|
+
showHelp() {
|
|
1326
|
+
if (!destroyed)
|
|
1327
|
+
requestMathHelp(root);
|
|
1328
|
+
},
|
|
1208
1329
|
focus() {
|
|
1209
1330
|
editing = true;
|
|
1210
1331
|
render();
|
|
@@ -1223,10 +1344,12 @@ export function mountMathEditor(host, initial = {}) {
|
|
|
1223
1344
|
destroyed = true;
|
|
1224
1345
|
cancelDrag();
|
|
1225
1346
|
unsubscribe();
|
|
1347
|
+
stopHelp();
|
|
1226
1348
|
latexPanel?.destroy();
|
|
1227
1349
|
toolbar?.destroy();
|
|
1228
1350
|
root.removeEventListener('focusout', blur);
|
|
1229
1351
|
stopPosition();
|
|
1352
|
+
stopReadableLayout();
|
|
1230
1353
|
doc.removeEventListener('pointermove', movePointer, true);
|
|
1231
1354
|
doc.removeEventListener('pointerup', endPointer, true);
|
|
1232
1355
|
doc.removeEventListener('pointercancel', cancelPointer, true);
|
package/dist/enter-policy.js
CHANGED
|
@@ -4,7 +4,7 @@ export function mathEnterAction(context) {
|
|
|
4
4
|
return 'suggestion';
|
|
5
5
|
if (context.gridKind && context.shiftKey)
|
|
6
6
|
return 'grid-row';
|
|
7
|
-
if (context.mode === 'inline' || context.behavior === 'commit')
|
|
7
|
+
if (context.mode === 'inline' || (context.behavior === 'commit' && !context.shiftKey))
|
|
8
8
|
return 'commit';
|
|
9
9
|
if (context.gridKind)
|
|
10
10
|
return context.gridKind === 'matrix' ? 'none' : 'grid-row';
|
package/dist/lines.d.ts
CHANGED
|
@@ -3,4 +3,6 @@ import { type MathState } from './model.js';
|
|
|
3
3
|
export declare function splitLine(state: MathState): MathState;
|
|
4
4
|
/** Backspace at the start of a top-level line merges it with the previous line. */
|
|
5
5
|
export declare function joinPreviousLine(state: MathState): MathState;
|
|
6
|
+
/** Delete at the end of a top-level line joins the following line without moving the caret. */
|
|
7
|
+
export declare function joinNextLine(state: MathState): MathState;
|
|
6
8
|
export declare function moveLineVertical(state: MathState, direction: -1 | 1): MathState;
|
package/dist/lines.js
CHANGED
|
@@ -39,6 +39,21 @@ export function joinPreviousLine(state) {
|
|
|
39
39
|
delete document.additionalLines;
|
|
40
40
|
return { document, caret: { id: tail.id, start: offset, end: offset } };
|
|
41
41
|
}
|
|
42
|
+
/** Delete at the end of a top-level line joins the following line without moving the caret. */
|
|
43
|
+
export function joinNextLine(state) {
|
|
44
|
+
if (state.caret.start !== state.caret.end)
|
|
45
|
+
return state;
|
|
46
|
+
const lines = documentRows(state.document);
|
|
47
|
+
const index = lines.findIndex((line) => line.children.at(-1)?.id === state.caret.id);
|
|
48
|
+
const tail = lines[index]?.children.at(-1);
|
|
49
|
+
const head = lines[index + 1]?.children[0];
|
|
50
|
+
if (index < 0 ||
|
|
51
|
+
tail?.type !== 'text' ||
|
|
52
|
+
head?.type !== 'text' ||
|
|
53
|
+
state.caret.end !== tail.text.length)
|
|
54
|
+
return state;
|
|
55
|
+
return joinPreviousLine({ ...state, caret: { id: head.id, start: 0, end: 0 } });
|
|
56
|
+
}
|
|
42
57
|
export function moveLineVertical(state, direction) {
|
|
43
58
|
const lines = documentRows(state.document);
|
|
44
59
|
const index = lines.findIndex((line) => line.children.some((node) => node.type === 'text' && node.id === state.caret.id));
|
package/dist/locales/en.js
CHANGED
|
@@ -92,7 +92,8 @@ export default {
|
|
|
92
92
|
"grid.addColumn": "Add column",
|
|
93
93
|
"grid.deleteColumn": "Delete column",
|
|
94
94
|
"grid.deleteRowShortcut": "Delete row: Alt(⌥)+Shift+↑",
|
|
95
|
-
"grid.deleteColumnShortcut": "Delete column: Alt(⌥)+Shift
|
|
95
|
+
"grid.deleteColumnShortcut": "Delete column: Alt(⌥)+Shift+Backspace",
|
|
96
|
+
"clipboard.invalid": "The copied formula data is invalid. The formula was not changed.",
|
|
96
97
|
"clipboard.cut": "Selected math cut.",
|
|
97
98
|
"clipboard.copied": "Selected math copied as structure and LaTeX.",
|
|
98
99
|
"clipboard.pasted": "Pasted.",
|
|
@@ -101,13 +102,15 @@ export default {
|
|
|
101
102
|
"grid.selectionHint": "Structure selected · Backspace/Delete to remove · Esc to cancel",
|
|
102
103
|
"selection.toolbar": "Wrap selected math",
|
|
103
104
|
"selection.highlighted": "Wrap highlighted range",
|
|
105
|
+
"selection.asNumerator": "Use as numerator",
|
|
106
|
+
"selection.asDenominator": "Use as denominator",
|
|
104
107
|
"selection.singleRowRequired": "Select a range within one row.",
|
|
105
108
|
"suggestion.label": "Math suggestions",
|
|
106
109
|
"suggestion.composing": "Composing · Choose after committing",
|
|
107
110
|
"suggestion.keyboardHint": "↑ ↓ to choose · Enter to apply",
|
|
108
111
|
"suggestion.imeHint": "Suggestion preview · Enter and arrows are reserved for the IME",
|
|
109
112
|
"suggestion.keepSource": "Keep typing, or use Space / Esc to keep the source",
|
|
110
|
-
"matrix.keyboardHint": "Shift+Enter add row · Shift+Space add column · Alt(⌥)+Shift+↑ delete row · Alt(⌥)+Shift
|
|
113
|
+
"matrix.keyboardHint": "Shift+Enter add row · Shift+Space add column · Alt(⌥)+Shift+↑ delete row · Alt(⌥)+Shift+Backspace delete column",
|
|
111
114
|
"aligned.inputHint": "Left: left-hand side · Right: start with =",
|
|
112
115
|
"cases.inputHint": "Left: expression · Right: condition",
|
|
113
116
|
"grid.keyboardHint": "Enter add row · Alt(⌥)+Shift+↑ delete row",
|
|
@@ -155,6 +158,7 @@ export default {
|
|
|
155
158
|
"template.detail": "Editable math template",
|
|
156
159
|
"template.quadratic": "Quadratic formula",
|
|
157
160
|
"template.pythagorean": "Pythagorean theorem",
|
|
161
|
+
"symbol.prime": "Prime",
|
|
158
162
|
"symbol.degree": "Degree",
|
|
159
163
|
"symbol.angle": "Angle",
|
|
160
164
|
"symbol.plus": "Plus",
|
|
@@ -353,7 +357,21 @@ export default {
|
|
|
353
357
|
"context.indexedRoot": "Indexed root",
|
|
354
358
|
"context.fenceKeyboardHint": "F6: tools · ← →: choose · Enter: apply · Esc: back to input",
|
|
355
359
|
"suggestion.transformFence": "Change brackets: {kind}",
|
|
356
|
-
"suggestion.transformFenceDetail": "Keep the enclosed formula and cursor position"
|
|
360
|
+
"suggestion.transformFenceDetail": "Keep the enclosed formula and cursor position",
|
|
361
|
+
"help.title": "Keyboard & clipboard help",
|
|
362
|
+
"help.intro": "Keep typing with these controls. Close help to return to your formula.",
|
|
363
|
+
"help.units": "Move by a variable, number or whole structure. Add Shift to extend selection. Inside a slot, reach the current token edge before leaving the structure.",
|
|
364
|
+
"help.slots": "Move to the next or previous editable slot.",
|
|
365
|
+
"help.select": "Extend the formula selection.",
|
|
366
|
+
"help.wrap": "With math selected: wrap in brackets, absolute value, a fraction, a power or a subscript.",
|
|
367
|
+
"help.suggestions": "Open suggestions and available transformations, even without a toolbar.",
|
|
368
|
+
"help.menu": "Choose a suggestion, apply it, or dismiss the menu.",
|
|
369
|
+
"help.clipboard": "Copy, cut or paste. Editor data preserves structure when the browser retains it. Ordinary text pastes literally.",
|
|
370
|
+
"help.latex": "Open Paste as LaTeX. Paste the source, then Ctrl/Cmd+Enter to insert. Invalid input leaves the formula unchanged.",
|
|
371
|
+
"help.history": "Undo or redo an edit.",
|
|
372
|
+
"help.lines": "Enter follows the host/mode policy. Shift+Enter adds a grid row or a block line. Inline mode never adds a top-level formula line.",
|
|
373
|
+
"help.open": "Open this help while the formula has focus.",
|
|
374
|
+
"help.platform": "Cmd on macOS, Ctrl on Windows/Linux. Alt is Option on macOS. Some keyboards require Fn+F1. Host or OS shortcuts can take precedence."
|
|
357
375
|
},
|
|
358
376
|
"aliases": {}
|
|
359
377
|
};
|
package/dist/locales/en.json
CHANGED
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
"grid.addColumn": "Add column",
|
|
92
92
|
"grid.deleteColumn": "Delete column",
|
|
93
93
|
"grid.deleteRowShortcut": "Delete row: Alt(⌥)+Shift+↑",
|
|
94
|
-
"grid.deleteColumnShortcut": "Delete column: Alt(⌥)+Shift
|
|
94
|
+
"grid.deleteColumnShortcut": "Delete column: Alt(⌥)+Shift+Backspace",
|
|
95
|
+
"clipboard.invalid": "The copied formula data is invalid. The formula was not changed.",
|
|
95
96
|
"clipboard.cut": "Selected math cut.",
|
|
96
97
|
"clipboard.copied": "Selected math copied as structure and LaTeX.",
|
|
97
98
|
"clipboard.pasted": "Pasted.",
|
|
@@ -100,13 +101,15 @@
|
|
|
100
101
|
"grid.selectionHint": "Structure selected · Backspace/Delete to remove · Esc to cancel",
|
|
101
102
|
"selection.toolbar": "Wrap selected math",
|
|
102
103
|
"selection.highlighted": "Wrap highlighted range",
|
|
104
|
+
"selection.asNumerator": "Use as numerator",
|
|
105
|
+
"selection.asDenominator": "Use as denominator",
|
|
103
106
|
"selection.singleRowRequired": "Select a range within one row.",
|
|
104
107
|
"suggestion.label": "Math suggestions",
|
|
105
108
|
"suggestion.composing": "Composing · Choose after committing",
|
|
106
109
|
"suggestion.keyboardHint": "↑ ↓ to choose · Enter to apply",
|
|
107
110
|
"suggestion.imeHint": "Suggestion preview · Enter and arrows are reserved for the IME",
|
|
108
111
|
"suggestion.keepSource": "Keep typing, or use Space / Esc to keep the source",
|
|
109
|
-
"matrix.keyboardHint": "Shift+Enter add row · Shift+Space add column · Alt(⌥)+Shift+↑ delete row · Alt(⌥)+Shift
|
|
112
|
+
"matrix.keyboardHint": "Shift+Enter add row · Shift+Space add column · Alt(⌥)+Shift+↑ delete row · Alt(⌥)+Shift+Backspace delete column",
|
|
110
113
|
"aligned.inputHint": "Left: left-hand side · Right: start with =",
|
|
111
114
|
"cases.inputHint": "Left: expression · Right: condition",
|
|
112
115
|
"grid.keyboardHint": "Enter add row · Alt(⌥)+Shift+↑ delete row",
|
|
@@ -154,6 +157,7 @@
|
|
|
154
157
|
"template.detail": "Editable math template",
|
|
155
158
|
"template.quadratic": "Quadratic formula",
|
|
156
159
|
"template.pythagorean": "Pythagorean theorem",
|
|
160
|
+
"symbol.prime": "Prime",
|
|
157
161
|
"symbol.degree": "Degree",
|
|
158
162
|
"symbol.angle": "Angle",
|
|
159
163
|
"symbol.plus": "Plus",
|
|
@@ -352,7 +356,21 @@
|
|
|
352
356
|
"context.indexedRoot": "Indexed root",
|
|
353
357
|
"context.fenceKeyboardHint": "F6: tools · ← →: choose · Enter: apply · Esc: back to input",
|
|
354
358
|
"suggestion.transformFence": "Change brackets: {kind}",
|
|
355
|
-
"suggestion.transformFenceDetail": "Keep the enclosed formula and cursor position"
|
|
359
|
+
"suggestion.transformFenceDetail": "Keep the enclosed formula and cursor position",
|
|
360
|
+
"help.title": "Keyboard & clipboard help",
|
|
361
|
+
"help.intro": "Keep typing with these controls. Close help to return to your formula.",
|
|
362
|
+
"help.units": "Move by a variable, number or whole structure. Add Shift to extend selection. Inside a slot, reach the current token edge before leaving the structure.",
|
|
363
|
+
"help.slots": "Move to the next or previous editable slot.",
|
|
364
|
+
"help.select": "Extend the formula selection.",
|
|
365
|
+
"help.wrap": "With math selected: wrap in brackets, absolute value, a fraction, a power or a subscript.",
|
|
366
|
+
"help.suggestions": "Open suggestions and available transformations, even without a toolbar.",
|
|
367
|
+
"help.menu": "Choose a suggestion, apply it, or dismiss the menu.",
|
|
368
|
+
"help.clipboard": "Copy, cut or paste. Editor data preserves structure when the browser retains it. Ordinary text pastes literally.",
|
|
369
|
+
"help.latex": "Open Paste as LaTeX. Paste the source, then Ctrl/Cmd+Enter to insert. Invalid input leaves the formula unchanged.",
|
|
370
|
+
"help.history": "Undo or redo an edit.",
|
|
371
|
+
"help.lines": "Enter follows the host/mode policy. Shift+Enter adds a grid row or a block line. Inline mode never adds a top-level formula line.",
|
|
372
|
+
"help.open": "Open this help while the formula has focus.",
|
|
373
|
+
"help.platform": "Cmd on macOS, Ctrl on Windows/Linux. Alt is Option on macOS. Some keyboards require Fn+F1. Host or OS shortcuts can take precedence."
|
|
356
374
|
},
|
|
357
375
|
"aliases": {}
|
|
358
376
|
}
|
package/dist/locales/ko.js
CHANGED
|
@@ -92,7 +92,8 @@ export default {
|
|
|
92
92
|
"grid.addColumn": "열 추가",
|
|
93
93
|
"grid.deleteColumn": "열 삭제",
|
|
94
94
|
"grid.deleteRowShortcut": "행 삭제: Alt(⌥)+Shift+↑",
|
|
95
|
-
"grid.deleteColumnShortcut": "열 삭제: Alt(⌥)+Shift
|
|
95
|
+
"grid.deleteColumnShortcut": "열 삭제: Alt(⌥)+Shift+Backspace",
|
|
96
|
+
"clipboard.invalid": "복사한 수식 데이터가 올바르지 않습니다. 기존 수식은 유지됩니다.",
|
|
96
97
|
"clipboard.cut": "선택한 수식을 잘라냈습니다.",
|
|
97
98
|
"clipboard.copied": "선택한 수식을 구조와 LaTeX로 복사했습니다.",
|
|
98
99
|
"clipboard.pasted": "붙여넣었습니다.",
|
|
@@ -101,13 +102,15 @@ export default {
|
|
|
101
102
|
"grid.selectionHint": "수식 구조 전체 선택 · Backspace/Delete로 삭제 · Esc로 취소",
|
|
102
103
|
"selection.toolbar": "선택한 수식 감싸기",
|
|
103
104
|
"selection.highlighted": "강조된 범위 감싸기",
|
|
105
|
+
"selection.asNumerator": "분자로 넣기",
|
|
106
|
+
"selection.asDenominator": "분모로 넣기",
|
|
104
107
|
"selection.singleRowRequired": "한 줄 안의 범위를 선택해 주세요.",
|
|
105
108
|
"suggestion.label": "수식 추천",
|
|
106
109
|
"suggestion.composing": "한글 조합 중 · 확정 후 선택",
|
|
107
110
|
"suggestion.keyboardHint": "↑ ↓ 선택 · Enter 적용",
|
|
108
111
|
"suggestion.imeHint": "후보 미리보기 · Enter와 방향키는 한글 입력에 사용됩니다",
|
|
109
112
|
"suggestion.keepSource": "계속 입력하거나 Space · Esc로 원문 유지",
|
|
110
|
-
"matrix.keyboardHint": "Shift+Enter 행 추가 · Shift+Space 열 추가 · Alt(⌥)+Shift+↑ 행 삭제 · Alt(⌥)+Shift
|
|
113
|
+
"matrix.keyboardHint": "Shift+Enter 행 추가 · Shift+Space 열 추가 · Alt(⌥)+Shift+↑ 행 삭제 · Alt(⌥)+Shift+Backspace 열 삭제",
|
|
111
114
|
"aligned.inputHint": "왼쪽: 좌변 · 오른쪽: =부터 입력",
|
|
112
115
|
"cases.inputHint": "왼쪽: 식 · 오른쪽: 조건",
|
|
113
116
|
"grid.keyboardHint": "Enter 행 추가 · Alt(⌥)+Shift+↑ 행 삭제",
|
|
@@ -155,6 +158,7 @@ export default {
|
|
|
155
158
|
"template.detail": "편집 가능한 수식 템플릿",
|
|
156
159
|
"template.quadratic": "근의 공식",
|
|
157
160
|
"template.pythagorean": "피타고라스 정리",
|
|
161
|
+
"symbol.prime": "프라임",
|
|
158
162
|
"symbol.degree": "도",
|
|
159
163
|
"symbol.angle": "각 기호",
|
|
160
164
|
"symbol.plus": "더하기",
|
|
@@ -353,7 +357,21 @@ export default {
|
|
|
353
357
|
"context.indexedRoot": "n제곱근",
|
|
354
358
|
"context.fenceKeyboardHint": "F6: 도구로 이동 · ← →: 선택 · Enter: 적용 · Esc: 입력으로",
|
|
355
359
|
"suggestion.transformFence": "괄호 변경: {kind}",
|
|
356
|
-
"suggestion.transformFenceDetail": "안의 수식과 커서 위치를 유지합니다"
|
|
360
|
+
"suggestion.transformFenceDetail": "안의 수식과 커서 위치를 유지합니다",
|
|
361
|
+
"help.title": "단축키와 복사·붙여넣기",
|
|
362
|
+
"help.intro": "키보드로 수식을 편집하는 방법입니다. 도움말을 닫으면 수식으로 돌아갑니다.",
|
|
363
|
+
"help.units": "변수·숫자·구조 단위로 이동합니다. Shift를 함께 누르면 선택합니다. 구조 안에서는 현재 항목의 경계로 이동한 뒤 구조 밖으로 나갑니다.",
|
|
364
|
+
"help.slots": "다음 또는 이전 입력 칸으로 이동합니다.",
|
|
365
|
+
"help.select": "수식의 선택 범위를 늘립니다.",
|
|
366
|
+
"help.wrap": "수식을 선택한 상태에서 괄호·절대값·분수·지수·아래첨자로 감쌉니다.",
|
|
367
|
+
"help.suggestions": "툴바 없이도 제안 목록과 가능한 변형을 엽니다.",
|
|
368
|
+
"help.menu": "제안을 고르고 적용하거나 목록을 닫습니다.",
|
|
369
|
+
"help.clipboard": "복사·잘라내기·붙여넣기입니다. 브라우저가 편집기 데이터를 유지하면 구조도 보존됩니다. 일반 텍스트는 글자로 붙여넣습니다.",
|
|
370
|
+
"help.latex": "LaTeX 붙여넣기를 엽니다. 원문을 붙여넣고 Ctrl/Cmd+Enter로 삽입합니다. 잘못된 입력은 기존 수식을 바꾸지 않습니다.",
|
|
371
|
+
"help.history": "편집을 실행 취소하거나 다시 실행합니다.",
|
|
372
|
+
"help.lines": "Enter는 모드와 연동 설정을 따릅니다. Shift+Enter는 행렬의 행 또는 블록 수식의 줄을 추가합니다. 인라인 모드는 수식의 바깥 줄을 추가하지 않습니다.",
|
|
373
|
+
"help.open": "수식에 포커스가 있을 때 도움말을 엽니다.",
|
|
374
|
+
"help.platform": "macOS에서는 Cmd, Windows/Linux에서는 Ctrl을 사용합니다. macOS의 Alt는 Option입니다. 일부 키보드는 Fn+F1이 필요합니다. 운영체제나 연동 편집기의 단축키가 우선할 수 있습니다."
|
|
357
375
|
},
|
|
358
376
|
"aliases": {
|
|
359
377
|
"function-sin": ["사인"],
|
package/dist/locales/ko.json
CHANGED
|
@@ -91,7 +91,8 @@
|
|
|
91
91
|
"grid.addColumn": "열 추가",
|
|
92
92
|
"grid.deleteColumn": "열 삭제",
|
|
93
93
|
"grid.deleteRowShortcut": "행 삭제: Alt(⌥)+Shift+↑",
|
|
94
|
-
"grid.deleteColumnShortcut": "열 삭제: Alt(⌥)+Shift
|
|
94
|
+
"grid.deleteColumnShortcut": "열 삭제: Alt(⌥)+Shift+Backspace",
|
|
95
|
+
"clipboard.invalid": "복사한 수식 데이터가 올바르지 않습니다. 기존 수식은 유지됩니다.",
|
|
95
96
|
"clipboard.cut": "선택한 수식을 잘라냈습니다.",
|
|
96
97
|
"clipboard.copied": "선택한 수식을 구조와 LaTeX로 복사했습니다.",
|
|
97
98
|
"clipboard.pasted": "붙여넣었습니다.",
|
|
@@ -100,13 +101,15 @@
|
|
|
100
101
|
"grid.selectionHint": "수식 구조 전체 선택 · Backspace/Delete로 삭제 · Esc로 취소",
|
|
101
102
|
"selection.toolbar": "선택한 수식 감싸기",
|
|
102
103
|
"selection.highlighted": "강조된 범위 감싸기",
|
|
104
|
+
"selection.asNumerator": "분자로 넣기",
|
|
105
|
+
"selection.asDenominator": "분모로 넣기",
|
|
103
106
|
"selection.singleRowRequired": "한 줄 안의 범위를 선택해 주세요.",
|
|
104
107
|
"suggestion.label": "수식 추천",
|
|
105
108
|
"suggestion.composing": "한글 조합 중 · 확정 후 선택",
|
|
106
109
|
"suggestion.keyboardHint": "↑ ↓ 선택 · Enter 적용",
|
|
107
110
|
"suggestion.imeHint": "후보 미리보기 · Enter와 방향키는 한글 입력에 사용됩니다",
|
|
108
111
|
"suggestion.keepSource": "계속 입력하거나 Space · Esc로 원문 유지",
|
|
109
|
-
"matrix.keyboardHint": "Shift+Enter 행 추가 · Shift+Space 열 추가 · Alt(⌥)+Shift+↑ 행 삭제 · Alt(⌥)+Shift
|
|
112
|
+
"matrix.keyboardHint": "Shift+Enter 행 추가 · Shift+Space 열 추가 · Alt(⌥)+Shift+↑ 행 삭제 · Alt(⌥)+Shift+Backspace 열 삭제",
|
|
110
113
|
"aligned.inputHint": "왼쪽: 좌변 · 오른쪽: =부터 입력",
|
|
111
114
|
"cases.inputHint": "왼쪽: 식 · 오른쪽: 조건",
|
|
112
115
|
"grid.keyboardHint": "Enter 행 추가 · Alt(⌥)+Shift+↑ 행 삭제",
|
|
@@ -154,6 +157,7 @@
|
|
|
154
157
|
"template.detail": "편집 가능한 수식 템플릿",
|
|
155
158
|
"template.quadratic": "근의 공식",
|
|
156
159
|
"template.pythagorean": "피타고라스 정리",
|
|
160
|
+
"symbol.prime": "프라임",
|
|
157
161
|
"symbol.degree": "도",
|
|
158
162
|
"symbol.angle": "각 기호",
|
|
159
163
|
"symbol.plus": "더하기",
|
|
@@ -352,7 +356,21 @@
|
|
|
352
356
|
"context.indexedRoot": "n제곱근",
|
|
353
357
|
"context.fenceKeyboardHint": "F6: 도구로 이동 · ← →: 선택 · Enter: 적용 · Esc: 입력으로",
|
|
354
358
|
"suggestion.transformFence": "괄호 변경: {kind}",
|
|
355
|
-
"suggestion.transformFenceDetail": "안의 수식과 커서 위치를 유지합니다"
|
|
359
|
+
"suggestion.transformFenceDetail": "안의 수식과 커서 위치를 유지합니다",
|
|
360
|
+
"help.title": "단축키와 복사·붙여넣기",
|
|
361
|
+
"help.intro": "키보드로 수식을 편집하는 방법입니다. 도움말을 닫으면 수식으로 돌아갑니다.",
|
|
362
|
+
"help.units": "변수·숫자·구조 단위로 이동합니다. Shift를 함께 누르면 선택합니다. 구조 안에서는 현재 항목의 경계로 이동한 뒤 구조 밖으로 나갑니다.",
|
|
363
|
+
"help.slots": "다음 또는 이전 입력 칸으로 이동합니다.",
|
|
364
|
+
"help.select": "수식의 선택 범위를 늘립니다.",
|
|
365
|
+
"help.wrap": "수식을 선택한 상태에서 괄호·절대값·분수·지수·아래첨자로 감쌉니다.",
|
|
366
|
+
"help.suggestions": "툴바 없이도 제안 목록과 가능한 변형을 엽니다.",
|
|
367
|
+
"help.menu": "제안을 고르고 적용하거나 목록을 닫습니다.",
|
|
368
|
+
"help.clipboard": "복사·잘라내기·붙여넣기입니다. 브라우저가 편집기 데이터를 유지하면 구조도 보존됩니다. 일반 텍스트는 글자로 붙여넣습니다.",
|
|
369
|
+
"help.latex": "LaTeX 붙여넣기를 엽니다. 원문을 붙여넣고 Ctrl/Cmd+Enter로 삽입합니다. 잘못된 입력은 기존 수식을 바꾸지 않습니다.",
|
|
370
|
+
"help.history": "편집을 실행 취소하거나 다시 실행합니다.",
|
|
371
|
+
"help.lines": "Enter는 모드와 연동 설정을 따릅니다. Shift+Enter는 행렬의 행 또는 블록 수식의 줄을 추가합니다. 인라인 모드는 수식의 바깥 줄을 추가하지 않습니다.",
|
|
372
|
+
"help.open": "수식에 포커스가 있을 때 도움말을 엽니다.",
|
|
373
|
+
"help.platform": "macOS에서는 Cmd, Windows/Linux에서는 Ctrl을 사용합니다. macOS의 Alt는 Option입니다. 일부 키보드는 Fn+F1이 필요합니다. 운영체제나 연동 편집기의 단축키가 우선할 수 있습니다."
|
|
356
374
|
},
|
|
357
375
|
"aliases": {
|
|
358
376
|
"function-sin": ["사인"],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { requestMathHelp } from './dom/help.js';
|
|
2
3
|
import { useState } from 'react';
|
|
3
4
|
import { mathStructures } from './suggestions.js';
|
|
4
5
|
import { wrappingKinds } from './range.js';
|
|
@@ -17,7 +18,7 @@ export function MathEditorToolbar({ locale, kinds, maxItems = 8, excludedStructu
|
|
|
17
18
|
const visibleCount = Math.max(0, Math.floor(Number.isFinite(maxItems) ? maxItems : 8));
|
|
18
19
|
const items = mathStructures.filter((s) => s.kind && !excludedStructures.includes(s.kind) && (!kinds || kinds.includes(s.kind)));
|
|
19
20
|
const t = (key, parameters) => translate(locale, key, parameters);
|
|
20
|
-
return (_jsxs("div", { className: "me-tools", role: "toolbar", "aria-label": t('toolbar.label'), children: [(expanded ? items : items.slice(0, visibleCount)).map((s) => (_jsxs("button", { type: "button", "aria-label": t(s.label), disabled: composing || (hasRange && (!canWrap || !wrappingKinds.includes(s.kind))), onMouseDown: (event) => event.preventDefault(), onClick: () => onInsertStructure(s.kind), children: [_jsx("span", { children: s.glyph }), t(s.label)] }, s.kind))), expanded && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "data-math-tool": "quick", disabled: composing || cellRange, onMouseDown: (event) => event.preventDefault(), onClick: onQuick, children: t('quick.title') }), _jsx("button", { type: "button", "data-math-tool": "paste-latex", disabled: composing || cellRange, onMouseDown: (event) => event.preventDefault(), onClick: onPasteLatex, title: t('clipboard.latexShortcut'), children: t('clipboard.latexTitle') }), _jsxs("select", { disabled: composing || hasRange, className: "me-matrix-size", "aria-label": t('matrix.preset'), value: "", onChange: (event) => {
|
|
21
|
+
return (_jsxs("div", { className: "me-tools", role: "toolbar", "aria-label": t('toolbar.label'), children: [_jsx("button", { type: "button", "data-math-tool": "help", disabled: composing, title: `${t('help.title')} (F1)`, "aria-keyshortcuts": "F1", onMouseDown: (event) => event.preventDefault(), onClick: (event) => requestMathHelp(event.currentTarget), children: t('help.title') }), (expanded ? items : items.slice(0, visibleCount)).map((s) => (_jsxs("button", { type: "button", "aria-label": t(s.label), disabled: composing || (hasRange && (!canWrap || !wrappingKinds.includes(s.kind))), onMouseDown: (event) => event.preventDefault(), onClick: () => onInsertStructure(s.kind), children: [_jsx("span", { children: s.glyph }), t(s.label)] }, s.kind))), expanded && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "data-math-tool": "quick", disabled: composing || cellRange, onMouseDown: (event) => event.preventDefault(), onClick: onQuick, children: t('quick.title') }), _jsx("button", { type: "button", "data-math-tool": "paste-latex", disabled: composing || cellRange, onMouseDown: (event) => event.preventDefault(), onClick: onPasteLatex, title: t('clipboard.latexShortcut'), children: t('clipboard.latexTitle') }), _jsxs("select", { disabled: composing || hasRange, className: "me-matrix-size", "aria-label": t('matrix.preset'), value: "", onChange: (event) => {
|
|
21
22
|
const value = event.target.value;
|
|
22
23
|
onMatrixPreset(value);
|
|
23
24
|
}, children: [_jsx("option", { value: "", disabled: true, children: t('matrix.presetPlaceholder') }), [2, 3, 4].map((size) => (_jsx("option", { value: size, children: t('matrix.insert', { rows: size, columns: size }) }, size))), [2, 3, 4].map((size) => (_jsx("option", { value: `identity-${size}`, children: t('matrix.insertIdentity', { rows: size, columns: size }) }, `identity-${size}`)))] }), _jsxs("select", { className: "me-matrix-size", "aria-label": t('template.label'), value: "", disabled: composing || cellRange, onChange: (event) => onTemplate(event.target.value), children: [_jsx("option", { value: "", disabled: true, children: t('template.placeholder') }), mathTemplates.map((item) => (_jsx("option", { value: item.id, children: t(item.label, item.labelParameters) }, item.id)))] }), _jsx("button", { type: "button", "aria-expanded": symbolsOpen, disabled: composing || cellRange, onClick: onToggleSymbols, children: t('symbols.title') }), _jsx("span", { className: "me-divider" }), symbols.map((s) => (_jsx("button", { type: "button", "aria-label": t(s.label), disabled: composing || hasRange, onMouseDown: (event) => event.preventDefault(), onClick: () => onInsertSymbol(s.value), children: s.value }, s.label)))] })), _jsx("button", { type: "button", className: "me-toolbar-toggle", "aria-expanded": expanded, onMouseDown: (event) => event.preventDefault(), onClick: () => setExpanded((value) => !value), children: t(expanded ? 'toolbar.less' : 'toolbar.more') }), _jsx("button", { type: "button", disabled: !canUndo || composing, onMouseDown: (event) => event.preventDefault(), onClick: onUndo, children: t('history.undo') }), _jsx("button", { type: "button", disabled: !canRedo || composing, onMouseDown: (event) => event.preventDefault(), onClick: onRedo, children: t('history.redo') }), children] }));
|