@drghaliasri/butex 5.4.5 → 5.5.0
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 +2 -2
- package/dist/document2.d.mts +20 -2
- package/dist/document2.d.ts +20 -2
- package/dist/document2.js +176 -13
- package/dist/document2.js.map +1 -1
- package/dist/document2.mjs +175 -13
- package/dist/document2.mjs.map +1 -1
- package/dist/react-document2.d.mts +23 -3
- package/dist/react-document2.d.ts +23 -3
- package/dist/react-document2.js +513 -48
- package/dist/react-document2.js.map +1 -1
- package/dist/react-document2.mjs +559 -94
- package/dist/react-document2.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react-document2.mjs
CHANGED
|
@@ -1133,7 +1133,7 @@ function parseReferences(json) {
|
|
|
1133
1133
|
}
|
|
1134
1134
|
return references;
|
|
1135
1135
|
}
|
|
1136
|
-
function createInlineField2(value = "", mathObjects = [], options = {}, path = "$", diagnostics = []) {
|
|
1136
|
+
function createInlineField2(value = "", mathObjects = [], options = {}, path = "$", diagnostics = [], formats = []) {
|
|
1137
1137
|
const mode = options.mode ?? "english";
|
|
1138
1138
|
const spans = detectInlineSpans2(value);
|
|
1139
1139
|
const mathSpans = spans.filter((span) => span.kind === "math");
|
|
@@ -1145,7 +1145,7 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
|
|
|
1145
1145
|
}
|
|
1146
1146
|
for (const span of spans) {
|
|
1147
1147
|
if (span.start > index) {
|
|
1148
|
-
tokens
|
|
1148
|
+
pushFormattedTextTokens(tokens, value.slice(index, span.start), index, formats);
|
|
1149
1149
|
}
|
|
1150
1150
|
if (span.kind === "cite") {
|
|
1151
1151
|
tokens.push({
|
|
@@ -1201,9 +1201,81 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
|
|
|
1201
1201
|
index = span.end;
|
|
1202
1202
|
}
|
|
1203
1203
|
if (index < value.length || tokens.length === 0) {
|
|
1204
|
-
tokens
|
|
1204
|
+
pushFormattedTextTokens(tokens, value.slice(index), index, formats);
|
|
1205
|
+
}
|
|
1206
|
+
return { id: document2Id("field"), tokens: compactTextTokens(tokens) };
|
|
1207
|
+
}
|
|
1208
|
+
function styleFromFormat(format) {
|
|
1209
|
+
const style = {};
|
|
1210
|
+
if (format.bold === true) {
|
|
1211
|
+
style.bold = true;
|
|
1212
|
+
}
|
|
1213
|
+
if (format.italic === true) {
|
|
1214
|
+
style.italic = true;
|
|
1215
|
+
}
|
|
1216
|
+
if (format.underline === true) {
|
|
1217
|
+
style.underline = true;
|
|
1218
|
+
}
|
|
1219
|
+
return style.bold || style.italic || style.underline ? style : null;
|
|
1220
|
+
}
|
|
1221
|
+
function mergeTextStyle(base, added) {
|
|
1222
|
+
return {
|
|
1223
|
+
...base?.bold ? { bold: true } : {},
|
|
1224
|
+
...base?.italic ? { italic: true } : {},
|
|
1225
|
+
...base?.underline ? { underline: true } : {},
|
|
1226
|
+
...added.bold ? { bold: true } : {},
|
|
1227
|
+
...added.italic ? { italic: true } : {},
|
|
1228
|
+
...added.underline ? { underline: true } : {}
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1231
|
+
function textStylesEqual(a, b) {
|
|
1232
|
+
return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);
|
|
1233
|
+
}
|
|
1234
|
+
function compactTextTokens(tokens) {
|
|
1235
|
+
const compacted = [];
|
|
1236
|
+
for (const token of tokens) {
|
|
1237
|
+
const previous = compacted[compacted.length - 1];
|
|
1238
|
+
if (previous?.kind === "text" && token.kind === "text" && textStylesEqual(previous.style, token.style)) {
|
|
1239
|
+
previous.text += token.text;
|
|
1240
|
+
} else {
|
|
1241
|
+
compacted.push(token);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
return compacted;
|
|
1245
|
+
}
|
|
1246
|
+
function styleKey(style) {
|
|
1247
|
+
return `${style?.bold ? "b" : ""}${style?.italic ? "i" : ""}${style?.underline ? "u" : ""}`;
|
|
1248
|
+
}
|
|
1249
|
+
function pushFormattedTextTokens(tokens, text, sourceStart, formats) {
|
|
1250
|
+
if (text.length === 0) {
|
|
1251
|
+
tokens.push({ id: document2Id("text"), kind: "text", text });
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
const styles = Array.from({ length: text.length });
|
|
1255
|
+
for (const format of formats) {
|
|
1256
|
+
const style = styleFromFormat(format);
|
|
1257
|
+
if (!style || !Number.isFinite(format.start) || !Number.isFinite(format.end)) {
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
const start = Math.max(0, Math.min(text.length, Math.trunc(format.start) - sourceStart));
|
|
1261
|
+
const end = Math.max(0, Math.min(text.length, Math.trunc(format.end) - sourceStart));
|
|
1262
|
+
if (end <= start) {
|
|
1263
|
+
continue;
|
|
1264
|
+
}
|
|
1265
|
+
for (let index = start; index < end; index += 1) {
|
|
1266
|
+
styles[index] = mergeTextStyle(styles[index], style);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
let chunkStart = 0;
|
|
1270
|
+
for (let index = 1; index <= text.length; index += 1) {
|
|
1271
|
+
if (index < text.length && styleKey(styles[index]) === styleKey(styles[chunkStart])) {
|
|
1272
|
+
continue;
|
|
1273
|
+
}
|
|
1274
|
+
const chunk = text.slice(chunkStart, index);
|
|
1275
|
+
const style = styles[chunkStart];
|
|
1276
|
+
tokens.push({ id: document2Id("text"), kind: "text", text: chunk, ...style ? { style } : {} });
|
|
1277
|
+
chunkStart = index;
|
|
1205
1278
|
}
|
|
1206
|
-
return { id: document2Id("field"), tokens };
|
|
1207
1279
|
}
|
|
1208
1280
|
function closingForList(command) {
|
|
1209
1281
|
return command === "\\begin{itemize}" ? "\\end{itemize}" : "\\end{enumerate}";
|
|
@@ -1214,7 +1286,7 @@ function parseTextBlock(json, options, path, diagnostics) {
|
|
|
1214
1286
|
id: document2Id("block"),
|
|
1215
1287
|
kind: "textBlock",
|
|
1216
1288
|
command: json.command,
|
|
1217
|
-
field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics),
|
|
1289
|
+
field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.command === "\\paragraph" ? json.formats ?? [] : []),
|
|
1218
1290
|
...json.centered === true ? { centered: true } : {}
|
|
1219
1291
|
};
|
|
1220
1292
|
}
|
|
@@ -1223,7 +1295,7 @@ function parseListItem(json, options, path, diagnostics) {
|
|
|
1223
1295
|
const blocksJson = Array.isArray(json.blocks) ? json.blocks : [];
|
|
1224
1296
|
return {
|
|
1225
1297
|
id: document2Id("item"),
|
|
1226
|
-
field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics),
|
|
1298
|
+
field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.formats ?? []),
|
|
1227
1299
|
blocks: blocksJson.map((block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics))
|
|
1228
1300
|
};
|
|
1229
1301
|
}
|
|
@@ -1256,7 +1328,8 @@ function parseTableBlock(json, options, path, diagnostics) {
|
|
|
1256
1328
|
const spanCount = detectMathSpans2(value).length;
|
|
1257
1329
|
const cellMathObjects = mathObjects.slice(mathObjectIndex, mathObjectIndex + spanCount);
|
|
1258
1330
|
mathObjectIndex += spanCount;
|
|
1259
|
-
|
|
1331
|
+
const cellFormats = json.cell_formats?.[rowIndex]?.[columnIndex] ?? [];
|
|
1332
|
+
return createInlineField2(value, cellMathObjects, options, `${path}.rows[${String(rowIndex)}][${String(columnIndex)}]`, diagnostics, cellFormats);
|
|
1260
1333
|
});
|
|
1261
1334
|
});
|
|
1262
1335
|
if (mathObjects.length > 0 && mathObjects.length !== mathObjectIndex) {
|
|
@@ -8081,6 +8154,79 @@ function normalizeFieldTokens(tokens) {
|
|
|
8081
8154
|
}
|
|
8082
8155
|
return tokens;
|
|
8083
8156
|
}
|
|
8157
|
+
function textStylesEqual2(a, b) {
|
|
8158
|
+
return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);
|
|
8159
|
+
}
|
|
8160
|
+
function compactAdjacentTextTokens(tokens) {
|
|
8161
|
+
const compacted = [];
|
|
8162
|
+
for (const token of tokens) {
|
|
8163
|
+
const previous = compacted[compacted.length - 1];
|
|
8164
|
+
if (previous?.kind === "text" && token.kind === "text" && textStylesEqual2(previous.style, token.style)) {
|
|
8165
|
+
previous.text += token.text;
|
|
8166
|
+
} else {
|
|
8167
|
+
compacted.push(token);
|
|
8168
|
+
}
|
|
8169
|
+
}
|
|
8170
|
+
return normalizeFieldTokens(compacted);
|
|
8171
|
+
}
|
|
8172
|
+
function withoutEmptyStyle(style) {
|
|
8173
|
+
const next = {};
|
|
8174
|
+
if (style.bold) {
|
|
8175
|
+
next.bold = true;
|
|
8176
|
+
}
|
|
8177
|
+
if (style.italic) {
|
|
8178
|
+
next.italic = true;
|
|
8179
|
+
}
|
|
8180
|
+
if (style.underline) {
|
|
8181
|
+
next.underline = true;
|
|
8182
|
+
}
|
|
8183
|
+
return next.bold || next.italic || next.underline ? next : void 0;
|
|
8184
|
+
}
|
|
8185
|
+
function textTokenPart(text, style, id = document2Id("text")) {
|
|
8186
|
+
return { id, kind: "text", text, ...style ? { style } : {} };
|
|
8187
|
+
}
|
|
8188
|
+
function toggleTextTokenStyle(document2, fieldId, tokenId, selectionStart, selectionEnd, styleName) {
|
|
8189
|
+
if (selectionEnd <= selectionStart) {
|
|
8190
|
+
return document2;
|
|
8191
|
+
}
|
|
8192
|
+
const next = cloneDocument(document2);
|
|
8193
|
+
visitFields(next.blocks, (field) => {
|
|
8194
|
+
if (field.id !== fieldId) {
|
|
8195
|
+
return false;
|
|
8196
|
+
}
|
|
8197
|
+
const tokenIndex = field.tokens.findIndex((entry) => entry.id === tokenId && entry.kind === "text");
|
|
8198
|
+
if (tokenIndex < 0) {
|
|
8199
|
+
return true;
|
|
8200
|
+
}
|
|
8201
|
+
const token = field.tokens[tokenIndex];
|
|
8202
|
+
const start = Math.max(0, Math.min(token.text.length, selectionStart));
|
|
8203
|
+
const end = Math.max(0, Math.min(token.text.length, selectionEnd));
|
|
8204
|
+
if (end <= start) {
|
|
8205
|
+
return true;
|
|
8206
|
+
}
|
|
8207
|
+
const selectedStyle = token.style ?? {};
|
|
8208
|
+
const enabled = selectedStyle[styleName] === true;
|
|
8209
|
+
const nextStyle = withoutEmptyStyle({ ...selectedStyle, [styleName]: enabled ? void 0 : true });
|
|
8210
|
+
const parts = [];
|
|
8211
|
+
const before = token.text.slice(0, start);
|
|
8212
|
+
const selected = token.text.slice(start, end);
|
|
8213
|
+
const after = token.text.slice(end);
|
|
8214
|
+
if (before.length > 0) {
|
|
8215
|
+
parts.push(textTokenPart(before, token.style, token.id));
|
|
8216
|
+
}
|
|
8217
|
+
parts.push(textTokenPart(selected, nextStyle, before.length > 0 ? document2Id("text") : token.id));
|
|
8218
|
+
if (after.length > 0) {
|
|
8219
|
+
parts.push(textTokenPart(after, token.style));
|
|
8220
|
+
}
|
|
8221
|
+
field.tokens = compactAdjacentTextTokens([
|
|
8222
|
+
...field.tokens.slice(0, tokenIndex),
|
|
8223
|
+
...parts,
|
|
8224
|
+
...field.tokens.slice(tokenIndex + 1)
|
|
8225
|
+
]);
|
|
8226
|
+
return true;
|
|
8227
|
+
});
|
|
8228
|
+
return next;
|
|
8229
|
+
}
|
|
8084
8230
|
function stitchTextAroundRemovedToken(tokens, index) {
|
|
8085
8231
|
const before = tokens[index - 1];
|
|
8086
8232
|
const after = tokens[index + 1];
|
|
@@ -8108,8 +8254,8 @@ function removeMathTokenById(document2, tokenId) {
|
|
|
8108
8254
|
function splitTextTokenAt(token, offset) {
|
|
8109
8255
|
const safeOffset = Math.max(0, Math.min(offset, token.text.length));
|
|
8110
8256
|
return [
|
|
8111
|
-
{ id: token.id, kind: "text", text: token.text.slice(0, safeOffset) },
|
|
8112
|
-
{ id: document2Id("text"), kind: "text", text: token.text.slice(safeOffset) }
|
|
8257
|
+
{ id: token.id, kind: "text", text: token.text.slice(0, safeOffset), ...token.style ? { style: token.style } : {} },
|
|
8258
|
+
{ id: document2Id("text"), kind: "text", text: token.text.slice(safeOffset), ...token.style ? { style: token.style } : {} }
|
|
8113
8259
|
];
|
|
8114
8260
|
}
|
|
8115
8261
|
function insertMathTokenAtCaret(document2, fieldId, textTokenId, caretOffset, session, opening = "$", closing = "$", side = "arabic") {
|
|
@@ -8681,7 +8827,7 @@ function arabicXeLatexPreambleCmd() {
|
|
|
8681
8827
|
\newcommand{\horzbar}{\rule[.5ex]{2.5ex}{0.5pt}}
|
|
8682
8828
|
|
|
8683
8829
|
|
|
8684
|
-
\newcommand{\butexreflect}[1]{
|
|
8830
|
+
\newcommand{\butexreflect}[1]{\tikz[baseline=(n.base)]{\node[inner sep=0pt,outer sep=0pt,xscale=-1](n){#1};}}
|
|
8685
8831
|
|
|
8686
8832
|
\newcommand{\arabsqrt}[2]{\butexreflect{\(\sqrt[\butexreflect{\(#1\)}]{\butexreflect{\(#2\)}}\)}}
|
|
8687
8833
|
\newcommand{\arabvec}[1]{\butexreflect{$\vec{\butexreflect{$#1$}}$}}
|
|
@@ -8817,9 +8963,22 @@ function mathBodyLatex(token) {
|
|
|
8817
8963
|
const rendered = renderMathNodeLatex(token.math);
|
|
8818
8964
|
return stripDisplayMathDelimiters(rendered);
|
|
8819
8965
|
}
|
|
8966
|
+
function styledTextLatex(text, style) {
|
|
8967
|
+
let output = text;
|
|
8968
|
+
if (style?.bold) {
|
|
8969
|
+
output = `\\textbf{${output}}`;
|
|
8970
|
+
}
|
|
8971
|
+
if (style?.italic) {
|
|
8972
|
+
output = `\\textit{${output}}`;
|
|
8973
|
+
}
|
|
8974
|
+
if (style?.underline) {
|
|
8975
|
+
output = `\\underline{${output}}`;
|
|
8976
|
+
}
|
|
8977
|
+
return output;
|
|
8978
|
+
}
|
|
8820
8979
|
function tokenLatex(token) {
|
|
8821
8980
|
if (token.kind === "text") {
|
|
8822
|
-
return token.text;
|
|
8981
|
+
return styledTextLatex(token.text, token.style);
|
|
8823
8982
|
}
|
|
8824
8983
|
if (token.kind === "cite") {
|
|
8825
8984
|
return citeTokenLatex(token.keys);
|
|
@@ -8843,7 +9002,9 @@ function inlineFieldLatex(field) {
|
|
|
8843
9002
|
return field.tokens.map((token) => tokenLatex(token)).join("");
|
|
8844
9003
|
}
|
|
8845
9004
|
function textBlockLatex(block) {
|
|
8846
|
-
const
|
|
9005
|
+
const content = inlineFieldLatex(block.field);
|
|
9006
|
+
const body = block.command === "\\paragraph" ? `\\par
|
|
9007
|
+
${content}` : `${block.command}{${content}}`;
|
|
8847
9008
|
if (block.command === "\\paragraph" && block.centered) {
|
|
8848
9009
|
return `\\begin{center}
|
|
8849
9010
|
${body}
|
|
@@ -9095,7 +9256,7 @@ function mathTex(token, equationSide) {
|
|
|
9095
9256
|
function previewInlines(field, islands, output, equationSide, document2, previewOptions) {
|
|
9096
9257
|
return field.tokens.map((token) => {
|
|
9097
9258
|
if (token.kind === "text") {
|
|
9098
|
-
return { kind: "text", text: token.text };
|
|
9259
|
+
return { kind: "text", text: token.text, ...token.style ? { style: token.style } : {} };
|
|
9099
9260
|
}
|
|
9100
9261
|
if (token.kind === "cite") {
|
|
9101
9262
|
return {
|
|
@@ -9271,6 +9432,10 @@ var DOCUMENT2_MESSAGES = {
|
|
|
9271
9432
|
redo: "\u0625\u0639\u0627\u062F\u0629",
|
|
9272
9433
|
structure: "\u0647\u064A\u0643\u0644",
|
|
9273
9434
|
content: "\u0645\u062D\u062A\u0648\u0649",
|
|
9435
|
+
textFormatting: "\u062A\u0646\u0633\u064A\u0642 \u0627\u0644\u0646\u0635",
|
|
9436
|
+
bold: "\u063A\u0627\u0645\u0642",
|
|
9437
|
+
italic: "\u0645\u0627\u0626\u0644",
|
|
9438
|
+
underline: "\u062A\u062D\u062A\u0647 \u062E\u0637",
|
|
9274
9439
|
equations: "\u0645\u0639\u0627\u062F\u0644\u0627\u062A",
|
|
9275
9440
|
citations: "\u0627\u0642\u062A\u0628\u0627\u0633\u0627\u062A \u0648\u0645\u0631\u0627\u062C\u0639",
|
|
9276
9441
|
lists: "\u0642\u0648\u0627\u0626\u0645",
|
|
@@ -9410,6 +9575,10 @@ var DOCUMENT2_MESSAGES = {
|
|
|
9410
9575
|
redo: "Redo",
|
|
9411
9576
|
structure: "Structure",
|
|
9412
9577
|
content: "Content",
|
|
9578
|
+
textFormatting: "Text formatting",
|
|
9579
|
+
bold: "Bold",
|
|
9580
|
+
italic: "Italic",
|
|
9581
|
+
underline: "Underline",
|
|
9413
9582
|
equations: "Equations",
|
|
9414
9583
|
citations: "Citations and references",
|
|
9415
9584
|
lists: "Lists",
|
|
@@ -9753,7 +9922,7 @@ function focusArticleMetaPanel(panel) {
|
|
|
9753
9922
|
}
|
|
9754
9923
|
|
|
9755
9924
|
// src/react-document2/ButexDocumentEditor2.tsx
|
|
9756
|
-
import { useCallback as useCallback2, useEffect as
|
|
9925
|
+
import { useCallback as useCallback2, useEffect as useEffect9, useMemo as useMemo2, useRef as useRef8, useState as useState12 } from "react";
|
|
9757
9926
|
|
|
9758
9927
|
// src/react-document2/BlockEditor.tsx
|
|
9759
9928
|
import { useState as useState3 } from "react";
|
|
@@ -10448,7 +10617,9 @@ function rememberCaret(element, blockId, fieldId, tokenId, onFieldFocus) {
|
|
|
10448
10617
|
if (!blockId || !onFieldFocus) {
|
|
10449
10618
|
return;
|
|
10450
10619
|
}
|
|
10451
|
-
|
|
10620
|
+
const selectionStart = element.selectionStart ?? element.value.length;
|
|
10621
|
+
const selectionEnd = element.selectionEnd ?? selectionStart;
|
|
10622
|
+
onFieldFocus(blockId, fieldId, tokenId, selectionEnd, selectionStart, selectionEnd);
|
|
10452
10623
|
}
|
|
10453
10624
|
function fitTextareaHeight(element) {
|
|
10454
10625
|
if (!element) {
|
|
@@ -10582,6 +10753,9 @@ function InlineField({
|
|
|
10582
10753
|
{
|
|
10583
10754
|
className: "butex-document2-widget__inline-text",
|
|
10584
10755
|
value: token.text,
|
|
10756
|
+
"data-bold": token.style?.bold === true ? "true" : void 0,
|
|
10757
|
+
"data-italic": token.style?.italic === true ? "true" : void 0,
|
|
10758
|
+
"data-underline": token.style?.underline === true ? "true" : void 0,
|
|
10585
10759
|
dir: documentDirection,
|
|
10586
10760
|
"aria-label": messages.text,
|
|
10587
10761
|
rows: 1,
|
|
@@ -11300,7 +11474,7 @@ function CitePickerPopover({
|
|
|
11300
11474
|
}
|
|
11301
11475
|
|
|
11302
11476
|
// src/react-document2/DocumentInsertToolbar.tsx
|
|
11303
|
-
import { useState as useState6 } from "react";
|
|
11477
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState6 } from "react";
|
|
11304
11478
|
|
|
11305
11479
|
// src/react-document2/TableInsertPopover.tsx
|
|
11306
11480
|
import { useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
|
|
@@ -11378,8 +11552,11 @@ function DocumentInsertToolbar({
|
|
|
11378
11552
|
selectionCount = 0,
|
|
11379
11553
|
canMoveSelectionUp = false,
|
|
11380
11554
|
canMoveSelectionDown = false,
|
|
11555
|
+
canFormatText = false,
|
|
11556
|
+
activeTextStyles = {},
|
|
11381
11557
|
onUndo,
|
|
11382
11558
|
onRedo,
|
|
11559
|
+
onToggleTextStyle,
|
|
11383
11560
|
onMoveSelectionUp,
|
|
11384
11561
|
onMoveSelectionDown,
|
|
11385
11562
|
onDeleteSelection,
|
|
@@ -11403,6 +11580,56 @@ function DocumentInsertToolbar({
|
|
|
11403
11580
|
}) {
|
|
11404
11581
|
const messages = document2Messages(uiLocale);
|
|
11405
11582
|
const [digitMenuOpen, setDigitMenuOpen] = useState6(false);
|
|
11583
|
+
const [referencesMenuOpen, setReferencesMenuOpen] = useState6(false);
|
|
11584
|
+
const referencesMenuRef = useRef5(null);
|
|
11585
|
+
const referencesTriggerRef = useRef5(null);
|
|
11586
|
+
useEffect5(() => {
|
|
11587
|
+
if (!referencesMenuOpen) {
|
|
11588
|
+
return;
|
|
11589
|
+
}
|
|
11590
|
+
referencesMenuRef.current?.querySelector('[role="menuitem"]')?.focus();
|
|
11591
|
+
const closeOnOutsideClick = (event) => {
|
|
11592
|
+
if (!referencesMenuRef.current?.contains(event.target)) {
|
|
11593
|
+
setReferencesMenuOpen(false);
|
|
11594
|
+
}
|
|
11595
|
+
};
|
|
11596
|
+
const closeOnEscape = (event) => {
|
|
11597
|
+
if (event.key === "Escape") {
|
|
11598
|
+
setReferencesMenuOpen(false);
|
|
11599
|
+
referencesTriggerRef.current?.focus();
|
|
11600
|
+
}
|
|
11601
|
+
};
|
|
11602
|
+
document.addEventListener("mousedown", closeOnOutsideClick);
|
|
11603
|
+
document.addEventListener("keydown", closeOnEscape);
|
|
11604
|
+
return () => {
|
|
11605
|
+
document.removeEventListener("mousedown", closeOnOutsideClick);
|
|
11606
|
+
document.removeEventListener("keydown", closeOnEscape);
|
|
11607
|
+
};
|
|
11608
|
+
}, [referencesMenuOpen]);
|
|
11609
|
+
function runReferenceAction(action) {
|
|
11610
|
+
setReferencesMenuOpen(false);
|
|
11611
|
+
action();
|
|
11612
|
+
}
|
|
11613
|
+
function moveReferenceMenuFocus(event) {
|
|
11614
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
11615
|
+
return;
|
|
11616
|
+
}
|
|
11617
|
+
const items = Array.from(event.currentTarget.querySelectorAll('[role="menuitem"]'));
|
|
11618
|
+
if (items.length === 0) {
|
|
11619
|
+
return;
|
|
11620
|
+
}
|
|
11621
|
+
event.preventDefault();
|
|
11622
|
+
const currentIndex = items.indexOf(document.activeElement);
|
|
11623
|
+
if (event.key === "Home") {
|
|
11624
|
+
items[0]?.focus();
|
|
11625
|
+
} else if (event.key === "End") {
|
|
11626
|
+
items[items.length - 1]?.focus();
|
|
11627
|
+
} else {
|
|
11628
|
+
const change = event.key === "ArrowDown" ? 1 : -1;
|
|
11629
|
+
const nextIndex = (currentIndex + change + items.length) % items.length;
|
|
11630
|
+
items[nextIndex]?.focus();
|
|
11631
|
+
}
|
|
11632
|
+
}
|
|
11406
11633
|
function digitTitle(id) {
|
|
11407
11634
|
if (id === "arabicIndic") {
|
|
11408
11635
|
return messages.arabicIndicDigits;
|
|
@@ -11460,6 +11687,50 @@ function DocumentInsertToolbar({
|
|
|
11460
11687
|
messages.selectedBlockCount
|
|
11461
11688
|
] }) : null
|
|
11462
11689
|
] }),
|
|
11690
|
+
/* @__PURE__ */ jsxs8("div", { className: "butex-document2-widget__toolbar-group", role: "group", "aria-label": messages.textFormatting, children: [
|
|
11691
|
+
/* @__PURE__ */ jsx10(
|
|
11692
|
+
"button",
|
|
11693
|
+
{
|
|
11694
|
+
type: "button",
|
|
11695
|
+
className: "butex-document2-widget__icon-btn butex-document2-widget__format-btn",
|
|
11696
|
+
title: messages.bold,
|
|
11697
|
+
"aria-label": messages.bold,
|
|
11698
|
+
"aria-pressed": activeTextStyles.bold === true,
|
|
11699
|
+
disabled: !canFormatText,
|
|
11700
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
11701
|
+
onClick: () => onToggleTextStyle?.("bold"),
|
|
11702
|
+
children: /* @__PURE__ */ jsx10("span", { className: "butex-document2-widget__format-icon butex-document2-widget__format-icon--bold", "aria-hidden": "true", children: "\u0646\u0635" })
|
|
11703
|
+
}
|
|
11704
|
+
),
|
|
11705
|
+
/* @__PURE__ */ jsx10(
|
|
11706
|
+
"button",
|
|
11707
|
+
{
|
|
11708
|
+
type: "button",
|
|
11709
|
+
className: "butex-document2-widget__icon-btn butex-document2-widget__format-btn",
|
|
11710
|
+
title: messages.italic,
|
|
11711
|
+
"aria-label": messages.italic,
|
|
11712
|
+
"aria-pressed": activeTextStyles.italic === true,
|
|
11713
|
+
disabled: !canFormatText,
|
|
11714
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
11715
|
+
onClick: () => onToggleTextStyle?.("italic"),
|
|
11716
|
+
children: /* @__PURE__ */ jsx10("span", { className: "butex-document2-widget__format-icon butex-document2-widget__format-icon--italic", "aria-hidden": "true", children: "\u0646\u0635" })
|
|
11717
|
+
}
|
|
11718
|
+
),
|
|
11719
|
+
/* @__PURE__ */ jsx10(
|
|
11720
|
+
"button",
|
|
11721
|
+
{
|
|
11722
|
+
type: "button",
|
|
11723
|
+
className: "butex-document2-widget__icon-btn butex-document2-widget__format-btn",
|
|
11724
|
+
title: messages.underline,
|
|
11725
|
+
"aria-label": messages.underline,
|
|
11726
|
+
"aria-pressed": activeTextStyles.underline === true,
|
|
11727
|
+
disabled: !canFormatText,
|
|
11728
|
+
onMouseDown: (event) => event.preventDefault(),
|
|
11729
|
+
onClick: () => onToggleTextStyle?.("underline"),
|
|
11730
|
+
children: /* @__PURE__ */ jsx10("span", { className: "butex-document2-widget__format-icon butex-document2-widget__format-icon--underline", "aria-hidden": "true", children: "\u0646\u0635" })
|
|
11731
|
+
}
|
|
11732
|
+
)
|
|
11733
|
+
] }),
|
|
11463
11734
|
/* @__PURE__ */ jsxs8("div", { className: "butex-document2-widget__toolbar-group", role: "group", "aria-label": messages.structure, children: [
|
|
11464
11735
|
/* @__PURE__ */ jsx10(
|
|
11465
11736
|
"button",
|
|
@@ -11511,35 +11782,57 @@ function DocumentInsertToolbar({
|
|
|
11511
11782
|
)) }) : null
|
|
11512
11783
|
] })
|
|
11513
11784
|
] }),
|
|
11514
|
-
/* @__PURE__ */
|
|
11515
|
-
/* @__PURE__ */
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
"
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
11785
|
+
/* @__PURE__ */ jsx10("div", { className: "butex-document2-widget__toolbar-group", role: "group", "aria-label": messages.citations, children: /* @__PURE__ */ jsxs8("div", { className: "butex-document2-widget__references-menu", ref: referencesMenuRef, children: [
|
|
11786
|
+
/* @__PURE__ */ jsxs8(
|
|
11787
|
+
"button",
|
|
11788
|
+
{
|
|
11789
|
+
ref: referencesTriggerRef,
|
|
11790
|
+
type: "button",
|
|
11791
|
+
className: "butex-document2-widget__icon-btn butex-document2-widget__references-trigger",
|
|
11792
|
+
title: messages.citations,
|
|
11793
|
+
"aria-label": messages.citations,
|
|
11794
|
+
"aria-haspopup": "menu",
|
|
11795
|
+
"aria-expanded": referencesMenuOpen,
|
|
11796
|
+
onClick: () => setReferencesMenuOpen((open) => !open),
|
|
11797
|
+
children: [
|
|
11798
|
+
/* @__PURE__ */ jsx10("span", { className: "butex-document2-widget__icon-bibliography", "aria-hidden": "true", children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 16 16", width: "14", height: "14", focusable: "false", children: /* @__PURE__ */ jsx10("path", { fill: "currentColor", d: "M2 2.2h4.2c.7 0 1.3.3 1.8.8.5-.5 1.1-.8 1.8-.8H14v10.6H9.8c-.6 0-1.1.3-1.4.8h-.8c-.3-.5-.8-.8-1.4-.8H2V2.2zm1.2 1.2v8.2h3c.4 0 .8.1 1.2.3V4.6c-.2-.7-.6-1.2-1.2-1.2h-3zm9.6 0h-3c-.6 0-1 .5-1.2 1.2v7.3c.4-.2.8-.3 1.2-.3h3V3.4z" }) }) }),
|
|
11799
|
+
/* @__PURE__ */ jsx10("span", { children: messages.citations }),
|
|
11800
|
+
/* @__PURE__ */ jsx10("span", { className: "butex-document2-widget__menu-chevron", "aria-hidden": "true", children: "\u2304" })
|
|
11801
|
+
]
|
|
11802
|
+
}
|
|
11803
|
+
),
|
|
11804
|
+
referencesMenuOpen ? /* @__PURE__ */ jsxs8(
|
|
11805
|
+
"div",
|
|
11806
|
+
{
|
|
11807
|
+
className: "butex-document2-widget__references-menu-options",
|
|
11808
|
+
role: "menu",
|
|
11809
|
+
"aria-label": messages.citations,
|
|
11810
|
+
onKeyDown: moveReferenceMenuFocus,
|
|
11811
|
+
children: [
|
|
11812
|
+
/* @__PURE__ */ jsxs8("button", { type: "button", role: "menuitem", title: messages.insertCitation, onClick: () => runReferenceAction(onInsertCitation), children: [
|
|
11813
|
+
/* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "[]" }),
|
|
11814
|
+
/* @__PURE__ */ jsx10("span", { children: messages.insertCitation })
|
|
11815
|
+
] }),
|
|
11816
|
+
/* @__PURE__ */ jsxs8("button", { type: "button", role: "menuitem", title: messages.insertInternalRef, onClick: () => runReferenceAction(onInsertInternalRef), children: [
|
|
11817
|
+
/* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "\xA7" }),
|
|
11818
|
+
/* @__PURE__ */ jsx10("span", { children: messages.insertInternalRef })
|
|
11819
|
+
] }),
|
|
11820
|
+
/* @__PURE__ */ jsxs8("button", { type: "button", role: "menuitem", title: messages.insertBibliography, onClick: () => runReferenceAction(onInsertBibliography), children: [
|
|
11821
|
+
/* @__PURE__ */ jsx10("span", { className: "butex-document2-widget__icon-bibliography", "aria-hidden": "true", children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 16 16", width: "14", height: "14", focusable: "false", children: /* @__PURE__ */ jsx10("path", { fill: "currentColor", d: "M2.2 2.4h7.2c.9 0 1.6.7 1.6 1.6v9.2c0 .5-.6.8-1 .5l-2.2-1.6H2.2c-.9 0-1.6-.7-1.6-1.6V4c0-.9.7-1.6 1.6-1.6zm0 1.2c-.2 0-.4.2-.4.4v6.5c0 .2.2.4.4.4h6.1l1.5 1.1V4c0-.2-.2-.4-.4-.4H2.2zM3.4 5.2h5.2v1H3.4zm0 2.1h4.2v1H3.4zm0 2.1h3.4v1H3.4zM11.4 4.1h2.2c.8 0 1.4.6 1.4 1.4v7.1c0 .4-.5.7-.8.4l-1.7-1.3h-1.1V4.1zm1.2 1.2v5.4l.7.5V5.5c0-.1-.1-.2-.2-.2h-.5z" }) }) }),
|
|
11822
|
+
/* @__PURE__ */ jsx10("span", { children: messages.insertBibliography })
|
|
11823
|
+
] }),
|
|
11824
|
+
/* @__PURE__ */ jsxs8("button", { type: "button", role: "menuitem", title: messages.manageReferences, onClick: () => runReferenceAction(onManageReferences), children: [
|
|
11825
|
+
/* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "\u2630" }),
|
|
11826
|
+
/* @__PURE__ */ jsx10("span", { children: messages.manageReferences })
|
|
11827
|
+
] }),
|
|
11828
|
+
/* @__PURE__ */ jsxs8("button", { type: "button", role: "menuitem", title: messages.manageLabels, onClick: () => runReferenceAction(onManageLabels), children: [
|
|
11829
|
+
/* @__PURE__ */ jsx10("span", { "aria-hidden": "true", children: "\u2317" }),
|
|
11830
|
+
/* @__PURE__ */ jsx10("span", { children: messages.manageLabels })
|
|
11831
|
+
] })
|
|
11832
|
+
]
|
|
11833
|
+
}
|
|
11834
|
+
) : null
|
|
11835
|
+
] }) }),
|
|
11543
11836
|
/* @__PURE__ */ jsxs8("div", { className: "butex-document2-widget__toolbar-group", role: "group", "aria-label": messages.lists, children: [
|
|
11544
11837
|
/* @__PURE__ */ jsx10("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.bulletedList, "aria-label": messages.bulletedList, onClick: onAddList, children: "\u2022\u2261" }),
|
|
11545
11838
|
/* @__PURE__ */ jsx10("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.numberedList, "aria-label": messages.numberedList, onClick: onAddEnumerate, children: "1." })
|
|
@@ -11554,7 +11847,17 @@ import { Fragment, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
|
11554
11847
|
function PreviewInlines({ inlines, output }) {
|
|
11555
11848
|
return /* @__PURE__ */ jsx11(Fragment, { children: inlines.map((inline, index) => {
|
|
11556
11849
|
if (inline.kind === "text") {
|
|
11557
|
-
|
|
11850
|
+
let content = /* @__PURE__ */ jsx11("span", { children: inline.text });
|
|
11851
|
+
if (inline.style?.bold) {
|
|
11852
|
+
content = /* @__PURE__ */ jsx11("strong", { children: content });
|
|
11853
|
+
}
|
|
11854
|
+
if (inline.style?.italic) {
|
|
11855
|
+
content = /* @__PURE__ */ jsx11("em", { children: content });
|
|
11856
|
+
}
|
|
11857
|
+
if (inline.style?.underline) {
|
|
11858
|
+
content = /* @__PURE__ */ jsx11("span", { className: "butex-document2-widget__preview-underline", children: content });
|
|
11859
|
+
}
|
|
11860
|
+
return /* @__PURE__ */ jsx11("span", { children: content }, index);
|
|
11558
11861
|
}
|
|
11559
11862
|
if (inline.kind === "cite") {
|
|
11560
11863
|
return /* @__PURE__ */ jsx11("span", { className: "butex-document2-widget__preview-cite", children: inline.label }, inline.id);
|
|
@@ -11703,15 +12006,15 @@ function DocumentPreview({
|
|
|
11703
12006
|
}
|
|
11704
12007
|
|
|
11705
12008
|
// src/react-document2/EquationDrawer.tsx
|
|
11706
|
-
import { useEffect as
|
|
12009
|
+
import { useEffect as useEffect7, useRef as useRef7, useState as useState8 } from "react";
|
|
11707
12010
|
|
|
11708
12011
|
// src/react/ButexEditor.tsx
|
|
11709
12012
|
import {
|
|
11710
12013
|
forwardRef,
|
|
11711
12014
|
useCallback,
|
|
11712
|
-
useEffect as
|
|
12015
|
+
useEffect as useEffect6,
|
|
11713
12016
|
useImperativeHandle,
|
|
11714
|
-
useRef as
|
|
12017
|
+
useRef as useRef6,
|
|
11715
12018
|
useState as useState7
|
|
11716
12019
|
} from "react";
|
|
11717
12020
|
|
|
@@ -12786,28 +13089,28 @@ ${latex || messages.empty}`;
|
|
|
12786
13089
|
var ButexEditor = forwardRef(
|
|
12787
13090
|
function ButexEditor2({ className, debug = false, defaultSide, uiLocale = "ar", initialSession, onSessionChange }, ref) {
|
|
12788
13091
|
const messages = equationEditorMessages(uiLocale);
|
|
12789
|
-
const wrapperRef =
|
|
12790
|
-
const surfaceRef =
|
|
12791
|
-
const mathOutputRef =
|
|
12792
|
-
const renderErrorRef =
|
|
12793
|
-
const latexLinesRef =
|
|
12794
|
-
const passivePreviewRef =
|
|
12795
|
-
const debugLogRef =
|
|
12796
|
-
const undoBtnRef =
|
|
12797
|
-
const redoBtnRef =
|
|
12798
|
-
const copyBtnRef =
|
|
12799
|
-
const cutBtnRef =
|
|
12800
|
-
const splitTypingBtnRef =
|
|
12801
|
-
const characterFontBtnRef =
|
|
12802
|
-
const digitFormBtnRef =
|
|
12803
|
-
const runtimeRef =
|
|
12804
|
-
const debugRef =
|
|
13092
|
+
const wrapperRef = useRef6(null);
|
|
13093
|
+
const surfaceRef = useRef6(null);
|
|
13094
|
+
const mathOutputRef = useRef6(null);
|
|
13095
|
+
const renderErrorRef = useRef6(null);
|
|
13096
|
+
const latexLinesRef = useRef6(null);
|
|
13097
|
+
const passivePreviewRef = useRef6(null);
|
|
13098
|
+
const debugLogRef = useRef6(null);
|
|
13099
|
+
const undoBtnRef = useRef6(null);
|
|
13100
|
+
const redoBtnRef = useRef6(null);
|
|
13101
|
+
const copyBtnRef = useRef6(null);
|
|
13102
|
+
const cutBtnRef = useRef6(null);
|
|
13103
|
+
const splitTypingBtnRef = useRef6(null);
|
|
13104
|
+
const characterFontBtnRef = useRef6(null);
|
|
13105
|
+
const digitFormBtnRef = useRef6(null);
|
|
13106
|
+
const runtimeRef = useRef6(null);
|
|
13107
|
+
const debugRef = useRef6(debug);
|
|
12805
13108
|
debugRef.current = debug;
|
|
12806
|
-
const uiLocaleRef =
|
|
13109
|
+
const uiLocaleRef = useRef6(uiLocale);
|
|
12807
13110
|
uiLocaleRef.current = uiLocale;
|
|
12808
|
-
const onSessionChangeRef =
|
|
13111
|
+
const onSessionChangeRef = useRef6(onSessionChange);
|
|
12809
13112
|
onSessionChangeRef.current = onSessionChange;
|
|
12810
|
-
const debugBodyHiddenRef =
|
|
13113
|
+
const debugBodyHiddenRef = useRef6(false);
|
|
12811
13114
|
const [debugBodyHidden, setDebugBodyHidden] = useState7(false);
|
|
12812
13115
|
debugBodyHiddenRef.current = debugBodyHidden;
|
|
12813
13116
|
const [digitMenuOpen, setDigitMenuOpen] = useState7(false);
|
|
@@ -12888,9 +13191,9 @@ ${arabic || currentMessages.empty}`;
|
|
|
12888
13191
|
}
|
|
12889
13192
|
}
|
|
12890
13193
|
}, []);
|
|
12891
|
-
const updatePreviewRef =
|
|
13194
|
+
const updatePreviewRef = useRef6(updatePreview);
|
|
12892
13195
|
updatePreviewRef.current = updatePreview;
|
|
12893
|
-
|
|
13196
|
+
useEffect6(() => {
|
|
12894
13197
|
injectWidgetChromeCss();
|
|
12895
13198
|
injectBuTeXEditorStyles(typeof document !== "undefined" ? document : void 0);
|
|
12896
13199
|
const surfaceEl = surfaceRef.current;
|
|
@@ -12946,7 +13249,7 @@ ${arabic || currentMessages.empty}`;
|
|
|
12946
13249
|
runtimeRef.current = null;
|
|
12947
13250
|
};
|
|
12948
13251
|
}, []);
|
|
12949
|
-
|
|
13252
|
+
useEffect6(() => {
|
|
12950
13253
|
runtimeRef.current?.setUiLocale(uiLocale);
|
|
12951
13254
|
const session = runtimeRef.current?.getSession();
|
|
12952
13255
|
if (session) {
|
|
@@ -14122,7 +14425,7 @@ function EquationDrawer({
|
|
|
14122
14425
|
onDelete
|
|
14123
14426
|
}) {
|
|
14124
14427
|
const messages = document2Messages(uiLocale);
|
|
14125
|
-
const latestSession =
|
|
14428
|
+
const latestSession = useRef7(session);
|
|
14126
14429
|
const [labelOverride, setLabelOverride] = useState8(null);
|
|
14127
14430
|
const displayedLabel = labelOverride ?? label;
|
|
14128
14431
|
const labelError = labelEnabled && mathMode === "display" ? document2KeyError(displayedLabel, {
|
|
@@ -14130,10 +14433,10 @@ function EquationDrawer({
|
|
|
14130
14433
|
labels,
|
|
14131
14434
|
excludeOwnerId: ownerId || void 0
|
|
14132
14435
|
}) : null;
|
|
14133
|
-
|
|
14436
|
+
useEffect7(() => {
|
|
14134
14437
|
setLabelOverride(null);
|
|
14135
14438
|
}, [ownerId, label]);
|
|
14136
|
-
|
|
14439
|
+
useEffect7(() => {
|
|
14137
14440
|
const onKeyDown = (event) => {
|
|
14138
14441
|
if (event.key === "Escape") {
|
|
14139
14442
|
onClose();
|
|
@@ -14675,7 +14978,7 @@ function ReferencesPanel({
|
|
|
14675
14978
|
}
|
|
14676
14979
|
|
|
14677
14980
|
// src/react-document2/RefPickerPopover.tsx
|
|
14678
|
-
import { useEffect as
|
|
14981
|
+
import { useEffect as useEffect8, useState as useState11 } from "react";
|
|
14679
14982
|
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
14680
14983
|
function RefPickerPopover({
|
|
14681
14984
|
open,
|
|
@@ -14692,7 +14995,7 @@ function RefPickerPopover({
|
|
|
14692
14995
|
const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
|
|
14693
14996
|
const [selected, setSelected] = useState11(initialKeys);
|
|
14694
14997
|
const [refCommand, setRefCommand] = useState11(initialRefCommand);
|
|
14695
|
-
|
|
14998
|
+
useEffect8(() => {
|
|
14696
14999
|
if (open) {
|
|
14697
15000
|
setSelected(initialKeys);
|
|
14698
15001
|
setRefCommand(initialRefCommand);
|
|
@@ -14757,7 +15060,7 @@ function RefPickerPopover({
|
|
|
14757
15060
|
|
|
14758
15061
|
// src/react-document2/editorFocus.ts
|
|
14759
15062
|
function createEmptyDocument2EditorFocus() {
|
|
14760
|
-
return { blockId: null, fieldId: null, textTokenId: null, caretOffset: 0 };
|
|
15063
|
+
return { blockId: null, fieldId: null, textTokenId: null, caretOffset: 0, selectionStart: 0, selectionEnd: 0 };
|
|
14761
15064
|
}
|
|
14762
15065
|
function findBlockIdForField(blocks, fieldId) {
|
|
14763
15066
|
for (const block of blocks) {
|
|
@@ -14965,6 +15268,89 @@ var DOCUMENT2_WIDGET_CSS = `
|
|
|
14965
15268
|
display: block;
|
|
14966
15269
|
}
|
|
14967
15270
|
|
|
15271
|
+
.butex-document2-widget__format-btn {
|
|
15272
|
+
font-family: "Amiri", "Noto Serif Arabic", Georgia, serif;
|
|
15273
|
+
min-width: 36px;
|
|
15274
|
+
}
|
|
15275
|
+
|
|
15276
|
+
.butex-document2-widget__format-icon {
|
|
15277
|
+
direction: rtl;
|
|
15278
|
+
display: inline-block;
|
|
15279
|
+
font-size: 0.84rem;
|
|
15280
|
+
font-weight: 500;
|
|
15281
|
+
}
|
|
15282
|
+
|
|
15283
|
+
.butex-document2-widget__format-icon--bold {
|
|
15284
|
+
font-weight: 900;
|
|
15285
|
+
}
|
|
15286
|
+
|
|
15287
|
+
.butex-document2-widget__format-icon--italic {
|
|
15288
|
+
font-style: italic;
|
|
15289
|
+
transform: skewX(-7deg);
|
|
15290
|
+
}
|
|
15291
|
+
|
|
15292
|
+
.butex-document2-widget__format-icon--underline {
|
|
15293
|
+
text-decoration: underline;
|
|
15294
|
+
text-underline-offset: 0.12em;
|
|
15295
|
+
}
|
|
15296
|
+
|
|
15297
|
+
.butex-document2-widget__format-underline,
|
|
15298
|
+
.butex-document2-widget__preview-underline {
|
|
15299
|
+
text-decoration: underline;
|
|
15300
|
+
text-underline-offset: 0.12em;
|
|
15301
|
+
}
|
|
15302
|
+
|
|
15303
|
+
.butex-document2-widget__references-menu {
|
|
15304
|
+
position: relative;
|
|
15305
|
+
}
|
|
15306
|
+
|
|
15307
|
+
.butex-document2-widget__references-trigger {
|
|
15308
|
+
gap: 5px;
|
|
15309
|
+
white-space: nowrap;
|
|
15310
|
+
}
|
|
15311
|
+
|
|
15312
|
+
.butex-document2-widget__menu-chevron {
|
|
15313
|
+
color: var(--butex-document2-muted);
|
|
15314
|
+
font-size: 0.8rem;
|
|
15315
|
+
}
|
|
15316
|
+
|
|
15317
|
+
.butex-document2-widget__references-menu-options {
|
|
15318
|
+
background: var(--butex-document2-panel);
|
|
15319
|
+
border: 1px solid var(--butex-document2-border);
|
|
15320
|
+
border-radius: 8px;
|
|
15321
|
+
box-shadow: 0 8px 24px color-mix(in srgb, var(--butex-document2-fg) 16%, transparent);
|
|
15322
|
+
display: grid;
|
|
15323
|
+
gap: 2px;
|
|
15324
|
+
inset-inline-start: 0;
|
|
15325
|
+
margin-top: 4px;
|
|
15326
|
+
min-width: max-content;
|
|
15327
|
+
padding: 4px;
|
|
15328
|
+
position: absolute;
|
|
15329
|
+
top: 100%;
|
|
15330
|
+
z-index: 30;
|
|
15331
|
+
}
|
|
15332
|
+
|
|
15333
|
+
.butex-document2-widget__references-menu-options button {
|
|
15334
|
+
align-items: center;
|
|
15335
|
+
background: transparent;
|
|
15336
|
+
border: 0;
|
|
15337
|
+
border-radius: 6px;
|
|
15338
|
+
color: var(--butex-document2-fg);
|
|
15339
|
+
cursor: pointer;
|
|
15340
|
+
display: grid;
|
|
15341
|
+
font: inherit;
|
|
15342
|
+
gap: 8px;
|
|
15343
|
+
grid-template-columns: 18px 1fr;
|
|
15344
|
+
padding: 7px 9px;
|
|
15345
|
+
text-align: start;
|
|
15346
|
+
}
|
|
15347
|
+
|
|
15348
|
+
.butex-document2-widget__references-menu-options button:hover,
|
|
15349
|
+
.butex-document2-widget__references-menu-options button:focus-visible {
|
|
15350
|
+
background: var(--butex-document2-accent-bg);
|
|
15351
|
+
outline: none;
|
|
15352
|
+
}
|
|
15353
|
+
|
|
14968
15354
|
.butex-document2-widget__float-meta {
|
|
14969
15355
|
display: grid;
|
|
14970
15356
|
gap: 8px;
|
|
@@ -15408,6 +15794,19 @@ var DOCUMENT2_WIDGET_CSS = `
|
|
|
15408
15794
|
border-color: color-mix(in srgb, var(--butex-document2-text-token-border) 55%, var(--butex-document2-accent));
|
|
15409
15795
|
}
|
|
15410
15796
|
|
|
15797
|
+
.butex-document2-widget__inline-text[data-bold="true"] {
|
|
15798
|
+
font-weight: 700;
|
|
15799
|
+
}
|
|
15800
|
+
|
|
15801
|
+
.butex-document2-widget__inline-text[data-italic="true"] {
|
|
15802
|
+
font-style: italic;
|
|
15803
|
+
}
|
|
15804
|
+
|
|
15805
|
+
.butex-document2-widget__inline-text[data-underline="true"] {
|
|
15806
|
+
text-decoration: underline;
|
|
15807
|
+
text-underline-offset: 0.12em;
|
|
15808
|
+
}
|
|
15809
|
+
|
|
15411
15810
|
.butex-document2-widget__inline-field input {
|
|
15412
15811
|
min-width: 12ch;
|
|
15413
15812
|
}
|
|
@@ -16425,6 +16824,50 @@ function topLevelBlockIdForField(document2, fieldId) {
|
|
|
16425
16824
|
function topLevelBlockIdForToken(document2, tokenId) {
|
|
16426
16825
|
return document2.blocks.find((block) => blockHasToken(block, tokenId))?.id ?? null;
|
|
16427
16826
|
}
|
|
16827
|
+
function findFormatTextToken(document2, focus) {
|
|
16828
|
+
if (!focus.fieldId || !focus.textTokenId || focus.selectionEnd <= focus.selectionStart) {
|
|
16829
|
+
return null;
|
|
16830
|
+
}
|
|
16831
|
+
function textTokenFromField(field) {
|
|
16832
|
+
if (field.id !== focus.fieldId) {
|
|
16833
|
+
return null;
|
|
16834
|
+
}
|
|
16835
|
+
const token = field.tokens.find((entry) => entry.id === focus.textTokenId && entry.kind === "text");
|
|
16836
|
+
return token ?? null;
|
|
16837
|
+
}
|
|
16838
|
+
function visit(blocks) {
|
|
16839
|
+
for (const block of blocks) {
|
|
16840
|
+
if (block.kind === "textBlock") {
|
|
16841
|
+
const token = block.command === "\\paragraph" ? textTokenFromField(block.field) : null;
|
|
16842
|
+
if (token) {
|
|
16843
|
+
return token;
|
|
16844
|
+
}
|
|
16845
|
+
} else if (block.kind === "list") {
|
|
16846
|
+
for (const item of block.items) {
|
|
16847
|
+
const itemToken = textTokenFromField(item.field);
|
|
16848
|
+
if (itemToken) {
|
|
16849
|
+
return itemToken;
|
|
16850
|
+
}
|
|
16851
|
+
const nestedToken = visit(item.blocks);
|
|
16852
|
+
if (nestedToken) {
|
|
16853
|
+
return nestedToken;
|
|
16854
|
+
}
|
|
16855
|
+
}
|
|
16856
|
+
} else if (block.kind === "table") {
|
|
16857
|
+
for (const row of block.rows) {
|
|
16858
|
+
for (const cell of row) {
|
|
16859
|
+
const token = textTokenFromField(cell);
|
|
16860
|
+
if (token) {
|
|
16861
|
+
return token;
|
|
16862
|
+
}
|
|
16863
|
+
}
|
|
16864
|
+
}
|
|
16865
|
+
}
|
|
16866
|
+
}
|
|
16867
|
+
return null;
|
|
16868
|
+
}
|
|
16869
|
+
return visit(document2.blocks);
|
|
16870
|
+
}
|
|
16428
16871
|
function formatDocument2Diagnostic(d, messages) {
|
|
16429
16872
|
if (d.message === "math_objects order mismatch") {
|
|
16430
16873
|
return `${messages.importOrderMismatch} ${messages.path}: ${d.path}`;
|
|
@@ -16510,13 +16953,13 @@ function ButexDocumentEditor2({
|
|
|
16510
16953
|
const [blockSelectionState, setBlockSelectionState] = useState12(emptyBlockSelection);
|
|
16511
16954
|
const [historyTick, setHistoryTick] = useState12(0);
|
|
16512
16955
|
const digitForm = digitFormProp ?? digitFormState ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
|
|
16513
|
-
const historyRef =
|
|
16514
|
-
const documentRef =
|
|
16515
|
-
const textSnapshotArmedRef =
|
|
16516
|
-
const textDebounceRef =
|
|
16517
|
-
const widgetRef =
|
|
16518
|
-
const articleMetaPanelRef =
|
|
16519
|
-
const pendingFocusRef =
|
|
16956
|
+
const historyRef = useRef8(createDocument2History());
|
|
16957
|
+
const documentRef = useRef8(documentNode);
|
|
16958
|
+
const textSnapshotArmedRef = useRef8(false);
|
|
16959
|
+
const textDebounceRef = useRef8(null);
|
|
16960
|
+
const widgetRef = useRef8(null);
|
|
16961
|
+
const articleMetaPanelRef = useRef8(null);
|
|
16962
|
+
const pendingFocusRef = useRef8(null);
|
|
16520
16963
|
documentRef.current = documentNode;
|
|
16521
16964
|
const latex = document2Latex(documentNode);
|
|
16522
16965
|
const documentLabels = useMemo2(() => collectDocument2Labels(documentNode), [documentNode]);
|
|
@@ -16543,6 +16986,9 @@ function ButexDocumentEditor2({
|
|
|
16543
16986
|
const selectionCount = blockSelection ? blockSelection.to - blockSelection.from + 1 : 0;
|
|
16544
16987
|
const canMoveSelectionUp = Boolean(blockSelection && blockSelection.from > 0);
|
|
16545
16988
|
const canMoveSelectionDown = Boolean(blockSelection && blockSelection.to < documentNode.blocks.length - 1);
|
|
16989
|
+
const formatTextToken = useMemo2(() => findFormatTextToken(documentNode, editorFocus), [documentNode, editorFocus]);
|
|
16990
|
+
const canFormatText = formatTextToken !== null;
|
|
16991
|
+
const activeTextStyles = formatTextToken?.style ?? {};
|
|
16546
16992
|
function clearBlockSelection() {
|
|
16547
16993
|
setBlockSelectionState(emptyBlockSelection());
|
|
16548
16994
|
}
|
|
@@ -16580,15 +17026,15 @@ function ButexDocumentEditor2({
|
|
|
16580
17026
|
applyDocument(removeDocument2BlockRange(documentRef.current, selection.from, selection.to), "immediate");
|
|
16581
17027
|
clearBlockSelection();
|
|
16582
17028
|
}
|
|
16583
|
-
|
|
17029
|
+
useEffect9(() => {
|
|
16584
17030
|
injectBuTeXDocument2Styles();
|
|
16585
17031
|
}, []);
|
|
16586
|
-
|
|
17032
|
+
useEffect9(() => {
|
|
16587
17033
|
if (!editableEquations || previewOnly) {
|
|
16588
17034
|
setSelectedMath(null);
|
|
16589
17035
|
}
|
|
16590
17036
|
}, [editableEquations, previewOnly]);
|
|
16591
|
-
|
|
17037
|
+
useEffect9(() => {
|
|
16592
17038
|
const next = resolveInitialDocument2(initialDocument, uiLocale, documentMeta);
|
|
16593
17039
|
setDocumentNode(next.document);
|
|
16594
17040
|
setError(next.error);
|
|
@@ -16597,13 +17043,13 @@ function ButexDocumentEditor2({
|
|
|
16597
17043
|
historyRef.current = createDocument2History();
|
|
16598
17044
|
setHistoryTick((tick) => tick + 1);
|
|
16599
17045
|
}, [initialDocument, documentMeta, uiLocale]);
|
|
16600
|
-
|
|
17046
|
+
useEffect9(() => {
|
|
16601
17047
|
onDocumentChange?.(documentNode);
|
|
16602
17048
|
}, [documentNode, onDocumentChange]);
|
|
16603
|
-
|
|
17049
|
+
useEffect9(() => {
|
|
16604
17050
|
onLatexChange?.(latex);
|
|
16605
17051
|
}, [latex, onLatexChange]);
|
|
16606
|
-
|
|
17052
|
+
useEffect9(() => {
|
|
16607
17053
|
const pending = pendingFocusRef.current;
|
|
16608
17054
|
const root = widgetRef.current;
|
|
16609
17055
|
if (!pending || !root) {
|
|
@@ -16719,7 +17165,7 @@ function ButexDocumentEditor2({
|
|
|
16719
17165
|
function openAllBlocks() {
|
|
16720
17166
|
setCollapsedBlockIds(/* @__PURE__ */ new Set());
|
|
16721
17167
|
}
|
|
16722
|
-
|
|
17168
|
+
useEffect9(() => {
|
|
16723
17169
|
const root = widgetRef.current;
|
|
16724
17170
|
if (!root) {
|
|
16725
17171
|
return;
|
|
@@ -16743,15 +17189,15 @@ function ButexDocumentEditor2({
|
|
|
16743
17189
|
root.addEventListener("keydown", onKeyDown);
|
|
16744
17190
|
return () => root.removeEventListener("keydown", onKeyDown);
|
|
16745
17191
|
}, [editorOpen]);
|
|
16746
|
-
function rememberFieldFocus(blockId, fieldId, textTokenId, caretOffset) {
|
|
17192
|
+
function rememberFieldFocus(blockId, fieldId, textTokenId, caretOffset, selectionStart, selectionEnd) {
|
|
16747
17193
|
openBlock(blockId);
|
|
16748
17194
|
clearBlockSelection();
|
|
16749
|
-
setEditorFocus({ blockId, fieldId, textTokenId, caretOffset });
|
|
17195
|
+
setEditorFocus({ blockId, fieldId, textTokenId, caretOffset, selectionStart, selectionEnd });
|
|
16750
17196
|
}
|
|
16751
17197
|
function rememberMathFocus(blockId, fieldId) {
|
|
16752
17198
|
openBlock(blockId);
|
|
16753
17199
|
clearBlockSelection();
|
|
16754
|
-
setEditorFocus({ blockId, fieldId, textTokenId: null, caretOffset: 0 });
|
|
17200
|
+
setEditorFocus({ blockId, fieldId, textTokenId: null, caretOffset: 0, selectionStart: 0, selectionEnd: 0 });
|
|
16755
17201
|
}
|
|
16756
17202
|
function rememberBlockFocus(blockId) {
|
|
16757
17203
|
openBlock(blockId);
|
|
@@ -17014,6 +17460,22 @@ function ButexDocumentEditor2({
|
|
|
17014
17460
|
function deleteRefToken(tokenId) {
|
|
17015
17461
|
applyDocument(removeRefTokenById(documentRef.current, tokenId), "immediate");
|
|
17016
17462
|
}
|
|
17463
|
+
function toggleInlineTextStyle(styleName) {
|
|
17464
|
+
if (!canFormatText || !editorFocus.fieldId || !editorFocus.textTokenId) {
|
|
17465
|
+
return;
|
|
17466
|
+
}
|
|
17467
|
+
applyDocument(
|
|
17468
|
+
toggleTextTokenStyle(
|
|
17469
|
+
documentRef.current,
|
|
17470
|
+
editorFocus.fieldId,
|
|
17471
|
+
editorFocus.textTokenId,
|
|
17472
|
+
editorFocus.selectionStart,
|
|
17473
|
+
editorFocus.selectionEnd,
|
|
17474
|
+
styleName
|
|
17475
|
+
),
|
|
17476
|
+
"immediate"
|
|
17477
|
+
);
|
|
17478
|
+
}
|
|
17017
17479
|
const showEditorPanel = !previewOnly && editorOpen;
|
|
17018
17480
|
const showPreviewPanel = previewOnly || previewOpen;
|
|
17019
17481
|
return /* @__PURE__ */ jsx17(
|
|
@@ -17036,8 +17498,11 @@ function ButexDocumentEditor2({
|
|
|
17036
17498
|
selectionCount,
|
|
17037
17499
|
canMoveSelectionUp,
|
|
17038
17500
|
canMoveSelectionDown,
|
|
17501
|
+
canFormatText,
|
|
17502
|
+
activeTextStyles,
|
|
17039
17503
|
onUndo: undoDocument,
|
|
17040
17504
|
onRedo: redoDocument,
|
|
17505
|
+
onToggleTextStyle: toggleInlineTextStyle,
|
|
17041
17506
|
onMoveSelectionUp: () => moveSelectedBlocks(-1),
|
|
17042
17507
|
onMoveSelectionDown: () => moveSelectedBlocks(1),
|
|
17043
17508
|
onDeleteSelection: deleteSelectedBlocks,
|