@drghaliasri/butex 5.3.0 → 5.3.2

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.
@@ -38,9 +38,11 @@ function formatDigits(value, digitForm = "western") {
38
38
  }
39
39
 
40
40
  // src/document2/articleMeta.ts
41
- var BUTEX_BASMALA_LINE1 = "\u0628\u0650\u0633\u0652\u0645\u0650 \u0627\u0644\u0644\u064E\u0651\u0647\u0650 \u0627\u0644\u0631\u064E\u0651\u062D\u0652\u0645\u064E\u0670\u0646\u0650 \u0627\u0644\u0631\u064E\u0651\u062D\u0650\u064A\u0645\u0650";
42
- var BUTEX_BASMALA_SALAWAT = "\u0635\u064E\u0644\u064E\u0651\u0649 \u0627\u0644\u0644\u064E\u0651\u0647\u064F \u0639\u064E\u0644\u064E\u064A\u0652\u0647\u0650 \u0648\u064E\u0633\u064E\u0644\u064E\u0651\u0645\u064E";
41
+ var BUTEX_BASMALA_LINE1 = "\u0628\u0650\u0633\u0652\u0645\u0650 \u0671\u0644\u0644\u064E\u0651\u0670\u0647\u0650 \u0671\u0644\u0631\u064E\u0651\u062D\u0652\u0645\u064E\u0670\u0646\u0650 \u0671\u0644\u0631\u064E\u0651\u062D\u0650\u064A\u0645\u0650";
42
+ var BUTEX_BASMALA_LINE2 = "\u0648\u064E\u0671\u0644\u0635\u064E\u0651\u0644\u064E\u0627\u0629\u064F \u0648\u064E\u0671\u0644\u0633\u064E\u0651\u0644\u064E\u0627\u0645\u064F \u0639\u064E\u0644\u064E\u0649\u0670 \u0631\u064E\u0633\u064F\u0648\u0644\u0650 \u0671\u0644\u0644\u064E\u0651\u0670\u0647\u0650";
43
+ var BUTEX_BASMALA_SALAWAT = "\u0635\u064E\u0644\u064E\u0651\u0649 \u0671\u0644\u0644\u064E\u0651\u0647\u064F \u0639\u064E\u0644\u064E\u064A\u0652\u0647\u0650 \u0648\u064E\u0633\u064E\u0644\u064E\u0651\u0645\u064E";
43
44
  var BUTEX_BASMALA = `${BUTEX_BASMALA_LINE1}
45
+ ${BUTEX_BASMALA_LINE2}
44
46
  ${BUTEX_BASMALA_SALAWAT}`;
45
47
  var BUTEX_CLOSING_HAMDALA = "\u0627\u0644\u0652\u062D\u064E\u0645\u0652\u062F\u064F \u0644\u0650\u0644\u064E\u0651\u0647\u0650 \u0646\u064E\u0641\u064E\u0639\u064E\u0646\u064E\u0627 \u0628\u0650\u0639\u0650\u0644\u0652\u0645\u0650\u0647\u0650";
46
48
  function escapeButexTextArg(text) {
@@ -54,26 +56,60 @@ function butexDiwaniDisplayLatex(text) {
54
56
  ${butexDiwaniDisplayTex(text)}
55
57
  \\]`;
56
58
  }
59
+ var BASMALA_LINES = [BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT];
57
60
  function butexBasmalaDisplayTex() {
58
- return `${butexDiwaniDisplayTex(BUTEX_BASMALA_LINE1)} \\\\ ${butexDiwaniDisplayTex(BUTEX_BASMALA_SALAWAT)}`;
61
+ return BASMALA_LINES.map((line) => butexDiwaniDisplayTex(line)).join(" \\\\ ");
59
62
  }
60
63
  function butexBasmalaDisplayLatex() {
61
64
  return `\\[
62
65
  ${butexBasmalaDisplayTex()}
63
66
  \\]`;
64
67
  }
65
- function butexBasmalaTitlingPreamble() {
66
- return [
68
+ function butexInColumnMaketitleHook() {
69
+ return String.raw`\makeatletter
70
+ \renewcommand{\maketitle}{%
71
+ \par
72
+ \begingroup
73
+ \renewcommand\thefootnote{\@fnsymbol\c@footnote}%
74
+ \def\@makefnmark{\rlap{\@textsuperscript{\normalfont\@thefnmark}}}%
75
+ \long\def\@makefntext##1{\parindent 1em\noindent
76
+ \hb@xt@1.8em{\hss\@textsuperscript{\normalfont\@thefnmark}}##1}%
77
+ \@maketitle
78
+ \thispagestyle{plain}\@thanks
79
+ \endgroup
80
+ \setcounter{footnote}{0}%
81
+ \global\let\thanks\relax
82
+ \global\let\maketitle\relax
83
+ \global\let\@maketitle\relax
84
+ \global\let\@thanks\@empty
85
+ \global\let\@author\@empty
86
+ \global\let\@date\@empty
87
+ \global\let\@title\@empty
88
+ \global\let\title\relax
89
+ \global\let\author\relax
90
+ \global\let\date\relax
91
+ \global\let\and\relax
92
+ }
93
+ \makeatother`;
94
+ }
95
+ function butexBasmalaTitlingPreamble(options = {}) {
96
+ const lines = [
67
97
  "\\usepackage{titling}",
68
98
  "\\pretitle{%",
69
99
  " \\begin{center}",
70
- ` ${butexDiwaniDisplayTex(BUTEX_BASMALA_LINE1)}\\\\`,
71
- ` ${butexDiwaniDisplayTex(BUTEX_BASMALA_SALAWAT)}`,
100
+ ...BASMALA_LINES.map((line, index) => {
101
+ const suffix = index < BASMALA_LINES.length - 1 ? "\\\\" : "";
102
+ return ` ${butexDiwaniDisplayTex(line)}${suffix}`;
103
+ }),
72
104
  " \\par\\vspace{1.5em}",
73
105
  " \\LARGE",
74
106
  "}",
75
107
  "\\posttitle{\\par\\end{center}}"
76
- ].join("\n");
108
+ ];
109
+ if (options.twocolumn) {
110
+ lines.push(butexInColumnMaketitleHook());
111
+ }
112
+ return lines.join("\n");
77
113
  }
78
114
  var HIJRI_YEAR_MIN = 1400;
79
115
  var HIJRI_YEAR_MAX = 1500;
@@ -232,6 +268,10 @@ function cloneDocument2Meta(meta) {
232
268
  }
233
269
 
234
270
  // src/document2/citations.ts
271
+ var DEFAULT_REFERENCE_FIELD_SEPARATOR = "\u060C";
272
+ function normalizeReferenceFieldSeparator(value) {
273
+ return value === "," ? "," : DEFAULT_REFERENCE_FIELD_SEPARATOR;
274
+ }
235
275
  function referenceNumberMap(references) {
236
276
  const map = /* @__PURE__ */ new Map();
237
277
  references.forEach((reference, index) => {
@@ -277,7 +317,8 @@ function referenceFromJson(json) {
277
317
  title: typeof json.title === "string" ? json.title : "",
278
318
  year: typeof json.year === "string" ? json.year : "",
279
319
  url: typeof json.url === "string" ? json.url : "",
280
- venue: typeof json.venue === "string" ? json.venue : ""
320
+ venue: typeof json.venue === "string" ? json.venue : "",
321
+ fieldSeparator: normalizeReferenceFieldSeparator(json.field_separator)
281
322
  };
282
323
  }
283
324
  function createEmptyReference2(partial = {}) {
@@ -287,15 +328,33 @@ function createEmptyReference2(partial = {}) {
287
328
  title: partial.title,
288
329
  year: partial.year,
289
330
  url: partial.url,
290
- venue: partial.venue
331
+ venue: partial.venue,
332
+ field_separator: partial.field_separator
291
333
  });
292
334
  }
335
+ function bibliographyEntryBody(reference, separator = reference.fieldSeparator, options = {}) {
336
+ const year = options.digitForm !== void 0 ? formatDigits(reference.year, options.digitForm) : reference.year;
337
+ const parts = [reference.authors, reference.title, reference.venue, year].filter((part) => part.trim().length > 0);
338
+ return parts.join(`${separator} `);
339
+ }
293
340
  function bibliographyEntryLatex(reference) {
294
- const parts = [reference.authors, reference.title, reference.venue, reference.year].filter((part) => part.trim().length > 0);
295
- const body = parts.join(", ");
341
+ const body = bibliographyEntryBody(reference);
296
342
  const url = reference.url.trim().length > 0 ? ` \\url{${reference.url}}` : "";
297
343
  return `\\bibitem{${reference.key}} ${body}${url}`.trim();
298
344
  }
345
+ function absoluteHttpHref(url) {
346
+ const trimmed = url.trim();
347
+ if (trimmed.length === 0) {
348
+ return "";
349
+ }
350
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
351
+ return trimmed;
352
+ }
353
+ if (trimmed.startsWith("//")) {
354
+ return `https:${trimmed}`;
355
+ }
356
+ return `https://${trimmed}`;
357
+ }
299
358
 
300
359
  // src/ast/commands/index.ts
301
360
  function renderCommandCore(context) {
@@ -780,6 +839,23 @@ function labelNumberMap(document2) {
780
839
  }
781
840
  return map;
782
841
  }
842
+ function formatFloatCaptionTitle(kind, number, options = {}) {
843
+ const locale = options.uiLocale ?? "ar";
844
+ const kindWord = kind === "fig" ? locale === "ar" ? "\u0627\u0644\u0634\u0643\u0644" : "Figure" : kind === "tab" ? locale === "ar" ? "\u0627\u0644\u062C\u062F\u0648\u0644" : "Table" : locale === "ar" ? "\u0627\u0644\u0645\u0639\u0627\u062F\u0644\u0629" : "Equation";
845
+ const digits = formatBibliographyNumber(number, {
846
+ documentDirection: options.documentDirection ?? (locale === "ar" ? "rtl" : "ltr"),
847
+ digitForm: options.digitForm ?? (locale === "ar" ? "arabicIndic" : "western")
848
+ });
849
+ return `${kindWord} ${digits}`;
850
+ }
851
+ function formatFloatCaptionPreview(title, caption, uiLocale = "ar") {
852
+ const trimmed = caption?.trim() ?? "";
853
+ if (trimmed.length === 0) {
854
+ return title;
855
+ }
856
+ const separator = uiLocale === "ar" ? ": " : ". ";
857
+ return `${title}${separator}${trimmed}`;
858
+ }
783
859
  function formatRefLabel(keys, document2, refCommand, options = {}) {
784
860
  const documentDirection = options.documentDirection ?? "rtl";
785
861
  const digitForm = options.digitForm ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
@@ -1050,7 +1126,8 @@ function parseReferences(json) {
1050
1126
  title: typeof entry.title === "string" ? entry.title : void 0,
1051
1127
  year: typeof entry.year === "string" ? entry.year : void 0,
1052
1128
  url: typeof entry.url === "string" ? entry.url : void 0,
1053
- venue: typeof entry.venue === "string" ? entry.venue : void 0
1129
+ venue: typeof entry.venue === "string" ? entry.venue : void 0,
1130
+ field_separator: entry.field_separator === "," || entry.field_separator === "\u060C" ? entry.field_separator : void 0
1054
1131
  })
1055
1132
  );
1056
1133
  }
@@ -7197,7 +7274,7 @@ function addDocument2ImageBlock(document2, src = "", afterBlockId) {
7197
7274
  kind: "image",
7198
7275
  command: "\\includegraphics",
7199
7276
  value: src,
7200
- options: { width: "0.8\\textwidth" },
7277
+ options: { width: "0.8\\columnwidth" },
7201
7278
  ...defaultFloatMeta()
7202
7279
  };
7203
7280
  return insertDocument2BlockAfter(document2, afterBlockId, block);
@@ -7482,6 +7559,9 @@ function updateDocument2Reference(document2, referenceId, patch) {
7482
7559
  if (typeof patch.venue === "string") {
7483
7560
  reference.venue = patch.venue;
7484
7561
  }
7562
+ if (patch.field_separator === "," || patch.field_separator === "\u060C") {
7563
+ reference.fieldSeparator = patch.field_separator;
7564
+ }
7485
7565
  return next;
7486
7566
  }
7487
7567
  function removeDocument2Reference(document2, referenceId) {
@@ -7515,6 +7595,48 @@ function updateDocument2Meta(document2, patch) {
7515
7595
  return next;
7516
7596
  }
7517
7597
 
7598
+ // src/document2/keys.ts
7599
+ var DOCUMENT2_KEY_PATTERN = /^[\p{L}\p{M}0-9:._-]+$/u;
7600
+ function normalizeDocument2Key(key) {
7601
+ return key.normalize("NFC").trim();
7602
+ }
7603
+ function isDuplicateDocument2Key(key, namespace) {
7604
+ const normalized = normalizeDocument2Key(key);
7605
+ if (normalized.length === 0) {
7606
+ return false;
7607
+ }
7608
+ for (const reference of namespace.references ?? []) {
7609
+ if (namespace.excludeReferenceId && reference.id === namespace.excludeReferenceId) {
7610
+ continue;
7611
+ }
7612
+ if (normalizeDocument2Key(reference.key) === normalized) {
7613
+ return true;
7614
+ }
7615
+ }
7616
+ for (const label of namespace.labels ?? []) {
7617
+ if (namespace.excludeOwnerId && label.ownerId === namespace.excludeOwnerId) {
7618
+ continue;
7619
+ }
7620
+ if (normalizeDocument2Key(label.key) === normalized) {
7621
+ return true;
7622
+ }
7623
+ }
7624
+ return false;
7625
+ }
7626
+ function document2KeyError(key, namespace = {}) {
7627
+ const normalized = normalizeDocument2Key(key);
7628
+ if (normalized.length === 0) {
7629
+ return "empty";
7630
+ }
7631
+ if (!DOCUMENT2_KEY_PATTERN.test(normalized)) {
7632
+ return "invalid";
7633
+ }
7634
+ if (isDuplicateDocument2Key(normalized, namespace)) {
7635
+ return "duplicate";
7636
+ }
7637
+ return null;
7638
+ }
7639
+
7518
7640
  // src/document2/arabicPreamble.ts
7519
7641
  function arabicXeLatexPreamblePkg(twocolumn = false) {
7520
7642
  const classOptions = twocolumn ? "12pt,a4paper,notitlepage,twocolumn" : "12pt,a4paper,notitlepage";
@@ -7797,8 +7919,16 @@ function tableBlockLatex(block) {
7797
7919
  lines.push("\\end{table}");
7798
7920
  return lines.join("\n");
7799
7921
  }
7800
- function imageOptionsLatex(block) {
7801
- const entries = Object.entries(block.options);
7922
+ function remapImageWidthForColumns(value) {
7923
+ return value.replace(/\\textwidth\b/g, "\\columnwidth");
7924
+ }
7925
+ function imageOptionsLatex(block, constrainToColumn) {
7926
+ const entries = Object.entries(block.options).map(([key, value]) => {
7927
+ if (constrainToColumn && key === "width") {
7928
+ return [key, remapImageWidthForColumns(value)];
7929
+ }
7930
+ return [key, value];
7931
+ });
7802
7932
  if (entries.length === 0) {
7803
7933
  return "";
7804
7934
  }
@@ -7809,7 +7939,7 @@ function imageBlockLatex(block) {
7809
7939
  if (block.centered) {
7810
7940
  lines.push(" \\centering");
7811
7941
  }
7812
- lines.push(` ${block.command}${imageOptionsLatex(block)}{${block.value}}`);
7942
+ lines.push(` ${block.command}${imageOptionsLatex(block, true)}{${block.value}}`);
7813
7943
  lines.push(...floatCaptionLabelLines(block));
7814
7944
  lines.push("\\end{figure}");
7815
7945
  return lines.join("\n");
@@ -7839,11 +7969,11 @@ ${block.closing}`;
7839
7969
  function authorLatex(authors) {
7840
7970
  return authors.split(/\n+/).map((line) => line.trim()).filter((line) => line.length > 0).join(" \\\\ ");
7841
7971
  }
7842
- function articleMaketitlePreamble(meta) {
7972
+ function articleMaketitlePreamble(meta, twocolumn = false) {
7843
7973
  if (!document2HasMaketitle(meta)) {
7844
7974
  return "";
7845
7975
  }
7846
- const parts = [butexBasmalaTitlingPreamble()];
7976
+ const parts = [butexBasmalaTitlingPreamble({ twocolumn })];
7847
7977
  if (meta.title.trim().length > 0) {
7848
7978
  parts.push(`\\title{${meta.title.trim()}}`);
7849
7979
  }
@@ -7869,21 +7999,22 @@ ${meta.abstract.trim()}
7869
7999
  }
7870
8000
  function document2Latex(document2, options = {}) {
7871
8001
  const meta = document2.meta ?? emptyDocument2Meta();
8002
+ const twocolumn = options.twocolumn === true;
7872
8003
  const front = articleFrontMatterLatex(meta);
7873
8004
  const bodyBlocks = document2.blocks.map((block) => blockLatex(block, document2.references));
7874
8005
  const closing = butexDiwaniDisplayLatex(BUTEX_CLOSING_HAMDALA);
7875
8006
  const body = [...front, ...bodyBlocks, closing].filter((part) => part.length > 0).join("\n\n");
7876
8007
  const wrapDocument = options.wrapDocument !== false;
7877
8008
  if (!wrapDocument) {
7878
- const metaPreamble = articleMaketitlePreamble(meta);
8009
+ const metaPreamble = articleMaketitlePreamble(meta, twocolumn);
7879
8010
  return metaPreamble.length > 0 ? `${metaPreamble}
7880
8011
 
7881
8012
  ${body}` : body;
7882
8013
  }
7883
8014
  const preamble = getArabicXeLatexPreamble({
7884
8015
  digitsMapping: options.digitsMapping ?? "arabicdigits",
7885
- twocolumn: options.twocolumn === true
7886
- }) + "\n" + articleMaketitlePreamble(meta);
8016
+ twocolumn
8017
+ }) + "\n" + articleMaketitlePreamble(meta, twocolumn);
7887
8018
  return `${preamble}
7888
8019
  \\begin{document}
7889
8020
 
@@ -8056,13 +8187,11 @@ function floatNumberLabel(document2, key, previewOptions) {
8056
8187
  if (!hit || hit.kind !== "fig" && hit.kind !== "tab") {
8057
8188
  return void 0;
8058
8189
  }
8059
- const locale = previewOptions.uiLocale ?? "ar";
8060
- const kindWord = hit.kind === "fig" ? locale === "ar" ? "\u0627\u0644\u0634\u0643\u0644" : "Figure" : locale === "ar" ? "\u0627\u0644\u062C\u062F\u0648\u0644" : "Table";
8061
- const digits = formatBibliographyNumber(hit.number, {
8190
+ return formatFloatCaptionTitle(hit.kind, hit.number, {
8191
+ uiLocale: previewOptions.uiLocale ?? "ar",
8062
8192
  documentDirection: previewOptions.documentDirection,
8063
8193
  digitForm: previewOptions.digitForm
8064
8194
  });
8065
- return `${kindWord} ${digits}`;
8066
8195
  }
8067
8196
  function blockPreview(block, islands, output, equationSide, document2, previewOptions) {
8068
8197
  if (block.kind === "textBlock") {
@@ -8117,7 +8246,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
8117
8246
  title: reference.title,
8118
8247
  year: reference.year,
8119
8248
  url: reference.url,
8120
- venue: reference.venue
8249
+ venue: reference.venue,
8250
+ fieldSeparator: reference.fieldSeparator
8121
8251
  }))
8122
8252
  };
8123
8253
  }
@@ -8268,6 +8398,15 @@ var DOCUMENT2_MESSAGES = {
8268
8398
  labelKindFig: "\u0634\u0643\u0644",
8269
8399
  labelKindTab: "\u062C\u062F\u0648\u0644",
8270
8400
  labelKindEq: "\u0645\u0639\u0627\u062F\u0644\u0629",
8401
+ captionPreview: "\u0645\u0639\u0627\u064A\u0646\u0629 \u0627\u0644\u062A\u0639\u0644\u064A\u0642",
8402
+ referencePreview: "\u0645\u0639\u0627\u064A\u0646\u0629 \u0627\u0644\u0645\u0631\u062C\u0639",
8403
+ referenceFieldSeparator: "\u0641\u0627\u0635\u0644 \u0627\u0644\u062D\u0642\u0648\u0644",
8404
+ referenceCommaLtr: "\u0641\u0627\u0635\u0644\u0629 \u0625\u0646\u062C\u0644\u064A\u0632\u064A\u0629 ,",
8405
+ referenceCommaRtl: "\u0641\u0627\u0635\u0644\u0629 \u0639\u0631\u0628\u064A\u0629 \u060C",
8406
+ keyEmpty: "\u0627\u0644\u0645\u0641\u062A\u0627\u062D \u0645\u0637\u0644\u0648\u0628",
8407
+ keyInvalid: "\u0627\u0644\u0645\u0641\u062A\u0627\u062D \u063A\u064A\u0631 \u0635\u0627\u0644\u062D: \u0628\u062F\u0648\u0646 \u0645\u0633\u0627\u0641\u0627\u062A\u060C \u0648\u064A\u064F\u0633\u0645\u062D \u0628\u0627\u0644\u062D\u0631\u0648\u0641 \u0648\u0627\u0644\u0623\u0631\u0642\u0627\u0645 \u0648`:._-` \u0641\u0642\u0637",
8408
+ keyDuplicate: "\u0647\u0630\u0627 \u0627\u0644\u0645\u0641\u062A\u0627\u062D \u0645\u0633\u062A\u062E\u062F\u0645 \u0645\u0633\u0628\u0642\u0627\u064B",
8409
+ keyRulesHint: "\u062D\u0631\u0648\u0641 (\u0639\u0631\u0628\u064A\u0629 \u0623\u0648 \u0644\u0627\u062A\u064A\u0646\u064A\u0629) \u0648\u0623\u0631\u0642\u0627\u0645 \u0648`:._-` \u0628\u062F\u0648\u0646 \u0645\u0633\u0627\u0641\u0627\u062A",
8271
8410
  citePickerTitle: "\u0627\u062E\u062A\u064A\u0627\u0631 \u0627\u0644\u0645\u0631\u0627\u062C\u0639",
8272
8411
  noReferencesYet: "\u0644\u0627 \u062A\u0648\u062C\u062F \u0645\u0631\u0627\u062C\u0639 \u0628\u0639\u062F. \u0623\u0636\u0641 \u0645\u0631\u062C\u0639\u0627\u064B \u0623\u0648\u0644\u0627\u064B.",
8273
8412
  editCitation: "\u062A\u062D\u0631\u064A\u0631 \u0627\u0644\u0627\u0642\u062A\u0628\u0627\u0633",
@@ -8398,6 +8537,15 @@ var DOCUMENT2_MESSAGES = {
8398
8537
  labelKindFig: "Figure",
8399
8538
  labelKindTab: "Table",
8400
8539
  labelKindEq: "Equation",
8540
+ captionPreview: "Caption preview",
8541
+ referencePreview: "Reference preview",
8542
+ referenceFieldSeparator: "Field separator",
8543
+ referenceCommaLtr: "Latin comma ,",
8544
+ referenceCommaRtl: "Arabic comma \u060C",
8545
+ keyEmpty: "Key is required",
8546
+ keyInvalid: "Invalid key: letters, digits, and `:._-` only; no spaces",
8547
+ keyDuplicate: "This key is already in use",
8548
+ keyRulesHint: "Letters (Arabic or Latin), digits, and `:._-`; no spaces",
8401
8549
  citePickerTitle: "Select references",
8402
8550
  noReferencesYet: "No references yet. Add a reference first.",
8403
8551
  editCitation: "Edit citation",
@@ -8528,6 +8676,8 @@ function ArticleMetaPanel({
8528
8676
  /* @__PURE__ */ jsxs("p", { className: "butex-document2-widget__article-meta-fixed", dir: "rtl", children: [
8529
8677
  BUTEX_BASMALA_LINE1,
8530
8678
  /* @__PURE__ */ jsx("br", {}),
8679
+ BUTEX_BASMALA_LINE2,
8680
+ /* @__PURE__ */ jsx("br", {}),
8531
8681
  BUTEX_BASMALA_SALAWAT
8532
8682
  ] }),
8533
8683
  /* @__PURE__ */ jsxs("div", { className: "butex-document2-widget__article-meta-grid", children: [
@@ -8633,7 +8783,10 @@ function focusArticleMetaPanel(panel) {
8633
8783
  }
8634
8784
 
8635
8785
  // src/react-document2/ButexDocumentEditor2.tsx
8636
- import { useCallback as useCallback2, useEffect as useEffect8, useMemo, useRef as useRef7, useState as useState9 } from "react";
8786
+ import { useCallback as useCallback2, useEffect as useEffect8, useMemo as useMemo2, useRef as useRef7, useState as useState12 } from "react";
8787
+
8788
+ // src/react-document2/BlockEditor.tsx
8789
+ import { useState as useState3 } from "react";
8637
8790
 
8638
8791
  // src/react-document2/InlineField.tsx
8639
8792
  import { useRef as useRef3 } from "react";
@@ -9670,6 +9823,18 @@ function inlineFieldSummary(field) {
9670
9823
  }).join("")
9671
9824
  );
9672
9825
  }
9826
+ function keyErrorMessage(error, messages) {
9827
+ if (error === "empty") {
9828
+ return messages.keyEmpty;
9829
+ }
9830
+ if (error === "invalid") {
9831
+ return messages.keyInvalid;
9832
+ }
9833
+ if (error === "duplicate") {
9834
+ return messages.keyDuplicate;
9835
+ }
9836
+ return null;
9837
+ }
9673
9838
  function FloatMetaEditor({
9674
9839
  captionEnabled,
9675
9840
  caption,
@@ -9678,8 +9843,18 @@ function FloatMetaEditor({
9678
9843
  labelPlaceholder,
9679
9844
  labelDir,
9680
9845
  messages,
9846
+ ownerId,
9847
+ references,
9848
+ labels,
9681
9849
  onChange
9682
9850
  }) {
9851
+ const [labelOverride, setLabelOverride] = useState3(null);
9852
+ const displayedLabel = labelOverride ?? label;
9853
+ const labelError = labelEnabled ? document2KeyError(displayedLabel, {
9854
+ references,
9855
+ labels,
9856
+ excludeOwnerId: ownerId
9857
+ }) : null;
9683
9858
  return /* @__PURE__ */ jsxs5("div", { className: "butex-document2-widget__float-meta", children: [
9684
9859
  /* @__PURE__ */ jsxs5("label", { className: "butex-document2-widget__float-meta-toggle", children: [
9685
9860
  /* @__PURE__ */ jsx7(
@@ -9729,15 +9904,27 @@ function FloatMetaEditor({
9729
9904
  /* @__PURE__ */ jsx7(
9730
9905
  "input",
9731
9906
  {
9732
- value: label,
9907
+ value: displayedLabel,
9733
9908
  dir: labelDir,
9734
9909
  placeholder: labelPlaceholder,
9910
+ "aria-invalid": labelError !== null ? true : void 0,
9735
9911
  onChange: (event) => {
9736
9912
  const value = event.currentTarget.value;
9913
+ setLabelOverride(value);
9914
+ const error = document2KeyError(value, {
9915
+ references,
9916
+ labels,
9917
+ excludeOwnerId: ownerId
9918
+ });
9919
+ if (error !== null) {
9920
+ return;
9921
+ }
9737
9922
  onChange({ label: value });
9923
+ setLabelOverride(null);
9738
9924
  }
9739
9925
  }
9740
- )
9926
+ ),
9927
+ labelError !== null ? /* @__PURE__ */ jsx7("p", { className: "butex-document2-widget__field-error", children: labelError === "invalid" ? messages.keyRulesHint : keyErrorMessage(labelError, messages) }) : null
9741
9928
  ] }) : null
9742
9929
  ] });
9743
9930
  }
@@ -9796,6 +9983,8 @@ function BlockEditor({
9796
9983
  onManageReferences
9797
9984
  }) {
9798
9985
  const messages = document2Messages(uiLocale);
9986
+ const labels = documentNode ? collectDocument2Labels(documentNode) : [];
9987
+ const referenceList = references ?? [];
9799
9988
  const showChrome = depth === 0;
9800
9989
  const chromeClass = [
9801
9990
  blockChromeClass(block),
@@ -9958,6 +10147,9 @@ function BlockEditor({
9958
10147
  labelPlaceholder: messages.tableLabelPlaceholder,
9959
10148
  labelDir: uiLocaleDirection(uiLocale),
9960
10149
  messages,
10150
+ ownerId: block.id,
10151
+ references: referenceList,
10152
+ labels,
9961
10153
  onChange: (patch) => onFloatMetaChange?.(block.id, "table", patch)
9962
10154
  }
9963
10155
  )
@@ -10001,6 +10193,9 @@ function BlockEditor({
10001
10193
  labelPlaceholder: messages.figureLabelPlaceholder,
10002
10194
  labelDir: uiLocaleDirection(uiLocale),
10003
10195
  messages,
10196
+ ownerId: block.id,
10197
+ references: referenceList,
10198
+ labels,
10004
10199
  onChange: (patch) => onFloatMetaChange?.(block.id, "image", patch)
10005
10200
  }
10006
10201
  )
@@ -10009,14 +10204,16 @@ function BlockEditor({
10009
10204
  if (block.kind === "bibliography") {
10010
10205
  return /* @__PURE__ */ jsxs5("section", { className: chromeClass, children: [
10011
10206
  header,
10012
- /* @__PURE__ */ jsx7("ol", { className: "butex-document2-widget__bibliography-editor", dir: documentDirection, children: references.map((reference, index) => /* @__PURE__ */ jsxs5("li", { children: [
10207
+ /* @__PURE__ */ jsx7("ol", { className: "butex-document2-widget__bibliography-editor", dir: documentDirection, children: referenceList.map((reference, index) => /* @__PURE__ */ jsxs5("li", { children: [
10013
10208
  /* @__PURE__ */ jsxs5("strong", { children: [
10014
10209
  "[",
10015
- index + 1,
10210
+ formatBibliographyNumber(index + 1, { documentDirection, digitForm }),
10016
10211
  "] ",
10017
10212
  reference.key
10018
10213
  ] }),
10019
- /* @__PURE__ */ jsx7("span", { children: [reference.authors, reference.title, reference.venue, reference.year].filter(Boolean).join(" \u2014 ") })
10214
+ /* @__PURE__ */ jsx7("span", { children: bibliographyEntryBody(reference, reference.fieldSeparator, {
10215
+ digitForm: digitForm ?? (documentDirection === "rtl" ? "arabicIndic" : "western")
10216
+ }) })
10020
10217
  ] }, reference.id)) }),
10021
10218
  onManageReferences ? /* @__PURE__ */ jsx7("button", { type: "button", onClick: onManageReferences, children: messages.manageReferences }) : null
10022
10219
  ] });
@@ -10028,19 +10225,21 @@ function BlockEditor({
10028
10225
  }
10029
10226
 
10030
10227
  // src/react-document2/CitePickerPopover.tsx
10031
- import { useEffect as useEffect3, useState as useState3 } from "react";
10228
+ import { useEffect as useEffect3, useState as useState4 } from "react";
10032
10229
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
10033
10230
  function CitePickerPopover({
10034
10231
  open,
10035
10232
  references,
10036
10233
  initialKeys = [],
10037
10234
  uiLocale = "ar",
10235
+ digitForm = "arabicIndic",
10038
10236
  onClose,
10039
10237
  onConfirm,
10040
10238
  onManageReferences
10041
10239
  }) {
10042
10240
  const messages = document2Messages(uiLocale);
10043
- const [selected, setSelected] = useState3(initialKeys);
10241
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
10242
+ const [selected, setSelected] = useState4(initialKeys);
10044
10243
  useEffect3(() => {
10045
10244
  if (open) {
10046
10245
  setSelected(initialKeys);
@@ -10067,12 +10266,13 @@ function CitePickerPopover({
10067
10266
  references.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noReferencesYet }) : /* @__PURE__ */ jsx8("ul", { className: "butex-document2-widget__cite-picker-list", children: references.map((reference, index) => {
10068
10267
  const checked = selected.includes(reference.key);
10069
10268
  const subtitle = [reference.authors, reference.title].filter(Boolean).join(" \u2014 ");
10269
+ const numberLabel = formatBibliographyNumber(index + 1, { documentDirection, digitForm });
10070
10270
  return /* @__PURE__ */ jsx8("li", { children: /* @__PURE__ */ jsxs6("label", { className: "butex-document2-widget__cite-picker-item", children: [
10071
10271
  /* @__PURE__ */ jsx8("input", { type: "checkbox", checked, onChange: () => toggleKey(reference.key) }),
10072
10272
  /* @__PURE__ */ jsxs6("span", { children: [
10073
10273
  /* @__PURE__ */ jsxs6("strong", { children: [
10074
10274
  "[",
10075
- index + 1,
10275
+ numberLabel,
10076
10276
  "] ",
10077
10277
  reference.key
10078
10278
  ] }),
@@ -10100,16 +10300,16 @@ function CitePickerPopover({
10100
10300
  }
10101
10301
 
10102
10302
  // src/react-document2/DocumentInsertToolbar.tsx
10103
- import { useState as useState5 } from "react";
10303
+ import { useState as useState6 } from "react";
10104
10304
 
10105
10305
  // src/react-document2/TableInsertPopover.tsx
10106
- import { useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
10306
+ import { useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
10107
10307
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
10108
10308
  function TableInsertPopover({ uiLocale = "ar", onConfirm }) {
10109
10309
  const messages = document2Messages(uiLocale);
10110
- const [open, setOpen] = useState4(false);
10111
- const [rows, setRows] = useState4("3");
10112
- const [cols, setCols] = useState4("3");
10310
+ const [open, setOpen] = useState5(false);
10311
+ const [rows, setRows] = useState5("3");
10312
+ const [cols, setCols] = useState5("3");
10113
10313
  const rootRef = useRef4(null);
10114
10314
  useEffect4(() => {
10115
10315
  if (!open) {
@@ -10202,7 +10402,7 @@ function DocumentInsertToolbar({
10202
10402
  onDigitFormChange
10203
10403
  }) {
10204
10404
  const messages = document2Messages(uiLocale);
10205
- const [digitMenuOpen, setDigitMenuOpen] = useState5(false);
10405
+ const [digitMenuOpen, setDigitMenuOpen] = useState6(false);
10206
10406
  function digitTitle(id) {
10207
10407
  if (id === "arabicIndic") {
10208
10408
  return messages.arabicIndicDigits;
@@ -10373,7 +10573,8 @@ function PreviewBlock({
10373
10573
  output,
10374
10574
  resolveImageUrl,
10375
10575
  uiLocale,
10376
- documentDirection
10576
+ documentDirection,
10577
+ digitForm
10377
10578
  }) {
10378
10579
  const messages = document2Messages(uiLocale);
10379
10580
  const floatCaptionSeparator = uiLocale === "ar" ? ": " : ". ";
@@ -10432,7 +10633,8 @@ function PreviewBlock({
10432
10633
  output,
10433
10634
  resolveImageUrl,
10434
10635
  uiLocale,
10435
- documentDirection
10636
+ documentDirection,
10637
+ digitForm
10436
10638
  },
10437
10639
  child.id
10438
10640
  ))
@@ -10462,10 +10664,10 @@ function PreviewBlock({
10462
10664
  ] }),
10463
10665
  " ",
10464
10666
  /* @__PURE__ */ jsxs9("span", { children: [
10465
- [item.authors, item.title, item.venue, item.year].filter(Boolean).join(", "),
10667
+ bibliographyEntryBody(item, item.fieldSeparator, { digitForm }),
10466
10668
  item.url ? /* @__PURE__ */ jsxs9(Fragment, { children: [
10467
10669
  " ",
10468
- /* @__PURE__ */ jsx11("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url })
10670
+ /* @__PURE__ */ jsx11("a", { href: absoluteHttpHref(item.url), target: "_blank", rel: "noreferrer", children: item.url })
10469
10671
  ] }) : null
10470
10672
  ] })
10471
10673
  ] }, item.id)) });
@@ -10477,9 +10679,11 @@ function DocumentPreview({
10477
10679
  output,
10478
10680
  documentDirection = "rtl",
10479
10681
  uiLocale = "ar",
10682
+ digitForm,
10480
10683
  resolveImageUrl
10481
10684
  }) {
10482
10685
  const messages = document2Messages(uiLocale);
10686
+ const resolvedDigitForm = digitForm ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
10483
10687
  const hasBody = blocks.some(isBodyPreviewBlock);
10484
10688
  return /* @__PURE__ */ jsxs9("div", { className: "butex-document2-widget__preview", dir: documentDirection, children: [
10485
10689
  blocks.map((block) => /* @__PURE__ */ jsx11(
@@ -10489,7 +10693,8 @@ function DocumentPreview({
10489
10693
  output,
10490
10694
  resolveImageUrl,
10491
10695
  uiLocale,
10492
- documentDirection
10696
+ documentDirection,
10697
+ digitForm: resolvedDigitForm
10493
10698
  },
10494
10699
  block.id
10495
10700
  )),
@@ -10498,7 +10703,7 @@ function DocumentPreview({
10498
10703
  }
10499
10704
 
10500
10705
  // src/react-document2/EquationDrawer.tsx
10501
- import { useEffect as useEffect6, useRef as useRef6 } from "react";
10706
+ import { useEffect as useEffect6, useRef as useRef6, useState as useState8 } from "react";
10502
10707
 
10503
10708
  // src/react/ButexEditor.tsx
10504
10709
  import {
@@ -10507,7 +10712,7 @@ import {
10507
10712
  useEffect as useEffect5,
10508
10713
  useImperativeHandle,
10509
10714
  useRef as useRef5,
10510
- useState as useState6
10715
+ useState as useState7
10511
10716
  } from "react";
10512
10717
 
10513
10718
  // src/react/widgetChromeCss.ts
@@ -11579,32 +11784,32 @@ var ButexEditor = forwardRef(
11579
11784
  const onSessionChangeRef = useRef5(onSessionChange);
11580
11785
  onSessionChangeRef.current = onSessionChange;
11581
11786
  const debugBodyHiddenRef = useRef5(false);
11582
- const [debugBodyHidden, setDebugBodyHidden] = useState6(false);
11787
+ const [debugBodyHidden, setDebugBodyHidden] = useState7(false);
11583
11788
  debugBodyHiddenRef.current = debugBodyHidden;
11584
- const [digitMenuOpen, setDigitMenuOpen] = useState6(false);
11585
- const [characterFontMenuOpen, setCharacterFontMenuOpen] = useState6(false);
11586
- const [delimiterMenuOpen, setDelimiterMenuOpen] = useState6(false);
11587
- const [matrixMenuOpen, setMatrixMenuOpen] = useState6(false);
11588
- const [spacingMenuOpen, setSpacingMenuOpen] = useState6(false);
11589
- const [functionMenuOpen, setFunctionMenuOpen] = useState6(false);
11590
- const [limitsSeriesMenuOpen, setLimitsSeriesMenuOpen] = useState6(false);
11591
- const [function2MenuOpen, setFunction2MenuOpen] = useState6(false);
11592
- const [derivativeMenuOpen, setDerivativeMenuOpen] = useState6(false);
11593
- const [groupMenuOpen, setGroupMenuOpen] = useState6(false);
11594
- const [operatorMenuOpen, setOperatorMenuOpen] = useState6(false);
11595
- const [operator2MenuOpen, setOperator2MenuOpen] = useState6(false);
11596
- const [operator3MenuOpen, setOperator3MenuOpen] = useState6(false);
11597
- const [dotMenuOpen, setDotMenuOpen] = useState6(false);
11598
- const [integralMenuOpen, setIntegralMenuOpen] = useState6(false);
11599
- const [selectedDigitForm2, setSelectedDigitForm] = useState6("western");
11600
- const [selectedCharacterFont, setSelectedCharacterFont] = useState6("default");
11601
- const [activeEditorSide, setActiveEditorSide] = useState6("arabic");
11602
- const [envPaletteMode, setEnvPaletteMode] = useState6("matrix");
11603
- const [matrixStyle, setMatrixStyle] = useState6("pmatrix");
11604
- const [matrixRows, setMatrixRows] = useState6(2);
11605
- const [matrixColumns, setMatrixColumns] = useState6(2);
11606
- const [matrixHover, setMatrixHover] = useState6(null);
11607
- const [arrayAlignmentColumn, setArrayAlignmentColumn] = useState6(1);
11789
+ const [digitMenuOpen, setDigitMenuOpen] = useState7(false);
11790
+ const [characterFontMenuOpen, setCharacterFontMenuOpen] = useState7(false);
11791
+ const [delimiterMenuOpen, setDelimiterMenuOpen] = useState7(false);
11792
+ const [matrixMenuOpen, setMatrixMenuOpen] = useState7(false);
11793
+ const [spacingMenuOpen, setSpacingMenuOpen] = useState7(false);
11794
+ const [functionMenuOpen, setFunctionMenuOpen] = useState7(false);
11795
+ const [limitsSeriesMenuOpen, setLimitsSeriesMenuOpen] = useState7(false);
11796
+ const [function2MenuOpen, setFunction2MenuOpen] = useState7(false);
11797
+ const [derivativeMenuOpen, setDerivativeMenuOpen] = useState7(false);
11798
+ const [groupMenuOpen, setGroupMenuOpen] = useState7(false);
11799
+ const [operatorMenuOpen, setOperatorMenuOpen] = useState7(false);
11800
+ const [operator2MenuOpen, setOperator2MenuOpen] = useState7(false);
11801
+ const [operator3MenuOpen, setOperator3MenuOpen] = useState7(false);
11802
+ const [dotMenuOpen, setDotMenuOpen] = useState7(false);
11803
+ const [integralMenuOpen, setIntegralMenuOpen] = useState7(false);
11804
+ const [selectedDigitForm2, setSelectedDigitForm] = useState7("western");
11805
+ const [selectedCharacterFont, setSelectedCharacterFont] = useState7("default");
11806
+ const [activeEditorSide, setActiveEditorSide] = useState7("arabic");
11807
+ const [envPaletteMode, setEnvPaletteMode] = useState7("matrix");
11808
+ const [matrixStyle, setMatrixStyle] = useState7("pmatrix");
11809
+ const [matrixRows, setMatrixRows] = useState7(2);
11810
+ const [matrixColumns, setMatrixColumns] = useState7(2);
11811
+ const [matrixHover, setMatrixHover] = useState7(null);
11812
+ const [arrayAlignmentColumn, setArrayAlignmentColumn] = useState7(1);
11608
11813
  useImperativeHandle(ref, () => ({
11609
11814
  getRuntime: () => runtimeRef.current
11610
11815
  }));
@@ -12789,6 +12994,18 @@ ButexEditor.displayName = "ButexEditor";
12789
12994
 
12790
12995
  // src/react-document2/EquationDrawer.tsx
12791
12996
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
12997
+ function keyErrorMessage2(error, messages) {
12998
+ if (error === "empty") {
12999
+ return messages.keyEmpty;
13000
+ }
13001
+ if (error === "invalid") {
13002
+ return messages.keyInvalid;
13003
+ }
13004
+ if (error === "duplicate") {
13005
+ return messages.keyDuplicate;
13006
+ }
13007
+ return null;
13008
+ }
12792
13009
  function EquationDrawer({
12793
13010
  session,
12794
13011
  reason,
@@ -12798,6 +13015,9 @@ function EquationDrawer({
12798
13015
  uiLocale = "ar",
12799
13016
  labelEnabled = false,
12800
13017
  label = "",
13018
+ labels = [],
13019
+ references = [],
13020
+ ownerId = "",
12801
13021
  onLabelEnabledChange,
12802
13022
  onLabelChange,
12803
13023
  onMathModeChange,
@@ -12807,6 +13027,16 @@ function EquationDrawer({
12807
13027
  }) {
12808
13028
  const messages = document2Messages(uiLocale);
12809
13029
  const latestSession = useRef6(session);
13030
+ const [labelOverride, setLabelOverride] = useState8(null);
13031
+ const displayedLabel = labelOverride ?? label;
13032
+ const labelError = labelEnabled && mathMode === "display" ? document2KeyError(displayedLabel, {
13033
+ references,
13034
+ labels,
13035
+ excludeOwnerId: ownerId || void 0
13036
+ }) : null;
13037
+ useEffect6(() => {
13038
+ setLabelOverride(null);
13039
+ }, [ownerId, label]);
12810
13040
  useEffect6(() => {
12811
13041
  const onKeyDown = (event) => {
12812
13042
  if (event.key === "Escape") {
@@ -12867,12 +13097,27 @@ function EquationDrawer({
12867
13097
  /* @__PURE__ */ jsx13(
12868
13098
  "input",
12869
13099
  {
12870
- value: label,
13100
+ value: displayedLabel,
12871
13101
  dir: uiLocaleDirection(uiLocale),
12872
13102
  placeholder: messages.equationLabelPlaceholder,
12873
- onChange: (event) => onLabelChange?.(event.currentTarget.value)
13103
+ "aria-invalid": labelError !== null ? true : void 0,
13104
+ onChange: (event) => {
13105
+ const value = event.currentTarget.value;
13106
+ setLabelOverride(value);
13107
+ const error = document2KeyError(value, {
13108
+ references,
13109
+ labels,
13110
+ excludeOwnerId: ownerId || void 0
13111
+ });
13112
+ if (error !== null) {
13113
+ return;
13114
+ }
13115
+ onLabelChange?.(value);
13116
+ setLabelOverride(null);
13117
+ }
12874
13118
  }
12875
- )
13119
+ ),
13120
+ labelError !== null ? /* @__PURE__ */ jsx13("p", { className: "butex-document2-widget__field-error", children: labelError === "invalid" ? messages.keyRulesHint : keyErrorMessage2(labelError, messages) }) : null
12876
13121
  ] }) : null
12877
13122
  ] }) : null,
12878
13123
  reason ? /* @__PURE__ */ jsx13("p", { className: "butex-document2-widget__error", children: uiLocale === "en" ? messages.equationUnavailable : reason }) : null,
@@ -12890,7 +13135,15 @@ function EquationDrawer({
12890
13135
  ),
12891
13136
  /* @__PURE__ */ jsxs11("div", { className: "butex-document2-widget__row", children: [
12892
13137
  canDelete && onDelete ? /* @__PURE__ */ jsx13("button", { type: "button", className: "butex-document2-widget__button--danger", onClick: onDelete, children: messages.deleteEquation }) : null,
12893
- /* @__PURE__ */ jsx13("button", { type: "button", onClick: () => onSave({ ...latestSession.current, activeSide: equationSide }), children: messages.saveEquation })
13138
+ /* @__PURE__ */ jsx13(
13139
+ "button",
13140
+ {
13141
+ type: "button",
13142
+ disabled: labelEnabled && mathMode === "display" && labelError !== null,
13143
+ onClick: () => onSave({ ...latestSession.current, activeSide: equationSide }),
13144
+ children: messages.saveEquation
13145
+ }
13146
+ )
12894
13147
  ] })
12895
13148
  ]
12896
13149
  }
@@ -12899,92 +13152,243 @@ function EquationDrawer({
12899
13152
  }
12900
13153
 
12901
13154
  // src/react-document2/LabelsPanel.tsx
13155
+ import { useState as useState9 } from "react";
12902
13156
  import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
12903
- function kindLabel(kind, uiLocale) {
12904
- const messages = document2Messages(uiLocale);
12905
- if (kind === "fig") {
12906
- return messages.labelKindFig;
13157
+ function keyErrorMessage3(error, messages) {
13158
+ if (error === "empty") {
13159
+ return messages.keyEmpty;
13160
+ }
13161
+ if (error === "invalid") {
13162
+ return messages.keyInvalid;
12907
13163
  }
12908
- if (kind === "tab") {
12909
- return messages.labelKindTab;
13164
+ if (error === "duplicate") {
13165
+ return messages.keyDuplicate;
12910
13166
  }
12911
- return messages.labelKindEq;
13167
+ return null;
12912
13168
  }
12913
13169
  function LabelsPanel({
12914
13170
  open,
12915
13171
  labels,
13172
+ references = [],
12916
13173
  uiLocale = "ar",
13174
+ digitForm = "arabicIndic",
12917
13175
  onClose,
12918
13176
  onUpdateFloat,
12919
13177
  onUpdateEquationLabel
12920
13178
  }) {
12921
13179
  const messages = document2Messages(uiLocale);
13180
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
13181
+ const [keyOverrides, setKeyOverrides] = useState9({});
12922
13182
  if (!open) {
12923
13183
  return null;
12924
13184
  }
12925
- return /* @__PURE__ */ jsx14("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs12("div", { className: "butex-document2-widget__refs-panel", role: "dialog", "aria-label": messages.labelsTitle, onClick: (event) => event.stopPropagation(), children: [
12926
- /* @__PURE__ */ jsxs12("header", { className: "butex-document2-widget__refs-header", children: [
12927
- /* @__PURE__ */ jsx14("strong", { children: messages.labelsTitle }),
12928
- /* @__PURE__ */ jsx14("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
12929
- ] }),
12930
- /* @__PURE__ */ jsx14("p", { className: "butex-document2-widget__labels-help", children: messages.labelsHelp }),
12931
- labels.length === 0 ? /* @__PURE__ */ jsx14("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noLabelsYet }) : /* @__PURE__ */ jsx14("ul", { className: "butex-document2-widget__refs-list", children: labels.map((entry) => /* @__PURE__ */ jsxs12("li", { className: "butex-document2-widget__refs-item", children: [
12932
- /* @__PURE__ */ jsx14("div", { className: "butex-document2-widget__refs-item-head", children: /* @__PURE__ */ jsxs12("strong", { children: [
12933
- "[",
12934
- kindLabel(entry.kind, uiLocale),
12935
- " ",
12936
- entry.number,
12937
- "] ",
12938
- entry.key
12939
- ] }) }),
12940
- /* @__PURE__ */ jsxs12("div", { className: "butex-document2-widget__refs-grid", children: [
12941
- /* @__PURE__ */ jsxs12("label", { className: "butex-document2-widget__refs-field", children: [
12942
- /* @__PURE__ */ jsx14("span", { children: messages.floatLabel }),
12943
- /* @__PURE__ */ jsx14(
12944
- "input",
12945
- {
12946
- value: entry.key,
12947
- dir: uiLocaleDirection(uiLocale),
12948
- onChange: (event) => {
12949
- const value = event.currentTarget.value;
12950
- if (entry.kind === "eq") {
12951
- onUpdateEquationLabel?.(entry.ownerId, { label: value, labelEnabled: true });
12952
- } else if (entry.kind === "fig" || entry.kind === "tab") {
12953
- onUpdateFloat?.(entry.ownerId, entry.kind, { label: value, labelEnabled: true });
12954
- }
12955
- }
12956
- }
12957
- )
13185
+ return /* @__PURE__ */ jsx14("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs12(
13186
+ "div",
13187
+ {
13188
+ className: "butex-document2-widget__refs-panel",
13189
+ role: "dialog",
13190
+ "aria-label": messages.labelsTitle,
13191
+ onClick: (event) => event.stopPropagation(),
13192
+ children: [
13193
+ /* @__PURE__ */ jsxs12("header", { className: "butex-document2-widget__refs-header", children: [
13194
+ /* @__PURE__ */ jsx14("strong", { children: messages.labelsTitle }),
13195
+ /* @__PURE__ */ jsx14("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
12958
13196
  ] }),
12959
- entry.kind === "fig" || entry.kind === "tab" ? /* @__PURE__ */ jsxs12("label", { className: "butex-document2-widget__refs-field", children: [
12960
- /* @__PURE__ */ jsx14("span", { children: messages.floatCaption }),
12961
- /* @__PURE__ */ jsx14(
12962
- "input",
12963
- {
12964
- value: entry.caption,
12965
- onChange: (event) => {
12966
- const value = event.currentTarget.value;
12967
- const kind = entry.kind;
12968
- if (kind === "fig" || kind === "tab") {
12969
- onUpdateFloat?.(entry.ownerId, kind, { caption: value, captionEnabled: true });
12970
- }
13197
+ /* @__PURE__ */ jsx14("p", { className: "butex-document2-widget__labels-help", children: messages.labelsHelp }),
13198
+ labels.length === 0 ? /* @__PURE__ */ jsx14("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noLabelsYet }) : /* @__PURE__ */ jsx14("ul", { className: "butex-document2-widget__refs-list", children: labels.map((entry) => {
13199
+ const title = formatFloatCaptionTitle(entry.kind, entry.number, {
13200
+ uiLocale,
13201
+ digitForm,
13202
+ documentDirection
13203
+ });
13204
+ const captionPreview = entry.kind === "eq" ? title : formatFloatCaptionPreview(title, entry.caption, uiLocale);
13205
+ const overrideKey = `${entry.kind}:${entry.ownerId}`;
13206
+ const displayedKey = keyOverrides[overrideKey] ?? entry.key;
13207
+ const entryKeyError = document2KeyError(displayedKey, {
13208
+ references,
13209
+ labels,
13210
+ excludeOwnerId: entry.ownerId
13211
+ });
13212
+ return /* @__PURE__ */ jsxs12("li", { className: "butex-document2-widget__refs-item", children: [
13213
+ /* @__PURE__ */ jsxs12("div", { className: "butex-document2-widget__refs-item-head", children: [
13214
+ /* @__PURE__ */ jsx14("strong", { children: title }),
13215
+ /* @__PURE__ */ jsx14("span", { className: "butex-document2-widget__refs-item-key", children: entry.key })
13216
+ ] }),
13217
+ /* @__PURE__ */ jsx14(
13218
+ "div",
13219
+ {
13220
+ className: "butex-document2-widget__modal-preview",
13221
+ dir: uiLocaleDirection(uiLocale),
13222
+ "aria-label": messages.captionPreview,
13223
+ children: captionPreview
12971
13224
  }
12972
- }
12973
- )
12974
- ] }) : null
12975
- ] })
12976
- ] }, `${entry.kind}:${entry.ownerId}`)) })
12977
- ] }) });
13225
+ ),
13226
+ /* @__PURE__ */ jsxs12("div", { className: "butex-document2-widget__refs-grid", children: [
13227
+ /* @__PURE__ */ jsxs12("label", { className: "butex-document2-widget__refs-field", children: [
13228
+ /* @__PURE__ */ jsx14("span", { children: messages.floatLabel }),
13229
+ /* @__PURE__ */ jsx14(
13230
+ "input",
13231
+ {
13232
+ value: displayedKey,
13233
+ dir: uiLocaleDirection(uiLocale),
13234
+ "aria-invalid": entryKeyError !== null ? true : void 0,
13235
+ onChange: (event) => {
13236
+ const value = event.currentTarget.value;
13237
+ setKeyOverrides((current) => ({ ...current, [overrideKey]: value }));
13238
+ const error = document2KeyError(value, {
13239
+ references,
13240
+ labels,
13241
+ excludeOwnerId: entry.ownerId
13242
+ });
13243
+ if (error !== null) {
13244
+ return;
13245
+ }
13246
+ if (entry.kind === "eq") {
13247
+ onUpdateEquationLabel?.(entry.ownerId, { label: value, labelEnabled: true });
13248
+ } else if (entry.kind === "fig" || entry.kind === "tab") {
13249
+ onUpdateFloat?.(entry.ownerId, entry.kind, { label: value, labelEnabled: true });
13250
+ }
13251
+ setKeyOverrides((current) => {
13252
+ const next = { ...current };
13253
+ delete next[overrideKey];
13254
+ return next;
13255
+ });
13256
+ }
13257
+ }
13258
+ ),
13259
+ entryKeyError !== null ? /* @__PURE__ */ jsx14("p", { className: "butex-document2-widget__field-error", children: entryKeyError === "invalid" ? messages.keyRulesHint : keyErrorMessage3(entryKeyError, messages) }) : null
13260
+ ] }),
13261
+ entry.kind === "fig" || entry.kind === "tab" ? /* @__PURE__ */ jsxs12("label", { className: "butex-document2-widget__refs-field", children: [
13262
+ /* @__PURE__ */ jsx14("span", { children: messages.floatCaption }),
13263
+ /* @__PURE__ */ jsx14(
13264
+ "input",
13265
+ {
13266
+ value: entry.caption,
13267
+ onChange: (event) => {
13268
+ const value = event.currentTarget.value;
13269
+ const kind = entry.kind;
13270
+ if (kind === "fig" || kind === "tab") {
13271
+ onUpdateFloat?.(entry.ownerId, kind, { caption: value, captionEnabled: true });
13272
+ }
13273
+ }
13274
+ }
13275
+ )
13276
+ ] }) : null
13277
+ ] })
13278
+ ] }, overrideKey);
13279
+ }) })
13280
+ ]
13281
+ }
13282
+ ) });
12978
13283
  }
12979
13284
 
12980
13285
  // src/react-document2/ReferencesPanel.tsx
12981
- import { useState as useState7 } from "react";
12982
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
12983
- var EMPTY_DRAFT = { key: "", authors: "", title: "", year: "", url: "", venue: "" };
13286
+ import { useMemo, useState as useState10 } from "react";
13287
+ import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
13288
+ var EMPTY_DRAFT = {
13289
+ key: "",
13290
+ authors: "",
13291
+ title: "",
13292
+ year: "",
13293
+ url: "",
13294
+ venue: "",
13295
+ field_separator: DEFAULT_REFERENCE_FIELD_SEPARATOR
13296
+ };
13297
+ var REFERENCE_FIELDS = [
13298
+ ["key", "referenceKey"],
13299
+ ["authors", "referenceAuthors"],
13300
+ ["title", "referenceTitle"],
13301
+ ["year", "referenceYear"],
13302
+ ["venue", "referenceVenue"],
13303
+ ["url", "referenceUrl"]
13304
+ ];
13305
+ function keyErrorMessage4(error, messages) {
13306
+ if (error === "empty") {
13307
+ return messages.keyEmpty;
13308
+ }
13309
+ if (error === "invalid") {
13310
+ return messages.keyInvalid;
13311
+ }
13312
+ if (error === "duplicate") {
13313
+ return messages.keyDuplicate;
13314
+ }
13315
+ return null;
13316
+ }
13317
+ function FieldSeparatorToggle({
13318
+ value,
13319
+ messages,
13320
+ onChange
13321
+ }) {
13322
+ return /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-field butex-document2-widget__refs-separator", children: [
13323
+ /* @__PURE__ */ jsx15("span", { children: messages.referenceFieldSeparator }),
13324
+ /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-separator-toggle", role: "group", "aria-label": messages.referenceFieldSeparator, children: [
13325
+ /* @__PURE__ */ jsx15(
13326
+ "button",
13327
+ {
13328
+ type: "button",
13329
+ className: value === "\u060C" ? "is-active" : void 0,
13330
+ title: messages.referenceCommaRtl,
13331
+ "aria-label": messages.referenceCommaRtl,
13332
+ "aria-pressed": value === "\u060C",
13333
+ onClick: () => onChange("\u060C"),
13334
+ children: "\u060C"
13335
+ }
13336
+ ),
13337
+ /* @__PURE__ */ jsx15(
13338
+ "button",
13339
+ {
13340
+ type: "button",
13341
+ className: value === "," ? "is-active" : void 0,
13342
+ title: messages.referenceCommaLtr,
13343
+ "aria-label": messages.referenceCommaLtr,
13344
+ "aria-pressed": value === ",",
13345
+ onClick: () => onChange(","),
13346
+ children: ","
13347
+ }
13348
+ )
13349
+ ] })
13350
+ ] });
13351
+ }
13352
+ function ReferencePreview({
13353
+ authors,
13354
+ title,
13355
+ venue,
13356
+ year,
13357
+ url,
13358
+ fieldSeparator,
13359
+ numberLabel,
13360
+ messages,
13361
+ uiLocale,
13362
+ digitForm
13363
+ }) {
13364
+ const body = bibliographyEntryBody({ authors, title, venue, year, fieldSeparator }, fieldSeparator, { digitForm });
13365
+ return /* @__PURE__ */ jsxs13(
13366
+ "div",
13367
+ {
13368
+ className: "butex-document2-widget__modal-preview",
13369
+ dir: uiLocaleDirection(uiLocale),
13370
+ "aria-label": messages.referencePreview,
13371
+ children: [
13372
+ numberLabel ? /* @__PURE__ */ jsxs13("span", { className: "butex-document2-widget__modal-preview-number", children: [
13373
+ "[",
13374
+ numberLabel,
13375
+ "] "
13376
+ ] }) : null,
13377
+ body.length > 0 ? body : /* @__PURE__ */ jsx15("span", { className: "butex-document2-widget__cite-picker-empty", children: "\u2026" }),
13378
+ url.trim().length > 0 ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
13379
+ " ",
13380
+ /* @__PURE__ */ jsx15("span", { className: "butex-document2-widget__modal-preview-url", children: url.trim() })
13381
+ ] }) : null
13382
+ ]
13383
+ }
13384
+ );
13385
+ }
12984
13386
  function ReferencesPanel({
12985
13387
  open,
12986
13388
  references,
13389
+ labels = [],
12987
13390
  uiLocale = "ar",
13391
+ digitForm = "arabicIndic",
12988
13392
  onClose,
12989
13393
  onAdd,
12990
13394
  onUpdate,
@@ -12992,101 +13396,190 @@ function ReferencesPanel({
12992
13396
  onMove
12993
13397
  }) {
12994
13398
  const messages = document2Messages(uiLocale);
12995
- const [draft, setDraft] = useState7(EMPTY_DRAFT);
13399
+ const [draft, setDraft] = useState10(EMPTY_DRAFT);
13400
+ const [draftKeyTouched, setDraftKeyTouched] = useState10(false);
13401
+ const [keyOverrides, setKeyOverrides] = useState10({});
13402
+ const draftSeparator = draft.field_separator === "," ? "," : DEFAULT_REFERENCE_FIELD_SEPARATOR;
13403
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
13404
+ const draftKeyError = useMemo(
13405
+ () => document2KeyError(draft.key ?? "", {
13406
+ references,
13407
+ labels
13408
+ }),
13409
+ [draft.key, references, labels]
13410
+ );
12996
13411
  if (!open) {
12997
13412
  return null;
12998
13413
  }
12999
- return /* @__PURE__ */ jsx15("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-panel", role: "dialog", "aria-label": messages.referencesTitle, onClick: (event) => event.stopPropagation(), children: [
13000
- /* @__PURE__ */ jsxs13("header", { className: "butex-document2-widget__refs-header", children: [
13001
- /* @__PURE__ */ jsx15("strong", { children: messages.referencesTitle }),
13002
- /* @__PURE__ */ jsx15("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
13003
- ] }),
13004
- /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-add", children: [
13005
- /* @__PURE__ */ jsx15("h3", { children: messages.addReference }),
13006
- /* @__PURE__ */ jsx15("div", { className: "butex-document2-widget__refs-grid", children: [
13007
- ["key", messages.referenceKey],
13008
- ["authors", messages.referenceAuthors],
13009
- ["title", messages.referenceTitle],
13010
- ["year", messages.referenceYear],
13011
- ["venue", messages.referenceVenue],
13012
- ["url", messages.referenceUrl]
13013
- ].map(([field, label]) => /* @__PURE__ */ jsxs13("label", { className: "butex-document2-widget__refs-field", children: [
13014
- /* @__PURE__ */ jsx15("span", { children: label }),
13015
- /* @__PURE__ */ jsx15(
13016
- "input",
13017
- {
13018
- value: draft[field] ?? "",
13019
- onChange: (event) => {
13020
- const value = event.currentTarget.value;
13021
- setDraft((current) => ({ ...current, [field]: value }));
13022
- }
13023
- }
13024
- )
13025
- ] }, field)) }),
13026
- /* @__PURE__ */ jsx15(
13027
- "button",
13028
- {
13029
- type: "button",
13030
- className: "butex-document2-widget__primary-btn",
13031
- disabled: !draft.key?.trim(),
13032
- onClick: () => {
13033
- onAdd(draft);
13034
- setDraft(EMPTY_DRAFT);
13035
- },
13036
- children: messages.addReference
13037
- }
13038
- )
13039
- ] }),
13040
- /* @__PURE__ */ jsx15("ul", { className: "butex-document2-widget__refs-list", children: references.map((reference, index) => /* @__PURE__ */ jsxs13("li", { className: "butex-document2-widget__refs-item", children: [
13041
- /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-item-head", children: [
13042
- /* @__PURE__ */ jsxs13("strong", { children: [
13043
- "[",
13044
- index + 1,
13045
- "] ",
13046
- reference.key
13414
+ return /* @__PURE__ */ jsx15("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs13(
13415
+ "div",
13416
+ {
13417
+ className: "butex-document2-widget__refs-panel",
13418
+ role: "dialog",
13419
+ "aria-label": messages.referencesTitle,
13420
+ onClick: (event) => event.stopPropagation(),
13421
+ children: [
13422
+ /* @__PURE__ */ jsxs13("header", { className: "butex-document2-widget__refs-header", children: [
13423
+ /* @__PURE__ */ jsx15("strong", { children: messages.referencesTitle }),
13424
+ /* @__PURE__ */ jsx15("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
13047
13425
  ] }),
13048
- /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-item-actions", children: [
13049
- /* @__PURE__ */ jsx15("button", { type: "button", title: messages.moveUp, "aria-label": messages.moveUp, disabled: index === 0, onClick: () => onMove(reference.id, -1), children: "\u2191" }),
13426
+ /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-add", children: [
13427
+ /* @__PURE__ */ jsx15("h3", { children: messages.addReference }),
13428
+ /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-grid", children: [
13429
+ REFERENCE_FIELDS.map(([field, messageKey]) => /* @__PURE__ */ jsxs13("label", { className: "butex-document2-widget__refs-field", children: [
13430
+ /* @__PURE__ */ jsx15("span", { children: messages[messageKey] }),
13431
+ /* @__PURE__ */ jsx15(
13432
+ "input",
13433
+ {
13434
+ value: draft[field] ?? "",
13435
+ "aria-invalid": field === "key" && draftKeyTouched && draftKeyError !== null ? true : void 0,
13436
+ onChange: (event) => {
13437
+ const value = event.currentTarget.value;
13438
+ if (field === "key") {
13439
+ setDraftKeyTouched(true);
13440
+ }
13441
+ setDraft((current) => ({ ...current, [field]: value }));
13442
+ }
13443
+ }
13444
+ ),
13445
+ field === "key" && draftKeyTouched && draftKeyError !== null ? /* @__PURE__ */ jsx15("p", { className: "butex-document2-widget__field-error", children: draftKeyError === "invalid" ? messages.keyRulesHint : keyErrorMessage4(draftKeyError, messages) }) : null
13446
+ ] }, field)),
13447
+ /* @__PURE__ */ jsx15(
13448
+ FieldSeparatorToggle,
13449
+ {
13450
+ value: draftSeparator,
13451
+ messages,
13452
+ onChange: (next) => setDraft((current) => ({ ...current, field_separator: next }))
13453
+ }
13454
+ )
13455
+ ] }),
13050
13456
  /* @__PURE__ */ jsx15(
13051
- "button",
13457
+ ReferencePreview,
13052
13458
  {
13053
- type: "button",
13054
- title: messages.moveDown,
13055
- "aria-label": messages.moveDown,
13056
- disabled: index === references.length - 1,
13057
- onClick: () => onMove(reference.id, 1),
13058
- children: "\u2193"
13459
+ authors: draft.authors ?? "",
13460
+ title: draft.title ?? "",
13461
+ venue: draft.venue ?? "",
13462
+ year: draft.year ?? "",
13463
+ url: draft.url ?? "",
13464
+ fieldSeparator: draftSeparator,
13465
+ messages,
13466
+ uiLocale,
13467
+ digitForm
13059
13468
  }
13060
13469
  ),
13061
- /* @__PURE__ */ jsx15("button", { type: "button", title: messages.deleteReference, "aria-label": messages.deleteReference, onClick: () => onRemove(reference.id), children: "\xD7" })
13062
- ] })
13063
- ] }),
13064
- /* @__PURE__ */ jsx15("div", { className: "butex-document2-widget__refs-grid", children: [
13065
- ["key", messages.referenceKey],
13066
- ["authors", messages.referenceAuthors],
13067
- ["title", messages.referenceTitle],
13068
- ["year", messages.referenceYear],
13069
- ["venue", messages.referenceVenue],
13070
- ["url", messages.referenceUrl]
13071
- ].map(([field, label]) => /* @__PURE__ */ jsxs13("label", { className: "butex-document2-widget__refs-field", children: [
13072
- /* @__PURE__ */ jsx15("span", { children: label }),
13073
- /* @__PURE__ */ jsx15(
13074
- "input",
13075
- {
13076
- value: reference[field],
13077
- onChange: (event) => {
13078
- const value = event.currentTarget.value;
13079
- onUpdate(reference.id, { [field]: value });
13470
+ /* @__PURE__ */ jsx15(
13471
+ "button",
13472
+ {
13473
+ type: "button",
13474
+ className: "butex-document2-widget__primary-btn",
13475
+ disabled: draftKeyError !== null,
13476
+ onClick: () => {
13477
+ onAdd({ ...draft, field_separator: draftSeparator });
13478
+ setDraft(EMPTY_DRAFT);
13479
+ setDraftKeyTouched(false);
13480
+ },
13481
+ children: messages.addReference
13080
13482
  }
13081
- }
13082
- )
13083
- ] }, field)) })
13084
- ] }, reference.id)) })
13085
- ] }) });
13483
+ )
13484
+ ] }),
13485
+ /* @__PURE__ */ jsx15("ul", { className: "butex-document2-widget__refs-list", children: references.map((reference, index) => {
13486
+ const displayedKey = keyOverrides[reference.id] ?? reference.key;
13487
+ const entryKeyError = document2KeyError(displayedKey, {
13488
+ references,
13489
+ labels,
13490
+ excludeReferenceId: reference.id
13491
+ });
13492
+ const numberLabel = formatBibliographyNumber(index + 1, { documentDirection, digitForm });
13493
+ return /* @__PURE__ */ jsxs13("li", { className: "butex-document2-widget__refs-item", children: [
13494
+ /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-item-head", children: [
13495
+ /* @__PURE__ */ jsxs13("strong", { children: [
13496
+ "[",
13497
+ numberLabel,
13498
+ "] ",
13499
+ reference.key
13500
+ ] }),
13501
+ /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-item-actions", children: [
13502
+ /* @__PURE__ */ jsx15("button", { type: "button", title: messages.moveUp, "aria-label": messages.moveUp, disabled: index === 0, onClick: () => onMove(reference.id, -1), children: "\u2191" }),
13503
+ /* @__PURE__ */ jsx15(
13504
+ "button",
13505
+ {
13506
+ type: "button",
13507
+ title: messages.moveDown,
13508
+ "aria-label": messages.moveDown,
13509
+ disabled: index === references.length - 1,
13510
+ onClick: () => onMove(reference.id, 1),
13511
+ children: "\u2193"
13512
+ }
13513
+ ),
13514
+ /* @__PURE__ */ jsx15("button", { type: "button", title: messages.deleteReference, "aria-label": messages.deleteReference, onClick: () => onRemove(reference.id), children: "\xD7" })
13515
+ ] })
13516
+ ] }),
13517
+ /* @__PURE__ */ jsx15(
13518
+ ReferencePreview,
13519
+ {
13520
+ authors: reference.authors,
13521
+ title: reference.title,
13522
+ venue: reference.venue,
13523
+ year: reference.year,
13524
+ url: reference.url,
13525
+ fieldSeparator: reference.fieldSeparator,
13526
+ numberLabel,
13527
+ messages,
13528
+ uiLocale,
13529
+ digitForm
13530
+ }
13531
+ ),
13532
+ /* @__PURE__ */ jsxs13("div", { className: "butex-document2-widget__refs-grid", children: [
13533
+ REFERENCE_FIELDS.map(([field, messageKey]) => /* @__PURE__ */ jsxs13("label", { className: "butex-document2-widget__refs-field", children: [
13534
+ /* @__PURE__ */ jsx15("span", { children: messages[messageKey] }),
13535
+ /* @__PURE__ */ jsx15(
13536
+ "input",
13537
+ {
13538
+ value: field === "key" ? displayedKey : reference[field],
13539
+ "aria-invalid": field === "key" && entryKeyError !== null ? true : void 0,
13540
+ onChange: (event) => {
13541
+ const value = event.currentTarget.value;
13542
+ if (field !== "key") {
13543
+ onUpdate(reference.id, { [field]: value });
13544
+ return;
13545
+ }
13546
+ setKeyOverrides((current) => ({ ...current, [reference.id]: value }));
13547
+ const error = document2KeyError(value, {
13548
+ references,
13549
+ labels,
13550
+ excludeReferenceId: reference.id
13551
+ });
13552
+ if (error === null) {
13553
+ onUpdate(reference.id, { key: value });
13554
+ setKeyOverrides((current) => {
13555
+ const next = { ...current };
13556
+ delete next[reference.id];
13557
+ return next;
13558
+ });
13559
+ }
13560
+ }
13561
+ }
13562
+ ),
13563
+ field === "key" && entryKeyError !== null ? /* @__PURE__ */ jsx15("p", { className: "butex-document2-widget__field-error", children: entryKeyError === "invalid" ? messages.keyRulesHint : keyErrorMessage4(entryKeyError, messages) }) : null
13564
+ ] }, field)),
13565
+ /* @__PURE__ */ jsx15(
13566
+ FieldSeparatorToggle,
13567
+ {
13568
+ value: reference.fieldSeparator,
13569
+ messages,
13570
+ onChange: (next) => onUpdate(reference.id, { field_separator: next })
13571
+ }
13572
+ )
13573
+ ] })
13574
+ ] }, reference.id);
13575
+ }) })
13576
+ ]
13577
+ }
13578
+ ) });
13086
13579
  }
13087
13580
 
13088
13581
  // src/react-document2/RefPickerPopover.tsx
13089
- import { useEffect as useEffect7, useState as useState8 } from "react";
13582
+ import { useEffect as useEffect7, useState as useState11 } from "react";
13090
13583
  import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
13091
13584
  function RefPickerPopover({
13092
13585
  open,
@@ -13094,13 +13587,15 @@ function RefPickerPopover({
13094
13587
  initialKeys = [],
13095
13588
  initialRefCommand = "ref",
13096
13589
  uiLocale = "ar",
13590
+ digitForm = "arabicIndic",
13097
13591
  onClose,
13098
13592
  onConfirm,
13099
13593
  onManageLabels
13100
13594
  }) {
13101
13595
  const messages = document2Messages(uiLocale);
13102
- const [selected, setSelected] = useState8(initialKeys);
13103
- const [refCommand, setRefCommand] = useState8(initialRefCommand);
13596
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
13597
+ const [selected, setSelected] = useState11(initialKeys);
13598
+ const [refCommand, setRefCommand] = useState11(initialRefCommand);
13104
13599
  useEffect7(() => {
13105
13600
  if (open) {
13106
13601
  setSelected(initialKeys);
@@ -13128,16 +13623,18 @@ function RefPickerPopover({
13128
13623
  ] }),
13129
13624
  labels.length === 0 ? /* @__PURE__ */ jsx16("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noLabelsYet }) : /* @__PURE__ */ jsx16("ul", { className: "butex-document2-widget__cite-picker-list", children: labels.map((entry) => {
13130
13625
  const checked = selected.includes(entry.key);
13626
+ const title = formatFloatCaptionTitle(entry.kind, entry.number, {
13627
+ uiLocale,
13628
+ digitForm,
13629
+ documentDirection
13630
+ });
13131
13631
  return /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsxs14("label", { className: "butex-document2-widget__cite-picker-item", children: [
13132
13632
  /* @__PURE__ */ jsx16("input", { type: "radio", name: "butex-ref-key", checked, onChange: () => selectKey(entry.key, entry.kind) }),
13133
13633
  /* @__PURE__ */ jsxs14("span", { children: [
13134
13634
  /* @__PURE__ */ jsxs14("strong", { children: [
13135
- "[",
13136
- entry.kind,
13635
+ title,
13137
13636
  " ",
13138
- entry.number,
13139
- "] ",
13140
- entry.key
13637
+ /* @__PURE__ */ jsx16("span", { className: "butex-document2-widget__refs-item-key", children: entry.key })
13141
13638
  ] }),
13142
13639
  entry.caption ? /* @__PURE__ */ jsx16("span", { className: "butex-document2-widget__cite-picker-meta", children: entry.caption }) : null
13143
13640
  ] })
@@ -14329,6 +14826,24 @@ var DOCUMENT2_WIDGET_CSS = `
14329
14826
  width: 100%;
14330
14827
  }
14331
14828
 
14829
+ .butex-document2-widget__field-error {
14830
+ color: #b42318;
14831
+ font-size: 0.85em;
14832
+ line-height: 1.35;
14833
+ margin: 0;
14834
+ }
14835
+
14836
+ .butex-document2-widget__field-hint {
14837
+ color: var(--butex-document2-muted);
14838
+ font-size: 0.82em;
14839
+ line-height: 1.35;
14840
+ margin: 0;
14841
+ }
14842
+
14843
+ .butex-document2-widget__refs-field input[aria-invalid='true'] {
14844
+ border-color: color-mix(in srgb, #b42318 55%, var(--butex-document2-border));
14845
+ }
14846
+
14332
14847
  .butex-document2-widget__refs-item {
14333
14848
  border: 1px solid var(--butex-document2-border);
14334
14849
  border-radius: 10px;
@@ -14337,6 +14852,58 @@ var DOCUMENT2_WIDGET_CSS = `
14337
14852
  padding: 0.75rem;
14338
14853
  }
14339
14854
 
14855
+ .butex-document2-widget__refs-item-key {
14856
+ color: var(--butex-document2-muted);
14857
+ font-size: 0.9em;
14858
+ font-weight: 500;
14859
+ }
14860
+
14861
+ .butex-document2-widget__modal-preview {
14862
+ background: color-mix(in srgb, var(--butex-document2-panel) 88%, var(--butex-document2-accent-bg));
14863
+ border: 1px dashed color-mix(in srgb, var(--butex-document2-accent) 30%, var(--butex-document2-border));
14864
+ border-radius: 8px;
14865
+ color: inherit;
14866
+ font-size: 0.95em;
14867
+ line-height: 1.55;
14868
+ padding: 0.55rem 0.7rem;
14869
+ text-align: center;
14870
+ }
14871
+
14872
+ .butex-document2-widget__modal-preview-number {
14873
+ color: var(--butex-document2-muted);
14874
+ font-weight: 600;
14875
+ }
14876
+
14877
+ .butex-document2-widget__modal-preview-url {
14878
+ color: var(--butex-document2-accent);
14879
+ word-break: break-all;
14880
+ }
14881
+
14882
+ .butex-document2-widget__refs-separator-toggle {
14883
+ display: inline-flex;
14884
+ gap: 0.35rem;
14885
+ }
14886
+
14887
+ .butex-document2-widget__refs-separator-toggle button {
14888
+ background: var(--butex-document2-input-bg, var(--butex-document2-panel));
14889
+ border: 1px solid var(--butex-document2-border);
14890
+ border-radius: 6px;
14891
+ color: inherit;
14892
+ cursor: pointer;
14893
+ font: inherit;
14894
+ font-size: 1.15em;
14895
+ line-height: 1;
14896
+ min-width: 2.25rem;
14897
+ padding: 0.35rem 0.55rem;
14898
+ }
14899
+
14900
+ .butex-document2-widget__refs-separator-toggle button.is-active {
14901
+ background: var(--butex-document2-accent-bg);
14902
+ border-color: color-mix(in srgb, var(--butex-document2-accent) 45%, var(--butex-document2-border));
14903
+ color: var(--butex-document2-accent);
14904
+ font-weight: 700;
14905
+ }
14906
+
14340
14907
  .butex-document2-widget__refs-item-actions {
14341
14908
  display: inline-flex;
14342
14909
  gap: 0.25rem;
@@ -14619,7 +15186,7 @@ function injectBuTeXDocument2Styles(doc) {
14619
15186
  }
14620
15187
 
14621
15188
  // src/react-document2/ButexDocumentEditor2.tsx
14622
- import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
15189
+ import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
14623
15190
  function mathDelimiters(mode) {
14624
15191
  return mode === "inline" ? { opening: "$", closing: "$" } : { opening: "\\[", closing: "\\]" };
14625
15192
  }
@@ -14828,24 +15395,24 @@ function ButexDocumentEditor2({
14828
15395
  onLatexChange
14829
15396
  }) {
14830
15397
  const messages = document2Messages(uiLocale);
14831
- const initialState = useMemo(
15398
+ const initialState = useMemo2(
14832
15399
  () => resolveInitialDocument2(initialDocument, uiLocale, documentMeta),
14833
15400
  [initialDocument, documentMeta, uiLocale]
14834
15401
  );
14835
- const [documentNode, setDocumentNode] = useState9(initialState.document);
14836
- const [error, setError] = useState9(initialState.error);
14837
- const [editorOpen, setEditorOpen] = useState9(true);
14838
- const [previewOpen, setPreviewOpen] = useState9(true);
14839
- const [selectedMath, setSelectedMath] = useState9(null);
14840
- const [citePicker, setCitePicker] = useState9(null);
14841
- const [referencesOpen, setReferencesOpen] = useState9(false);
14842
- const [labelsOpen, setLabelsOpen] = useState9(false);
14843
- const [refPicker, setRefPicker] = useState9(null);
14844
- const [digitFormState, setDigitFormState] = useState9(null);
14845
- const [editorFocus, setEditorFocus] = useState9(createEmptyDocument2EditorFocus());
14846
- const [collapsedBlockIds, setCollapsedBlockIds] = useState9(() => /* @__PURE__ */ new Set());
14847
- const [blockSelectionState, setBlockSelectionState] = useState9(emptyBlockSelection);
14848
- const [historyTick, setHistoryTick] = useState9(0);
15402
+ const [documentNode, setDocumentNode] = useState12(initialState.document);
15403
+ const [error, setError] = useState12(initialState.error);
15404
+ const [editorOpen, setEditorOpen] = useState12(true);
15405
+ const [previewOpen, setPreviewOpen] = useState12(true);
15406
+ const [selectedMath, setSelectedMath] = useState12(null);
15407
+ const [citePicker, setCitePicker] = useState12(null);
15408
+ const [referencesOpen, setReferencesOpen] = useState12(false);
15409
+ const [labelsOpen, setLabelsOpen] = useState12(false);
15410
+ const [refPicker, setRefPicker] = useState12(null);
15411
+ const [digitFormState, setDigitFormState] = useState12(null);
15412
+ const [editorFocus, setEditorFocus] = useState12(createEmptyDocument2EditorFocus());
15413
+ const [collapsedBlockIds, setCollapsedBlockIds] = useState12(() => /* @__PURE__ */ new Set());
15414
+ const [blockSelectionState, setBlockSelectionState] = useState12(emptyBlockSelection);
15415
+ const [historyTick, setHistoryTick] = useState12(0);
14849
15416
  const digitForm = digitFormProp ?? digitFormState ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
14850
15417
  const historyRef = useRef7(createDocument2History());
14851
15418
  const documentRef = useRef7(documentNode);
@@ -14856,8 +15423,8 @@ function ButexDocumentEditor2({
14856
15423
  const pendingFocusRef = useRef7(null);
14857
15424
  documentRef.current = documentNode;
14858
15425
  const latex = document2Latex(documentNode);
14859
- const documentLabels = useMemo(() => collectDocument2Labels(documentNode), [documentNode]);
14860
- const preview = useMemo(
15426
+ const documentLabels = useMemo2(() => collectDocument2Labels(documentNode), [documentNode]);
15427
+ const preview = useMemo2(
14861
15428
  () => document2Preview(documentNode, mathOutput, equationSide, {
14862
15429
  documentDirection,
14863
15430
  digitForm,
@@ -14865,7 +15432,7 @@ function ButexDocumentEditor2({
14865
15432
  }),
14866
15433
  [documentNode, documentDirection, digitForm, equationSide, mathOutput, uiLocale]
14867
15434
  );
14868
- const debugEnabled = useMemo(() => {
15435
+ const debugEnabled = useMemo2(() => {
14869
15436
  if (debug) {
14870
15437
  return true;
14871
15438
  }
@@ -14874,8 +15441,8 @@ function ButexDocumentEditor2({
14874
15441
  }
14875
15442
  return new URLSearchParams(window.location.search).get("debug") === "1";
14876
15443
  }, [debug]);
14877
- const canUndo = useMemo(() => document2HistoryCanUndo(historyRef.current), [historyTick, documentNode]);
14878
- const canRedo = useMemo(() => document2HistoryCanRedo(historyRef.current), [historyTick, documentNode]);
15444
+ const canUndo = useMemo2(() => document2HistoryCanUndo(historyRef.current), [historyTick, documentNode]);
15445
+ const canRedo = useMemo2(() => document2HistoryCanRedo(historyRef.current), [historyTick, documentNode]);
14879
15446
  const blockSelection = normalizeBlockSelection(blockSelectionState.selection, documentNode.blocks.length);
14880
15447
  const selectionCount = blockSelection ? blockSelection.to - blockSelection.from + 1 : 0;
14881
15448
  const canMoveSelectionUp = Boolean(blockSelection && blockSelection.from > 0);
@@ -15536,6 +16103,7 @@ function ButexDocumentEditor2({
15536
16103
  output: mathOutput,
15537
16104
  documentDirection,
15538
16105
  uiLocale,
16106
+ digitForm,
15539
16107
  resolveImageUrl
15540
16108
  }
15541
16109
  )
@@ -15545,7 +16113,7 @@ function ButexDocumentEditor2({
15545
16113
  }
15546
16114
  ),
15547
16115
  debugEnabled ? /* @__PURE__ */ jsxs15("div", { className: "butex-document2-widget__dev", children: [
15548
- debugEnabled && documentNode.diagnostics.length > 0 ? /* @__PURE__ */ jsxs15(Fragment3, { children: [
16116
+ debugEnabled && documentNode.diagnostics.length > 0 ? /* @__PURE__ */ jsxs15(Fragment4, { children: [
15549
16117
  /* @__PURE__ */ jsx17("strong", { children: messages.importWarnings }),
15550
16118
  documentNode.diagnostics.map((diagnostic) => /* @__PURE__ */ jsx17("p", { className: "butex-document2-widget__dev-diagnostic", children: formatDocument2Diagnostic(diagnostic, messages) }, `${diagnostic.path}-${diagnostic.message}`))
15551
16119
  ] }) : null,
@@ -15565,6 +16133,9 @@ function ButexDocumentEditor2({
15565
16133
  uiLocale,
15566
16134
  labelEnabled: selectedMath.labelEnabled,
15567
16135
  label: selectedMath.label,
16136
+ labels: documentLabels,
16137
+ references: documentNode.references,
16138
+ ownerId: selectedMath.tokenId ?? void 0,
15568
16139
  onLabelEnabledChange: (enabled) => setSelectedMath((current) => current ? { ...current, labelEnabled: enabled } : current),
15569
16140
  onLabelChange: (nextLabel) => setSelectedMath((current) => current ? { ...current, label: nextLabel } : current),
15570
16141
  onMathModeChange: (mode) => setSelectedMath((current) => current ? { ...current, mathMode: mode } : current),
@@ -15580,6 +16151,7 @@ function ButexDocumentEditor2({
15580
16151
  references: documentNode.references,
15581
16152
  initialKeys: citePicker?.keys ?? [],
15582
16153
  uiLocale,
16154
+ digitForm,
15583
16155
  onClose: () => setCitePicker(null),
15584
16156
  onConfirm: confirmCiteKeys,
15585
16157
  onManageReferences: () => {
@@ -15596,6 +16168,7 @@ function ButexDocumentEditor2({
15596
16168
  initialKeys: refPicker?.keys ?? [],
15597
16169
  initialRefCommand: refPicker?.refCommand ?? "ref",
15598
16170
  uiLocale,
16171
+ digitForm,
15599
16172
  onClose: () => setRefPicker(null),
15600
16173
  onConfirm: confirmRefKeys,
15601
16174
  onManageLabels: () => {
@@ -15609,7 +16182,9 @@ function ButexDocumentEditor2({
15609
16182
  {
15610
16183
  open: referencesOpen,
15611
16184
  references: documentNode.references,
16185
+ labels: documentLabels,
15612
16186
  uiLocale,
16187
+ digitForm,
15613
16188
  onClose: () => setReferencesOpen(false),
15614
16189
  onAdd: (partial) => applyDocument(addDocument2Reference(documentRef.current, partial), "immediate"),
15615
16190
  onUpdate: (referenceId, patch) => applyDocument(updateDocument2Reference(documentRef.current, referenceId, patch), "immediate"),
@@ -15622,7 +16197,9 @@ function ButexDocumentEditor2({
15622
16197
  {
15623
16198
  open: labelsOpen,
15624
16199
  labels: documentLabels,
16200
+ references: documentNode.references,
15625
16201
  uiLocale,
16202
+ digitForm,
15626
16203
  onClose: () => setLabelsOpen(false),
15627
16204
  onUpdateFloat: (ownerId, kind, patch) => applyDocument(
15628
16205
  kind === "fig" ? updateDocument2ImageMeta(documentRef.current, ownerId, patch) : updateDocument2TableMeta(documentRef.current, ownerId, patch),