@drghaliasri/butex 5.3.1 → 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.
@@ -303,6 +303,10 @@ function cloneDocument2Meta(meta) {
303
303
  }
304
304
 
305
305
  // src/document2/citations.ts
306
+ var DEFAULT_REFERENCE_FIELD_SEPARATOR = "\u060C";
307
+ function normalizeReferenceFieldSeparator(value) {
308
+ return value === "," ? "," : DEFAULT_REFERENCE_FIELD_SEPARATOR;
309
+ }
306
310
  function referenceNumberMap(references) {
307
311
  const map = /* @__PURE__ */ new Map();
308
312
  references.forEach((reference, index) => {
@@ -348,7 +352,8 @@ function referenceFromJson(json) {
348
352
  title: typeof json.title === "string" ? json.title : "",
349
353
  year: typeof json.year === "string" ? json.year : "",
350
354
  url: typeof json.url === "string" ? json.url : "",
351
- venue: typeof json.venue === "string" ? json.venue : ""
355
+ venue: typeof json.venue === "string" ? json.venue : "",
356
+ fieldSeparator: normalizeReferenceFieldSeparator(json.field_separator)
352
357
  };
353
358
  }
354
359
  function createEmptyReference2(partial = {}) {
@@ -358,15 +363,33 @@ function createEmptyReference2(partial = {}) {
358
363
  title: partial.title,
359
364
  year: partial.year,
360
365
  url: partial.url,
361
- venue: partial.venue
366
+ venue: partial.venue,
367
+ field_separator: partial.field_separator
362
368
  });
363
369
  }
370
+ function bibliographyEntryBody(reference, separator = reference.fieldSeparator, options = {}) {
371
+ const year = options.digitForm !== void 0 ? formatDigits(reference.year, options.digitForm) : reference.year;
372
+ const parts = [reference.authors, reference.title, reference.venue, year].filter((part) => part.trim().length > 0);
373
+ return parts.join(`${separator} `);
374
+ }
364
375
  function bibliographyEntryLatex(reference) {
365
- const parts = [reference.authors, reference.title, reference.venue, reference.year].filter((part) => part.trim().length > 0);
366
- const body = parts.join(", ");
376
+ const body = bibliographyEntryBody(reference);
367
377
  const url = reference.url.trim().length > 0 ? ` \\url{${reference.url}}` : "";
368
378
  return `\\bibitem{${reference.key}} ${body}${url}`.trim();
369
379
  }
380
+ function absoluteHttpHref(url) {
381
+ const trimmed = url.trim();
382
+ if (trimmed.length === 0) {
383
+ return "";
384
+ }
385
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
386
+ return trimmed;
387
+ }
388
+ if (trimmed.startsWith("//")) {
389
+ return `https:${trimmed}`;
390
+ }
391
+ return `https://${trimmed}`;
392
+ }
370
393
 
371
394
  // src/ast/commands/index.ts
372
395
  function renderCommandCore(context) {
@@ -851,6 +874,23 @@ function labelNumberMap(document2) {
851
874
  }
852
875
  return map;
853
876
  }
877
+ function formatFloatCaptionTitle(kind, number, options = {}) {
878
+ const locale = options.uiLocale ?? "ar";
879
+ 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";
880
+ const digits = formatBibliographyNumber(number, {
881
+ documentDirection: options.documentDirection ?? (locale === "ar" ? "rtl" : "ltr"),
882
+ digitForm: options.digitForm ?? (locale === "ar" ? "arabicIndic" : "western")
883
+ });
884
+ return `${kindWord} ${digits}`;
885
+ }
886
+ function formatFloatCaptionPreview(title, caption, uiLocale = "ar") {
887
+ const trimmed = caption?.trim() ?? "";
888
+ if (trimmed.length === 0) {
889
+ return title;
890
+ }
891
+ const separator = uiLocale === "ar" ? ": " : ". ";
892
+ return `${title}${separator}${trimmed}`;
893
+ }
854
894
  function formatRefLabel(keys, document2, refCommand, options = {}) {
855
895
  const documentDirection = options.documentDirection ?? "rtl";
856
896
  const digitForm = options.digitForm ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
@@ -1121,7 +1161,8 @@ function parseReferences(json) {
1121
1161
  title: typeof entry.title === "string" ? entry.title : void 0,
1122
1162
  year: typeof entry.year === "string" ? entry.year : void 0,
1123
1163
  url: typeof entry.url === "string" ? entry.url : void 0,
1124
- venue: typeof entry.venue === "string" ? entry.venue : void 0
1164
+ venue: typeof entry.venue === "string" ? entry.venue : void 0,
1165
+ field_separator: entry.field_separator === "," || entry.field_separator === "\u060C" ? entry.field_separator : void 0
1125
1166
  })
1126
1167
  );
1127
1168
  }
@@ -7553,6 +7594,9 @@ function updateDocument2Reference(document2, referenceId, patch) {
7553
7594
  if (typeof patch.venue === "string") {
7554
7595
  reference.venue = patch.venue;
7555
7596
  }
7597
+ if (patch.field_separator === "," || patch.field_separator === "\u060C") {
7598
+ reference.fieldSeparator = patch.field_separator;
7599
+ }
7556
7600
  return next;
7557
7601
  }
7558
7602
  function removeDocument2Reference(document2, referenceId) {
@@ -7586,6 +7630,48 @@ function updateDocument2Meta(document2, patch) {
7586
7630
  return next;
7587
7631
  }
7588
7632
 
7633
+ // src/document2/keys.ts
7634
+ var DOCUMENT2_KEY_PATTERN = /^[\p{L}\p{M}0-9:._-]+$/u;
7635
+ function normalizeDocument2Key(key) {
7636
+ return key.normalize("NFC").trim();
7637
+ }
7638
+ function isDuplicateDocument2Key(key, namespace) {
7639
+ const normalized = normalizeDocument2Key(key);
7640
+ if (normalized.length === 0) {
7641
+ return false;
7642
+ }
7643
+ for (const reference of namespace.references ?? []) {
7644
+ if (namespace.excludeReferenceId && reference.id === namespace.excludeReferenceId) {
7645
+ continue;
7646
+ }
7647
+ if (normalizeDocument2Key(reference.key) === normalized) {
7648
+ return true;
7649
+ }
7650
+ }
7651
+ for (const label of namespace.labels ?? []) {
7652
+ if (namespace.excludeOwnerId && label.ownerId === namespace.excludeOwnerId) {
7653
+ continue;
7654
+ }
7655
+ if (normalizeDocument2Key(label.key) === normalized) {
7656
+ return true;
7657
+ }
7658
+ }
7659
+ return false;
7660
+ }
7661
+ function document2KeyError(key, namespace = {}) {
7662
+ const normalized = normalizeDocument2Key(key);
7663
+ if (normalized.length === 0) {
7664
+ return "empty";
7665
+ }
7666
+ if (!DOCUMENT2_KEY_PATTERN.test(normalized)) {
7667
+ return "invalid";
7668
+ }
7669
+ if (isDuplicateDocument2Key(normalized, namespace)) {
7670
+ return "duplicate";
7671
+ }
7672
+ return null;
7673
+ }
7674
+
7589
7675
  // src/document2/arabicPreamble.ts
7590
7676
  function arabicXeLatexPreamblePkg(twocolumn = false) {
7591
7677
  const classOptions = twocolumn ? "12pt,a4paper,notitlepage,twocolumn" : "12pt,a4paper,notitlepage";
@@ -8136,13 +8222,11 @@ function floatNumberLabel(document2, key, previewOptions) {
8136
8222
  if (!hit || hit.kind !== "fig" && hit.kind !== "tab") {
8137
8223
  return void 0;
8138
8224
  }
8139
- const locale = previewOptions.uiLocale ?? "ar";
8140
- const kindWord = hit.kind === "fig" ? locale === "ar" ? "\u0627\u0644\u0634\u0643\u0644" : "Figure" : locale === "ar" ? "\u0627\u0644\u062C\u062F\u0648\u0644" : "Table";
8141
- const digits = formatBibliographyNumber(hit.number, {
8225
+ return formatFloatCaptionTitle(hit.kind, hit.number, {
8226
+ uiLocale: previewOptions.uiLocale ?? "ar",
8142
8227
  documentDirection: previewOptions.documentDirection,
8143
8228
  digitForm: previewOptions.digitForm
8144
8229
  });
8145
- return `${kindWord} ${digits}`;
8146
8230
  }
8147
8231
  function blockPreview(block, islands, output, equationSide, document2, previewOptions) {
8148
8232
  if (block.kind === "textBlock") {
@@ -8197,7 +8281,8 @@ function blockPreview(block, islands, output, equationSide, document2, previewOp
8197
8281
  title: reference.title,
8198
8282
  year: reference.year,
8199
8283
  url: reference.url,
8200
- venue: reference.venue
8284
+ venue: reference.venue,
8285
+ fieldSeparator: reference.fieldSeparator
8201
8286
  }))
8202
8287
  };
8203
8288
  }
@@ -8348,6 +8433,15 @@ var DOCUMENT2_MESSAGES = {
8348
8433
  labelKindFig: "\u0634\u0643\u0644",
8349
8434
  labelKindTab: "\u062C\u062F\u0648\u0644",
8350
8435
  labelKindEq: "\u0645\u0639\u0627\u062F\u0644\u0629",
8436
+ captionPreview: "\u0645\u0639\u0627\u064A\u0646\u0629 \u0627\u0644\u062A\u0639\u0644\u064A\u0642",
8437
+ referencePreview: "\u0645\u0639\u0627\u064A\u0646\u0629 \u0627\u0644\u0645\u0631\u062C\u0639",
8438
+ referenceFieldSeparator: "\u0641\u0627\u0635\u0644 \u0627\u0644\u062D\u0642\u0648\u0644",
8439
+ referenceCommaLtr: "\u0641\u0627\u0635\u0644\u0629 \u0625\u0646\u062C\u0644\u064A\u0632\u064A\u0629 ,",
8440
+ referenceCommaRtl: "\u0641\u0627\u0635\u0644\u0629 \u0639\u0631\u0628\u064A\u0629 \u060C",
8441
+ keyEmpty: "\u0627\u0644\u0645\u0641\u062A\u0627\u062D \u0645\u0637\u0644\u0648\u0628",
8442
+ 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",
8443
+ keyDuplicate: "\u0647\u0630\u0627 \u0627\u0644\u0645\u0641\u062A\u0627\u062D \u0645\u0633\u062A\u062E\u062F\u0645 \u0645\u0633\u0628\u0642\u0627\u064B",
8444
+ 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",
8351
8445
  citePickerTitle: "\u0627\u062E\u062A\u064A\u0627\u0631 \u0627\u0644\u0645\u0631\u0627\u062C\u0639",
8352
8446
  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.",
8353
8447
  editCitation: "\u062A\u062D\u0631\u064A\u0631 \u0627\u0644\u0627\u0642\u062A\u0628\u0627\u0633",
@@ -8478,6 +8572,15 @@ var DOCUMENT2_MESSAGES = {
8478
8572
  labelKindFig: "Figure",
8479
8573
  labelKindTab: "Table",
8480
8574
  labelKindEq: "Equation",
8575
+ captionPreview: "Caption preview",
8576
+ referencePreview: "Reference preview",
8577
+ referenceFieldSeparator: "Field separator",
8578
+ referenceCommaLtr: "Latin comma ,",
8579
+ referenceCommaRtl: "Arabic comma \u060C",
8580
+ keyEmpty: "Key is required",
8581
+ keyInvalid: "Invalid key: letters, digits, and `:._-` only; no spaces",
8582
+ keyDuplicate: "This key is already in use",
8583
+ keyRulesHint: "Letters (Arabic or Latin), digits, and `:._-`; no spaces",
8481
8584
  citePickerTitle: "Select references",
8482
8585
  noReferencesYet: "No references yet. Add a reference first.",
8483
8586
  editCitation: "Edit citation",
@@ -8715,7 +8818,10 @@ function focusArticleMetaPanel(panel) {
8715
8818
  }
8716
8819
 
8717
8820
  // src/react-document2/ButexDocumentEditor2.tsx
8718
- var import_react11 = require("react");
8821
+ var import_react13 = require("react");
8822
+
8823
+ // src/react-document2/BlockEditor.tsx
8824
+ var import_react4 = require("react");
8719
8825
 
8720
8826
  // src/react-document2/InlineField.tsx
8721
8827
  var import_react3 = require("react");
@@ -9752,6 +9858,18 @@ function inlineFieldSummary(field) {
9752
9858
  }).join("")
9753
9859
  );
9754
9860
  }
9861
+ function keyErrorMessage(error, messages) {
9862
+ if (error === "empty") {
9863
+ return messages.keyEmpty;
9864
+ }
9865
+ if (error === "invalid") {
9866
+ return messages.keyInvalid;
9867
+ }
9868
+ if (error === "duplicate") {
9869
+ return messages.keyDuplicate;
9870
+ }
9871
+ return null;
9872
+ }
9755
9873
  function FloatMetaEditor({
9756
9874
  captionEnabled,
9757
9875
  caption,
@@ -9760,8 +9878,18 @@ function FloatMetaEditor({
9760
9878
  labelPlaceholder,
9761
9879
  labelDir,
9762
9880
  messages,
9881
+ ownerId,
9882
+ references,
9883
+ labels,
9763
9884
  onChange
9764
9885
  }) {
9886
+ const [labelOverride, setLabelOverride] = (0, import_react4.useState)(null);
9887
+ const displayedLabel = labelOverride ?? label;
9888
+ const labelError = labelEnabled ? document2KeyError(displayedLabel, {
9889
+ references,
9890
+ labels,
9891
+ excludeOwnerId: ownerId
9892
+ }) : null;
9765
9893
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "butex-document2-widget__float-meta", children: [
9766
9894
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { className: "butex-document2-widget__float-meta-toggle", children: [
9767
9895
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
@@ -9811,15 +9939,27 @@ function FloatMetaEditor({
9811
9939
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
9812
9940
  "input",
9813
9941
  {
9814
- value: label,
9942
+ value: displayedLabel,
9815
9943
  dir: labelDir,
9816
9944
  placeholder: labelPlaceholder,
9945
+ "aria-invalid": labelError !== null ? true : void 0,
9817
9946
  onChange: (event) => {
9818
9947
  const value = event.currentTarget.value;
9948
+ setLabelOverride(value);
9949
+ const error = document2KeyError(value, {
9950
+ references,
9951
+ labels,
9952
+ excludeOwnerId: ownerId
9953
+ });
9954
+ if (error !== null) {
9955
+ return;
9956
+ }
9819
9957
  onChange({ label: value });
9958
+ setLabelOverride(null);
9820
9959
  }
9821
9960
  }
9822
- )
9961
+ ),
9962
+ labelError !== null ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "butex-document2-widget__field-error", children: labelError === "invalid" ? messages.keyRulesHint : keyErrorMessage(labelError, messages) }) : null
9823
9963
  ] }) : null
9824
9964
  ] });
9825
9965
  }
@@ -9878,6 +10018,8 @@ function BlockEditor({
9878
10018
  onManageReferences
9879
10019
  }) {
9880
10020
  const messages = document2Messages(uiLocale);
10021
+ const labels = documentNode ? collectDocument2Labels(documentNode) : [];
10022
+ const referenceList = references ?? [];
9881
10023
  const showChrome = depth === 0;
9882
10024
  const chromeClass = [
9883
10025
  blockChromeClass(block),
@@ -10040,6 +10182,9 @@ function BlockEditor({
10040
10182
  labelPlaceholder: messages.tableLabelPlaceholder,
10041
10183
  labelDir: uiLocaleDirection(uiLocale),
10042
10184
  messages,
10185
+ ownerId: block.id,
10186
+ references: referenceList,
10187
+ labels,
10043
10188
  onChange: (patch) => onFloatMetaChange?.(block.id, "table", patch)
10044
10189
  }
10045
10190
  )
@@ -10083,6 +10228,9 @@ function BlockEditor({
10083
10228
  labelPlaceholder: messages.figureLabelPlaceholder,
10084
10229
  labelDir: uiLocaleDirection(uiLocale),
10085
10230
  messages,
10231
+ ownerId: block.id,
10232
+ references: referenceList,
10233
+ labels,
10086
10234
  onChange: (patch) => onFloatMetaChange?.(block.id, "image", patch)
10087
10235
  }
10088
10236
  )
@@ -10091,14 +10239,16 @@ function BlockEditor({
10091
10239
  if (block.kind === "bibliography") {
10092
10240
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: chromeClass, children: [
10093
10241
  header,
10094
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ol", { className: "butex-document2-widget__bibliography-editor", dir: documentDirection, children: references.map((reference, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { children: [
10242
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ol", { className: "butex-document2-widget__bibliography-editor", dir: documentDirection, children: referenceList.map((reference, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { children: [
10095
10243
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("strong", { children: [
10096
10244
  "[",
10097
- index + 1,
10245
+ formatBibliographyNumber(index + 1, { documentDirection, digitForm }),
10098
10246
  "] ",
10099
10247
  reference.key
10100
10248
  ] }),
10101
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: [reference.authors, reference.title, reference.venue, reference.year].filter(Boolean).join(" \u2014 ") })
10249
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: bibliographyEntryBody(reference, reference.fieldSeparator, {
10250
+ digitForm: digitForm ?? (documentDirection === "rtl" ? "arabicIndic" : "western")
10251
+ }) })
10102
10252
  ] }, reference.id)) }),
10103
10253
  onManageReferences ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", onClick: onManageReferences, children: messages.manageReferences }) : null
10104
10254
  ] });
@@ -10110,20 +10260,22 @@ function BlockEditor({
10110
10260
  }
10111
10261
 
10112
10262
  // src/react-document2/CitePickerPopover.tsx
10113
- var import_react4 = require("react");
10263
+ var import_react5 = require("react");
10114
10264
  var import_jsx_runtime8 = require("react/jsx-runtime");
10115
10265
  function CitePickerPopover({
10116
10266
  open,
10117
10267
  references,
10118
10268
  initialKeys = [],
10119
10269
  uiLocale = "ar",
10270
+ digitForm = "arabicIndic",
10120
10271
  onClose,
10121
10272
  onConfirm,
10122
10273
  onManageReferences
10123
10274
  }) {
10124
10275
  const messages = document2Messages(uiLocale);
10125
- const [selected, setSelected] = (0, import_react4.useState)(initialKeys);
10126
- (0, import_react4.useEffect)(() => {
10276
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
10277
+ const [selected, setSelected] = (0, import_react5.useState)(initialKeys);
10278
+ (0, import_react5.useEffect)(() => {
10127
10279
  if (open) {
10128
10280
  setSelected(initialKeys);
10129
10281
  }
@@ -10149,12 +10301,13 @@ function CitePickerPopover({
10149
10301
  references.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noReferencesYet }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { className: "butex-document2-widget__cite-picker-list", children: references.map((reference, index) => {
10150
10302
  const checked = selected.includes(reference.key);
10151
10303
  const subtitle = [reference.authors, reference.title].filter(Boolean).join(" \u2014 ");
10304
+ const numberLabel = formatBibliographyNumber(index + 1, { documentDirection, digitForm });
10152
10305
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "butex-document2-widget__cite-picker-item", children: [
10153
10306
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked, onChange: () => toggleKey(reference.key) }),
10154
10307
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
10155
10308
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("strong", { children: [
10156
10309
  "[",
10157
- index + 1,
10310
+ numberLabel,
10158
10311
  "] ",
10159
10312
  reference.key
10160
10313
  ] }),
@@ -10182,18 +10335,18 @@ function CitePickerPopover({
10182
10335
  }
10183
10336
 
10184
10337
  // src/react-document2/DocumentInsertToolbar.tsx
10185
- var import_react6 = require("react");
10338
+ var import_react7 = require("react");
10186
10339
 
10187
10340
  // src/react-document2/TableInsertPopover.tsx
10188
- var import_react5 = require("react");
10341
+ var import_react6 = require("react");
10189
10342
  var import_jsx_runtime9 = require("react/jsx-runtime");
10190
10343
  function TableInsertPopover({ uiLocale = "ar", onConfirm }) {
10191
10344
  const messages = document2Messages(uiLocale);
10192
- const [open, setOpen] = (0, import_react5.useState)(false);
10193
- const [rows, setRows] = (0, import_react5.useState)("3");
10194
- const [cols, setCols] = (0, import_react5.useState)("3");
10195
- const rootRef = (0, import_react5.useRef)(null);
10196
- (0, import_react5.useEffect)(() => {
10345
+ const [open, setOpen] = (0, import_react6.useState)(false);
10346
+ const [rows, setRows] = (0, import_react6.useState)("3");
10347
+ const [cols, setCols] = (0, import_react6.useState)("3");
10348
+ const rootRef = (0, import_react6.useRef)(null);
10349
+ (0, import_react6.useEffect)(() => {
10197
10350
  if (!open) {
10198
10351
  return;
10199
10352
  }
@@ -10284,7 +10437,7 @@ function DocumentInsertToolbar({
10284
10437
  onDigitFormChange
10285
10438
  }) {
10286
10439
  const messages = document2Messages(uiLocale);
10287
- const [digitMenuOpen, setDigitMenuOpen] = (0, import_react6.useState)(false);
10440
+ const [digitMenuOpen, setDigitMenuOpen] = (0, import_react7.useState)(false);
10288
10441
  function digitTitle(id) {
10289
10442
  if (id === "arabicIndic") {
10290
10443
  return messages.arabicIndicDigits;
@@ -10455,7 +10608,8 @@ function PreviewBlock({
10455
10608
  output,
10456
10609
  resolveImageUrl,
10457
10610
  uiLocale,
10458
- documentDirection
10611
+ documentDirection,
10612
+ digitForm
10459
10613
  }) {
10460
10614
  const messages = document2Messages(uiLocale);
10461
10615
  const floatCaptionSeparator = uiLocale === "ar" ? ": " : ". ";
@@ -10514,7 +10668,8 @@ function PreviewBlock({
10514
10668
  output,
10515
10669
  resolveImageUrl,
10516
10670
  uiLocale,
10517
- documentDirection
10671
+ documentDirection,
10672
+ digitForm
10518
10673
  },
10519
10674
  child.id
10520
10675
  ))
@@ -10544,10 +10699,10 @@ function PreviewBlock({
10544
10699
  ] }),
10545
10700
  " ",
10546
10701
  /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { children: [
10547
- [item.authors, item.title, item.venue, item.year].filter(Boolean).join(", "),
10702
+ bibliographyEntryBody(item, item.fieldSeparator, { digitForm }),
10548
10703
  item.url ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
10549
10704
  " ",
10550
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { href: item.url, target: "_blank", rel: "noreferrer", children: item.url })
10705
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("a", { href: absoluteHttpHref(item.url), target: "_blank", rel: "noreferrer", children: item.url })
10551
10706
  ] }) : null
10552
10707
  ] })
10553
10708
  ] }, item.id)) });
@@ -10559,9 +10714,11 @@ function DocumentPreview({
10559
10714
  output,
10560
10715
  documentDirection = "rtl",
10561
10716
  uiLocale = "ar",
10717
+ digitForm,
10562
10718
  resolveImageUrl
10563
10719
  }) {
10564
10720
  const messages = document2Messages(uiLocale);
10721
+ const resolvedDigitForm = digitForm ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
10565
10722
  const hasBody = blocks.some(isBodyPreviewBlock);
10566
10723
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "butex-document2-widget__preview", dir: documentDirection, children: [
10567
10724
  blocks.map((block) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
@@ -10571,7 +10728,8 @@ function DocumentPreview({
10571
10728
  output,
10572
10729
  resolveImageUrl,
10573
10730
  uiLocale,
10574
- documentDirection
10731
+ documentDirection,
10732
+ digitForm: resolvedDigitForm
10575
10733
  },
10576
10734
  block.id
10577
10735
  )),
@@ -10580,10 +10738,10 @@ function DocumentPreview({
10580
10738
  }
10581
10739
 
10582
10740
  // src/react-document2/EquationDrawer.tsx
10583
- var import_react8 = require("react");
10741
+ var import_react9 = require("react");
10584
10742
 
10585
10743
  // src/react/ButexEditor.tsx
10586
- var import_react7 = require("react");
10744
+ var import_react8 = require("react");
10587
10745
 
10588
10746
  // src/react/widgetChromeCss.ts
10589
10747
  var WIDGET_CHROME_CSS = `
@@ -11629,61 +11787,61 @@ function passiveTreeText(session, messages) {
11629
11787
 
11630
11788
  ${latex || messages.empty}`;
11631
11789
  }
11632
- var ButexEditor = (0, import_react7.forwardRef)(
11790
+ var ButexEditor = (0, import_react8.forwardRef)(
11633
11791
  function ButexEditor2({ className, debug = false, defaultSide, uiLocale = "ar", initialSession, onSessionChange }, ref) {
11634
11792
  const messages = equationEditorMessages(uiLocale);
11635
- const wrapperRef = (0, import_react7.useRef)(null);
11636
- const surfaceRef = (0, import_react7.useRef)(null);
11637
- const mathOutputRef = (0, import_react7.useRef)(null);
11638
- const renderErrorRef = (0, import_react7.useRef)(null);
11639
- const latexLinesRef = (0, import_react7.useRef)(null);
11640
- const passivePreviewRef = (0, import_react7.useRef)(null);
11641
- const debugLogRef = (0, import_react7.useRef)(null);
11642
- const undoBtnRef = (0, import_react7.useRef)(null);
11643
- const redoBtnRef = (0, import_react7.useRef)(null);
11644
- const copyBtnRef = (0, import_react7.useRef)(null);
11645
- const cutBtnRef = (0, import_react7.useRef)(null);
11646
- const splitTypingBtnRef = (0, import_react7.useRef)(null);
11647
- const characterFontBtnRef = (0, import_react7.useRef)(null);
11648
- const digitFormBtnRef = (0, import_react7.useRef)(null);
11649
- const runtimeRef = (0, import_react7.useRef)(null);
11650
- const debugRef = (0, import_react7.useRef)(debug);
11793
+ const wrapperRef = (0, import_react8.useRef)(null);
11794
+ const surfaceRef = (0, import_react8.useRef)(null);
11795
+ const mathOutputRef = (0, import_react8.useRef)(null);
11796
+ const renderErrorRef = (0, import_react8.useRef)(null);
11797
+ const latexLinesRef = (0, import_react8.useRef)(null);
11798
+ const passivePreviewRef = (0, import_react8.useRef)(null);
11799
+ const debugLogRef = (0, import_react8.useRef)(null);
11800
+ const undoBtnRef = (0, import_react8.useRef)(null);
11801
+ const redoBtnRef = (0, import_react8.useRef)(null);
11802
+ const copyBtnRef = (0, import_react8.useRef)(null);
11803
+ const cutBtnRef = (0, import_react8.useRef)(null);
11804
+ const splitTypingBtnRef = (0, import_react8.useRef)(null);
11805
+ const characterFontBtnRef = (0, import_react8.useRef)(null);
11806
+ const digitFormBtnRef = (0, import_react8.useRef)(null);
11807
+ const runtimeRef = (0, import_react8.useRef)(null);
11808
+ const debugRef = (0, import_react8.useRef)(debug);
11651
11809
  debugRef.current = debug;
11652
- const uiLocaleRef = (0, import_react7.useRef)(uiLocale);
11810
+ const uiLocaleRef = (0, import_react8.useRef)(uiLocale);
11653
11811
  uiLocaleRef.current = uiLocale;
11654
- const onSessionChangeRef = (0, import_react7.useRef)(onSessionChange);
11812
+ const onSessionChangeRef = (0, import_react8.useRef)(onSessionChange);
11655
11813
  onSessionChangeRef.current = onSessionChange;
11656
- const debugBodyHiddenRef = (0, import_react7.useRef)(false);
11657
- const [debugBodyHidden, setDebugBodyHidden] = (0, import_react7.useState)(false);
11814
+ const debugBodyHiddenRef = (0, import_react8.useRef)(false);
11815
+ const [debugBodyHidden, setDebugBodyHidden] = (0, import_react8.useState)(false);
11658
11816
  debugBodyHiddenRef.current = debugBodyHidden;
11659
- const [digitMenuOpen, setDigitMenuOpen] = (0, import_react7.useState)(false);
11660
- const [characterFontMenuOpen, setCharacterFontMenuOpen] = (0, import_react7.useState)(false);
11661
- const [delimiterMenuOpen, setDelimiterMenuOpen] = (0, import_react7.useState)(false);
11662
- const [matrixMenuOpen, setMatrixMenuOpen] = (0, import_react7.useState)(false);
11663
- const [spacingMenuOpen, setSpacingMenuOpen] = (0, import_react7.useState)(false);
11664
- const [functionMenuOpen, setFunctionMenuOpen] = (0, import_react7.useState)(false);
11665
- const [limitsSeriesMenuOpen, setLimitsSeriesMenuOpen] = (0, import_react7.useState)(false);
11666
- const [function2MenuOpen, setFunction2MenuOpen] = (0, import_react7.useState)(false);
11667
- const [derivativeMenuOpen, setDerivativeMenuOpen] = (0, import_react7.useState)(false);
11668
- const [groupMenuOpen, setGroupMenuOpen] = (0, import_react7.useState)(false);
11669
- const [operatorMenuOpen, setOperatorMenuOpen] = (0, import_react7.useState)(false);
11670
- const [operator2MenuOpen, setOperator2MenuOpen] = (0, import_react7.useState)(false);
11671
- const [operator3MenuOpen, setOperator3MenuOpen] = (0, import_react7.useState)(false);
11672
- const [dotMenuOpen, setDotMenuOpen] = (0, import_react7.useState)(false);
11673
- const [integralMenuOpen, setIntegralMenuOpen] = (0, import_react7.useState)(false);
11674
- const [selectedDigitForm2, setSelectedDigitForm] = (0, import_react7.useState)("western");
11675
- const [selectedCharacterFont, setSelectedCharacterFont] = (0, import_react7.useState)("default");
11676
- const [activeEditorSide, setActiveEditorSide] = (0, import_react7.useState)("arabic");
11677
- const [envPaletteMode, setEnvPaletteMode] = (0, import_react7.useState)("matrix");
11678
- const [matrixStyle, setMatrixStyle] = (0, import_react7.useState)("pmatrix");
11679
- const [matrixRows, setMatrixRows] = (0, import_react7.useState)(2);
11680
- const [matrixColumns, setMatrixColumns] = (0, import_react7.useState)(2);
11681
- const [matrixHover, setMatrixHover] = (0, import_react7.useState)(null);
11682
- const [arrayAlignmentColumn, setArrayAlignmentColumn] = (0, import_react7.useState)(1);
11683
- (0, import_react7.useImperativeHandle)(ref, () => ({
11817
+ const [digitMenuOpen, setDigitMenuOpen] = (0, import_react8.useState)(false);
11818
+ const [characterFontMenuOpen, setCharacterFontMenuOpen] = (0, import_react8.useState)(false);
11819
+ const [delimiterMenuOpen, setDelimiterMenuOpen] = (0, import_react8.useState)(false);
11820
+ const [matrixMenuOpen, setMatrixMenuOpen] = (0, import_react8.useState)(false);
11821
+ const [spacingMenuOpen, setSpacingMenuOpen] = (0, import_react8.useState)(false);
11822
+ const [functionMenuOpen, setFunctionMenuOpen] = (0, import_react8.useState)(false);
11823
+ const [limitsSeriesMenuOpen, setLimitsSeriesMenuOpen] = (0, import_react8.useState)(false);
11824
+ const [function2MenuOpen, setFunction2MenuOpen] = (0, import_react8.useState)(false);
11825
+ const [derivativeMenuOpen, setDerivativeMenuOpen] = (0, import_react8.useState)(false);
11826
+ const [groupMenuOpen, setGroupMenuOpen] = (0, import_react8.useState)(false);
11827
+ const [operatorMenuOpen, setOperatorMenuOpen] = (0, import_react8.useState)(false);
11828
+ const [operator2MenuOpen, setOperator2MenuOpen] = (0, import_react8.useState)(false);
11829
+ const [operator3MenuOpen, setOperator3MenuOpen] = (0, import_react8.useState)(false);
11830
+ const [dotMenuOpen, setDotMenuOpen] = (0, import_react8.useState)(false);
11831
+ const [integralMenuOpen, setIntegralMenuOpen] = (0, import_react8.useState)(false);
11832
+ const [selectedDigitForm2, setSelectedDigitForm] = (0, import_react8.useState)("western");
11833
+ const [selectedCharacterFont, setSelectedCharacterFont] = (0, import_react8.useState)("default");
11834
+ const [activeEditorSide, setActiveEditorSide] = (0, import_react8.useState)("arabic");
11835
+ const [envPaletteMode, setEnvPaletteMode] = (0, import_react8.useState)("matrix");
11836
+ const [matrixStyle, setMatrixStyle] = (0, import_react8.useState)("pmatrix");
11837
+ const [matrixRows, setMatrixRows] = (0, import_react8.useState)(2);
11838
+ const [matrixColumns, setMatrixColumns] = (0, import_react8.useState)(2);
11839
+ const [matrixHover, setMatrixHover] = (0, import_react8.useState)(null);
11840
+ const [arrayAlignmentColumn, setArrayAlignmentColumn] = (0, import_react8.useState)(1);
11841
+ (0, import_react8.useImperativeHandle)(ref, () => ({
11684
11842
  getRuntime: () => runtimeRef.current
11685
11843
  }));
11686
- const updatePreview = (0, import_react7.useCallback)(async (session) => {
11844
+ const updatePreview = (0, import_react8.useCallback)(async (session) => {
11687
11845
  const mathOutputEl = mathOutputRef.current;
11688
11846
  const renderErrorEl = renderErrorRef.current;
11689
11847
  const latexLinesEl = latexLinesRef.current;
@@ -11733,9 +11891,9 @@ ${arabic || currentMessages.empty}`;
11733
11891
  }
11734
11892
  }
11735
11893
  }, []);
11736
- const updatePreviewRef = (0, import_react7.useRef)(updatePreview);
11894
+ const updatePreviewRef = (0, import_react8.useRef)(updatePreview);
11737
11895
  updatePreviewRef.current = updatePreview;
11738
- (0, import_react7.useEffect)(() => {
11896
+ (0, import_react8.useEffect)(() => {
11739
11897
  injectWidgetChromeCss();
11740
11898
  injectBuTeXEditorStyles(typeof document !== "undefined" ? document : void 0);
11741
11899
  const surfaceEl = surfaceRef.current;
@@ -11791,7 +11949,7 @@ ${arabic || currentMessages.empty}`;
11791
11949
  runtimeRef.current = null;
11792
11950
  };
11793
11951
  }, []);
11794
- (0, import_react7.useEffect)(() => {
11952
+ (0, import_react8.useEffect)(() => {
11795
11953
  runtimeRef.current?.setUiLocale(uiLocale);
11796
11954
  const session = runtimeRef.current?.getSession();
11797
11955
  if (session) {
@@ -12864,6 +13022,18 @@ ButexEditor.displayName = "ButexEditor";
12864
13022
 
12865
13023
  // src/react-document2/EquationDrawer.tsx
12866
13024
  var import_jsx_runtime13 = require("react/jsx-runtime");
13025
+ function keyErrorMessage2(error, messages) {
13026
+ if (error === "empty") {
13027
+ return messages.keyEmpty;
13028
+ }
13029
+ if (error === "invalid") {
13030
+ return messages.keyInvalid;
13031
+ }
13032
+ if (error === "duplicate") {
13033
+ return messages.keyDuplicate;
13034
+ }
13035
+ return null;
13036
+ }
12867
13037
  function EquationDrawer({
12868
13038
  session,
12869
13039
  reason,
@@ -12873,6 +13043,9 @@ function EquationDrawer({
12873
13043
  uiLocale = "ar",
12874
13044
  labelEnabled = false,
12875
13045
  label = "",
13046
+ labels = [],
13047
+ references = [],
13048
+ ownerId = "",
12876
13049
  onLabelEnabledChange,
12877
13050
  onLabelChange,
12878
13051
  onMathModeChange,
@@ -12881,8 +13054,18 @@ function EquationDrawer({
12881
13054
  onDelete
12882
13055
  }) {
12883
13056
  const messages = document2Messages(uiLocale);
12884
- const latestSession = (0, import_react8.useRef)(session);
12885
- (0, import_react8.useEffect)(() => {
13057
+ const latestSession = (0, import_react9.useRef)(session);
13058
+ const [labelOverride, setLabelOverride] = (0, import_react9.useState)(null);
13059
+ const displayedLabel = labelOverride ?? label;
13060
+ const labelError = labelEnabled && mathMode === "display" ? document2KeyError(displayedLabel, {
13061
+ references,
13062
+ labels,
13063
+ excludeOwnerId: ownerId || void 0
13064
+ }) : null;
13065
+ (0, import_react9.useEffect)(() => {
13066
+ setLabelOverride(null);
13067
+ }, [ownerId, label]);
13068
+ (0, import_react9.useEffect)(() => {
12886
13069
  const onKeyDown = (event) => {
12887
13070
  if (event.key === "Escape") {
12888
13071
  onClose();
@@ -12942,12 +13125,27 @@ function EquationDrawer({
12942
13125
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
12943
13126
  "input",
12944
13127
  {
12945
- value: label,
13128
+ value: displayedLabel,
12946
13129
  dir: uiLocaleDirection(uiLocale),
12947
13130
  placeholder: messages.equationLabelPlaceholder,
12948
- onChange: (event) => onLabelChange?.(event.currentTarget.value)
13131
+ "aria-invalid": labelError !== null ? true : void 0,
13132
+ onChange: (event) => {
13133
+ const value = event.currentTarget.value;
13134
+ setLabelOverride(value);
13135
+ const error = document2KeyError(value, {
13136
+ references,
13137
+ labels,
13138
+ excludeOwnerId: ownerId || void 0
13139
+ });
13140
+ if (error !== null) {
13141
+ return;
13142
+ }
13143
+ onLabelChange?.(value);
13144
+ setLabelOverride(null);
13145
+ }
12949
13146
  }
12950
- )
13147
+ ),
13148
+ labelError !== null ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "butex-document2-widget__field-error", children: labelError === "invalid" ? messages.keyRulesHint : keyErrorMessage2(labelError, messages) }) : null
12951
13149
  ] }) : null
12952
13150
  ] }) : null,
12953
13151
  reason ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "butex-document2-widget__error", children: uiLocale === "en" ? messages.equationUnavailable : reason }) : null,
@@ -12965,7 +13163,15 @@ function EquationDrawer({
12965
13163
  ),
12966
13164
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "butex-document2-widget__row", children: [
12967
13165
  canDelete && onDelete ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", className: "butex-document2-widget__button--danger", onClick: onDelete, children: messages.deleteEquation }) : null,
12968
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", onClick: () => onSave({ ...latestSession.current, activeSide: equationSide }), children: messages.saveEquation })
13166
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
13167
+ "button",
13168
+ {
13169
+ type: "button",
13170
+ disabled: labelEnabled && mathMode === "display" && labelError !== null,
13171
+ onClick: () => onSave({ ...latestSession.current, activeSide: equationSide }),
13172
+ children: messages.saveEquation
13173
+ }
13174
+ )
12969
13175
  ] })
12970
13176
  ]
12971
13177
  }
@@ -12974,92 +13180,243 @@ function EquationDrawer({
12974
13180
  }
12975
13181
 
12976
13182
  // src/react-document2/LabelsPanel.tsx
13183
+ var import_react10 = require("react");
12977
13184
  var import_jsx_runtime14 = require("react/jsx-runtime");
12978
- function kindLabel(kind, uiLocale) {
12979
- const messages = document2Messages(uiLocale);
12980
- if (kind === "fig") {
12981
- return messages.labelKindFig;
13185
+ function keyErrorMessage3(error, messages) {
13186
+ if (error === "empty") {
13187
+ return messages.keyEmpty;
12982
13188
  }
12983
- if (kind === "tab") {
12984
- return messages.labelKindTab;
13189
+ if (error === "invalid") {
13190
+ return messages.keyInvalid;
12985
13191
  }
12986
- return messages.labelKindEq;
13192
+ if (error === "duplicate") {
13193
+ return messages.keyDuplicate;
13194
+ }
13195
+ return null;
12987
13196
  }
12988
13197
  function LabelsPanel({
12989
13198
  open,
12990
13199
  labels,
13200
+ references = [],
12991
13201
  uiLocale = "ar",
13202
+ digitForm = "arabicIndic",
12992
13203
  onClose,
12993
13204
  onUpdateFloat,
12994
13205
  onUpdateEquationLabel
12995
13206
  }) {
12996
13207
  const messages = document2Messages(uiLocale);
13208
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
13209
+ const [keyOverrides, setKeyOverrides] = (0, import_react10.useState)({});
12997
13210
  if (!open) {
12998
13211
  return null;
12999
13212
  }
13000
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "butex-document2-widget__refs-panel", role: "dialog", "aria-label": messages.labelsTitle, onClick: (event) => event.stopPropagation(), children: [
13001
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("header", { className: "butex-document2-widget__refs-header", children: [
13002
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: messages.labelsTitle }),
13003
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
13004
- ] }),
13005
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "butex-document2-widget__labels-help", children: messages.labelsHelp }),
13006
- labels.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noLabelsYet }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "butex-document2-widget__refs-list", children: labels.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { className: "butex-document2-widget__refs-item", children: [
13007
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "butex-document2-widget__refs-item-head", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("strong", { children: [
13008
- "[",
13009
- kindLabel(entry.kind, uiLocale),
13010
- " ",
13011
- entry.number,
13012
- "] ",
13013
- entry.key
13014
- ] }) }),
13015
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "butex-document2-widget__refs-grid", children: [
13016
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13017
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: messages.floatLabel }),
13018
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
13019
- "input",
13020
- {
13021
- value: entry.key,
13022
- dir: uiLocaleDirection(uiLocale),
13023
- onChange: (event) => {
13024
- const value = event.currentTarget.value;
13025
- if (entry.kind === "eq") {
13026
- onUpdateEquationLabel?.(entry.ownerId, { label: value, labelEnabled: true });
13027
- } else if (entry.kind === "fig" || entry.kind === "tab") {
13028
- onUpdateFloat?.(entry.ownerId, entry.kind, { label: value, labelEnabled: true });
13029
- }
13030
- }
13031
- }
13032
- )
13213
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
13214
+ "div",
13215
+ {
13216
+ className: "butex-document2-widget__refs-panel",
13217
+ role: "dialog",
13218
+ "aria-label": messages.labelsTitle,
13219
+ onClick: (event) => event.stopPropagation(),
13220
+ children: [
13221
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("header", { className: "butex-document2-widget__refs-header", children: [
13222
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: messages.labelsTitle }),
13223
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
13033
13224
  ] }),
13034
- entry.kind === "fig" || entry.kind === "tab" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13035
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: messages.floatCaption }),
13036
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
13037
- "input",
13038
- {
13039
- value: entry.caption,
13040
- onChange: (event) => {
13041
- const value = event.currentTarget.value;
13042
- const kind = entry.kind;
13043
- if (kind === "fig" || kind === "tab") {
13044
- onUpdateFloat?.(entry.ownerId, kind, { caption: value, captionEnabled: true });
13045
- }
13225
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "butex-document2-widget__labels-help", children: messages.labelsHelp }),
13226
+ labels.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noLabelsYet }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("ul", { className: "butex-document2-widget__refs-list", children: labels.map((entry) => {
13227
+ const title = formatFloatCaptionTitle(entry.kind, entry.number, {
13228
+ uiLocale,
13229
+ digitForm,
13230
+ documentDirection
13231
+ });
13232
+ const captionPreview = entry.kind === "eq" ? title : formatFloatCaptionPreview(title, entry.caption, uiLocale);
13233
+ const overrideKey = `${entry.kind}:${entry.ownerId}`;
13234
+ const displayedKey = keyOverrides[overrideKey] ?? entry.key;
13235
+ const entryKeyError = document2KeyError(displayedKey, {
13236
+ references,
13237
+ labels,
13238
+ excludeOwnerId: entry.ownerId
13239
+ });
13240
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("li", { className: "butex-document2-widget__refs-item", children: [
13241
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "butex-document2-widget__refs-item-head", children: [
13242
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: title }),
13243
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "butex-document2-widget__refs-item-key", children: entry.key })
13244
+ ] }),
13245
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
13246
+ "div",
13247
+ {
13248
+ className: "butex-document2-widget__modal-preview",
13249
+ dir: uiLocaleDirection(uiLocale),
13250
+ "aria-label": messages.captionPreview,
13251
+ children: captionPreview
13046
13252
  }
13047
- }
13048
- )
13049
- ] }) : null
13050
- ] })
13051
- ] }, `${entry.kind}:${entry.ownerId}`)) })
13052
- ] }) });
13253
+ ),
13254
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "butex-document2-widget__refs-grid", children: [
13255
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13256
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: messages.floatLabel }),
13257
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
13258
+ "input",
13259
+ {
13260
+ value: displayedKey,
13261
+ dir: uiLocaleDirection(uiLocale),
13262
+ "aria-invalid": entryKeyError !== null ? true : void 0,
13263
+ onChange: (event) => {
13264
+ const value = event.currentTarget.value;
13265
+ setKeyOverrides((current) => ({ ...current, [overrideKey]: value }));
13266
+ const error = document2KeyError(value, {
13267
+ references,
13268
+ labels,
13269
+ excludeOwnerId: entry.ownerId
13270
+ });
13271
+ if (error !== null) {
13272
+ return;
13273
+ }
13274
+ if (entry.kind === "eq") {
13275
+ onUpdateEquationLabel?.(entry.ownerId, { label: value, labelEnabled: true });
13276
+ } else if (entry.kind === "fig" || entry.kind === "tab") {
13277
+ onUpdateFloat?.(entry.ownerId, entry.kind, { label: value, labelEnabled: true });
13278
+ }
13279
+ setKeyOverrides((current) => {
13280
+ const next = { ...current };
13281
+ delete next[overrideKey];
13282
+ return next;
13283
+ });
13284
+ }
13285
+ }
13286
+ ),
13287
+ entryKeyError !== null ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "butex-document2-widget__field-error", children: entryKeyError === "invalid" ? messages.keyRulesHint : keyErrorMessage3(entryKeyError, messages) }) : null
13288
+ ] }),
13289
+ entry.kind === "fig" || entry.kind === "tab" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13290
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: messages.floatCaption }),
13291
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
13292
+ "input",
13293
+ {
13294
+ value: entry.caption,
13295
+ onChange: (event) => {
13296
+ const value = event.currentTarget.value;
13297
+ const kind = entry.kind;
13298
+ if (kind === "fig" || kind === "tab") {
13299
+ onUpdateFloat?.(entry.ownerId, kind, { caption: value, captionEnabled: true });
13300
+ }
13301
+ }
13302
+ }
13303
+ )
13304
+ ] }) : null
13305
+ ] })
13306
+ ] }, overrideKey);
13307
+ }) })
13308
+ ]
13309
+ }
13310
+ ) });
13053
13311
  }
13054
13312
 
13055
13313
  // src/react-document2/ReferencesPanel.tsx
13056
- var import_react9 = require("react");
13314
+ var import_react11 = require("react");
13057
13315
  var import_jsx_runtime15 = require("react/jsx-runtime");
13058
- var EMPTY_DRAFT = { key: "", authors: "", title: "", year: "", url: "", venue: "" };
13316
+ var EMPTY_DRAFT = {
13317
+ key: "",
13318
+ authors: "",
13319
+ title: "",
13320
+ year: "",
13321
+ url: "",
13322
+ venue: "",
13323
+ field_separator: DEFAULT_REFERENCE_FIELD_SEPARATOR
13324
+ };
13325
+ var REFERENCE_FIELDS = [
13326
+ ["key", "referenceKey"],
13327
+ ["authors", "referenceAuthors"],
13328
+ ["title", "referenceTitle"],
13329
+ ["year", "referenceYear"],
13330
+ ["venue", "referenceVenue"],
13331
+ ["url", "referenceUrl"]
13332
+ ];
13333
+ function keyErrorMessage4(error, messages) {
13334
+ if (error === "empty") {
13335
+ return messages.keyEmpty;
13336
+ }
13337
+ if (error === "invalid") {
13338
+ return messages.keyInvalid;
13339
+ }
13340
+ if (error === "duplicate") {
13341
+ return messages.keyDuplicate;
13342
+ }
13343
+ return null;
13344
+ }
13345
+ function FieldSeparatorToggle({
13346
+ value,
13347
+ messages,
13348
+ onChange
13349
+ }) {
13350
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-field butex-document2-widget__refs-separator", children: [
13351
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: messages.referenceFieldSeparator }),
13352
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-separator-toggle", role: "group", "aria-label": messages.referenceFieldSeparator, children: [
13353
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13354
+ "button",
13355
+ {
13356
+ type: "button",
13357
+ className: value === "\u060C" ? "is-active" : void 0,
13358
+ title: messages.referenceCommaRtl,
13359
+ "aria-label": messages.referenceCommaRtl,
13360
+ "aria-pressed": value === "\u060C",
13361
+ onClick: () => onChange("\u060C"),
13362
+ children: "\u060C"
13363
+ }
13364
+ ),
13365
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13366
+ "button",
13367
+ {
13368
+ type: "button",
13369
+ className: value === "," ? "is-active" : void 0,
13370
+ title: messages.referenceCommaLtr,
13371
+ "aria-label": messages.referenceCommaLtr,
13372
+ "aria-pressed": value === ",",
13373
+ onClick: () => onChange(","),
13374
+ children: ","
13375
+ }
13376
+ )
13377
+ ] })
13378
+ ] });
13379
+ }
13380
+ function ReferencePreview({
13381
+ authors,
13382
+ title,
13383
+ venue,
13384
+ year,
13385
+ url,
13386
+ fieldSeparator,
13387
+ numberLabel,
13388
+ messages,
13389
+ uiLocale,
13390
+ digitForm
13391
+ }) {
13392
+ const body = bibliographyEntryBody({ authors, title, venue, year, fieldSeparator }, fieldSeparator, { digitForm });
13393
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
13394
+ "div",
13395
+ {
13396
+ className: "butex-document2-widget__modal-preview",
13397
+ dir: uiLocaleDirection(uiLocale),
13398
+ "aria-label": messages.referencePreview,
13399
+ children: [
13400
+ numberLabel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "butex-document2-widget__modal-preview-number", children: [
13401
+ "[",
13402
+ numberLabel,
13403
+ "] "
13404
+ ] }) : null,
13405
+ body.length > 0 ? body : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "butex-document2-widget__cite-picker-empty", children: "\u2026" }),
13406
+ url.trim().length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
13407
+ " ",
13408
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "butex-document2-widget__modal-preview-url", children: url.trim() })
13409
+ ] }) : null
13410
+ ]
13411
+ }
13412
+ );
13413
+ }
13059
13414
  function ReferencesPanel({
13060
13415
  open,
13061
13416
  references,
13417
+ labels = [],
13062
13418
  uiLocale = "ar",
13419
+ digitForm = "arabicIndic",
13063
13420
  onClose,
13064
13421
  onAdd,
13065
13422
  onUpdate,
@@ -13067,101 +13424,190 @@ function ReferencesPanel({
13067
13424
  onMove
13068
13425
  }) {
13069
13426
  const messages = document2Messages(uiLocale);
13070
- const [draft, setDraft] = (0, import_react9.useState)(EMPTY_DRAFT);
13427
+ const [draft, setDraft] = (0, import_react11.useState)(EMPTY_DRAFT);
13428
+ const [draftKeyTouched, setDraftKeyTouched] = (0, import_react11.useState)(false);
13429
+ const [keyOverrides, setKeyOverrides] = (0, import_react11.useState)({});
13430
+ const draftSeparator = draft.field_separator === "," ? "," : DEFAULT_REFERENCE_FIELD_SEPARATOR;
13431
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
13432
+ const draftKeyError = (0, import_react11.useMemo)(
13433
+ () => document2KeyError(draft.key ?? "", {
13434
+ references,
13435
+ labels
13436
+ }),
13437
+ [draft.key, references, labels]
13438
+ );
13071
13439
  if (!open) {
13072
13440
  return null;
13073
13441
  }
13074
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-panel", role: "dialog", "aria-label": messages.referencesTitle, onClick: (event) => event.stopPropagation(), children: [
13075
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("header", { className: "butex-document2-widget__refs-header", children: [
13076
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: messages.referencesTitle }),
13077
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
13078
- ] }),
13079
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-add", children: [
13080
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { children: messages.addReference }),
13081
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "butex-document2-widget__refs-grid", children: [
13082
- ["key", messages.referenceKey],
13083
- ["authors", messages.referenceAuthors],
13084
- ["title", messages.referenceTitle],
13085
- ["year", messages.referenceYear],
13086
- ["venue", messages.referenceVenue],
13087
- ["url", messages.referenceUrl]
13088
- ].map(([field, label]) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13089
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: label }),
13090
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13091
- "input",
13092
- {
13093
- value: draft[field] ?? "",
13094
- onChange: (event) => {
13095
- const value = event.currentTarget.value;
13096
- setDraft((current) => ({ ...current, [field]: value }));
13097
- }
13098
- }
13099
- )
13100
- ] }, field)) }),
13101
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13102
- "button",
13103
- {
13104
- type: "button",
13105
- className: "butex-document2-widget__primary-btn",
13106
- disabled: !draft.key?.trim(),
13107
- onClick: () => {
13108
- onAdd(draft);
13109
- setDraft(EMPTY_DRAFT);
13110
- },
13111
- children: messages.addReference
13112
- }
13113
- )
13114
- ] }),
13115
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("ul", { className: "butex-document2-widget__refs-list", children: references.map((reference, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("li", { className: "butex-document2-widget__refs-item", children: [
13116
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-item-head", children: [
13117
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("strong", { children: [
13118
- "[",
13119
- index + 1,
13120
- "] ",
13121
- reference.key
13442
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "butex-document2-widget__refs-backdrop", role: "presentation", onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
13443
+ "div",
13444
+ {
13445
+ className: "butex-document2-widget__refs-panel",
13446
+ role: "dialog",
13447
+ "aria-label": messages.referencesTitle,
13448
+ onClick: (event) => event.stopPropagation(),
13449
+ children: [
13450
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("header", { className: "butex-document2-widget__refs-header", children: [
13451
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: messages.referencesTitle }),
13452
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", className: "butex-document2-widget__icon-btn", title: messages.close, "aria-label": messages.close, onClick: onClose, children: "\xD7" })
13122
13453
  ] }),
13123
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-item-actions", children: [
13124
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", title: messages.moveUp, "aria-label": messages.moveUp, disabled: index === 0, onClick: () => onMove(reference.id, -1), children: "\u2191" }),
13454
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-add", children: [
13455
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("h3", { children: messages.addReference }),
13456
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-grid", children: [
13457
+ REFERENCE_FIELDS.map(([field, messageKey]) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13458
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: messages[messageKey] }),
13459
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13460
+ "input",
13461
+ {
13462
+ value: draft[field] ?? "",
13463
+ "aria-invalid": field === "key" && draftKeyTouched && draftKeyError !== null ? true : void 0,
13464
+ onChange: (event) => {
13465
+ const value = event.currentTarget.value;
13466
+ if (field === "key") {
13467
+ setDraftKeyTouched(true);
13468
+ }
13469
+ setDraft((current) => ({ ...current, [field]: value }));
13470
+ }
13471
+ }
13472
+ ),
13473
+ field === "key" && draftKeyTouched && draftKeyError !== null ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "butex-document2-widget__field-error", children: draftKeyError === "invalid" ? messages.keyRulesHint : keyErrorMessage4(draftKeyError, messages) }) : null
13474
+ ] }, field)),
13475
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13476
+ FieldSeparatorToggle,
13477
+ {
13478
+ value: draftSeparator,
13479
+ messages,
13480
+ onChange: (next) => setDraft((current) => ({ ...current, field_separator: next }))
13481
+ }
13482
+ )
13483
+ ] }),
13125
13484
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13126
- "button",
13485
+ ReferencePreview,
13127
13486
  {
13128
- type: "button",
13129
- title: messages.moveDown,
13130
- "aria-label": messages.moveDown,
13131
- disabled: index === references.length - 1,
13132
- onClick: () => onMove(reference.id, 1),
13133
- children: "\u2193"
13487
+ authors: draft.authors ?? "",
13488
+ title: draft.title ?? "",
13489
+ venue: draft.venue ?? "",
13490
+ year: draft.year ?? "",
13491
+ url: draft.url ?? "",
13492
+ fieldSeparator: draftSeparator,
13493
+ messages,
13494
+ uiLocale,
13495
+ digitForm
13134
13496
  }
13135
13497
  ),
13136
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", title: messages.deleteReference, "aria-label": messages.deleteReference, onClick: () => onRemove(reference.id), children: "\xD7" })
13137
- ] })
13138
- ] }),
13139
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "butex-document2-widget__refs-grid", children: [
13140
- ["key", messages.referenceKey],
13141
- ["authors", messages.referenceAuthors],
13142
- ["title", messages.referenceTitle],
13143
- ["year", messages.referenceYear],
13144
- ["venue", messages.referenceVenue],
13145
- ["url", messages.referenceUrl]
13146
- ].map(([field, label]) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13147
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: label }),
13148
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13149
- "input",
13150
- {
13151
- value: reference[field],
13152
- onChange: (event) => {
13153
- const value = event.currentTarget.value;
13154
- onUpdate(reference.id, { [field]: value });
13498
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13499
+ "button",
13500
+ {
13501
+ type: "button",
13502
+ className: "butex-document2-widget__primary-btn",
13503
+ disabled: draftKeyError !== null,
13504
+ onClick: () => {
13505
+ onAdd({ ...draft, field_separator: draftSeparator });
13506
+ setDraft(EMPTY_DRAFT);
13507
+ setDraftKeyTouched(false);
13508
+ },
13509
+ children: messages.addReference
13155
13510
  }
13156
- }
13157
- )
13158
- ] }, field)) })
13159
- ] }, reference.id)) })
13160
- ] }) });
13511
+ )
13512
+ ] }),
13513
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("ul", { className: "butex-document2-widget__refs-list", children: references.map((reference, index) => {
13514
+ const displayedKey = keyOverrides[reference.id] ?? reference.key;
13515
+ const entryKeyError = document2KeyError(displayedKey, {
13516
+ references,
13517
+ labels,
13518
+ excludeReferenceId: reference.id
13519
+ });
13520
+ const numberLabel = formatBibliographyNumber(index + 1, { documentDirection, digitForm });
13521
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("li", { className: "butex-document2-widget__refs-item", children: [
13522
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-item-head", children: [
13523
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("strong", { children: [
13524
+ "[",
13525
+ numberLabel,
13526
+ "] ",
13527
+ reference.key
13528
+ ] }),
13529
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-item-actions", children: [
13530
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", title: messages.moveUp, "aria-label": messages.moveUp, disabled: index === 0, onClick: () => onMove(reference.id, -1), children: "\u2191" }),
13531
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13532
+ "button",
13533
+ {
13534
+ type: "button",
13535
+ title: messages.moveDown,
13536
+ "aria-label": messages.moveDown,
13537
+ disabled: index === references.length - 1,
13538
+ onClick: () => onMove(reference.id, 1),
13539
+ children: "\u2193"
13540
+ }
13541
+ ),
13542
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { type: "button", title: messages.deleteReference, "aria-label": messages.deleteReference, onClick: () => onRemove(reference.id), children: "\xD7" })
13543
+ ] })
13544
+ ] }),
13545
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13546
+ ReferencePreview,
13547
+ {
13548
+ authors: reference.authors,
13549
+ title: reference.title,
13550
+ venue: reference.venue,
13551
+ year: reference.year,
13552
+ url: reference.url,
13553
+ fieldSeparator: reference.fieldSeparator,
13554
+ numberLabel,
13555
+ messages,
13556
+ uiLocale,
13557
+ digitForm
13558
+ }
13559
+ ),
13560
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "butex-document2-widget__refs-grid", children: [
13561
+ REFERENCE_FIELDS.map(([field, messageKey]) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "butex-document2-widget__refs-field", children: [
13562
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: messages[messageKey] }),
13563
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13564
+ "input",
13565
+ {
13566
+ value: field === "key" ? displayedKey : reference[field],
13567
+ "aria-invalid": field === "key" && entryKeyError !== null ? true : void 0,
13568
+ onChange: (event) => {
13569
+ const value = event.currentTarget.value;
13570
+ if (field !== "key") {
13571
+ onUpdate(reference.id, { [field]: value });
13572
+ return;
13573
+ }
13574
+ setKeyOverrides((current) => ({ ...current, [reference.id]: value }));
13575
+ const error = document2KeyError(value, {
13576
+ references,
13577
+ labels,
13578
+ excludeReferenceId: reference.id
13579
+ });
13580
+ if (error === null) {
13581
+ onUpdate(reference.id, { key: value });
13582
+ setKeyOverrides((current) => {
13583
+ const next = { ...current };
13584
+ delete next[reference.id];
13585
+ return next;
13586
+ });
13587
+ }
13588
+ }
13589
+ }
13590
+ ),
13591
+ field === "key" && entryKeyError !== null ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "butex-document2-widget__field-error", children: entryKeyError === "invalid" ? messages.keyRulesHint : keyErrorMessage4(entryKeyError, messages) }) : null
13592
+ ] }, field)),
13593
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
13594
+ FieldSeparatorToggle,
13595
+ {
13596
+ value: reference.fieldSeparator,
13597
+ messages,
13598
+ onChange: (next) => onUpdate(reference.id, { field_separator: next })
13599
+ }
13600
+ )
13601
+ ] })
13602
+ ] }, reference.id);
13603
+ }) })
13604
+ ]
13605
+ }
13606
+ ) });
13161
13607
  }
13162
13608
 
13163
13609
  // src/react-document2/RefPickerPopover.tsx
13164
- var import_react10 = require("react");
13610
+ var import_react12 = require("react");
13165
13611
  var import_jsx_runtime16 = require("react/jsx-runtime");
13166
13612
  function RefPickerPopover({
13167
13613
  open,
@@ -13169,14 +13615,16 @@ function RefPickerPopover({
13169
13615
  initialKeys = [],
13170
13616
  initialRefCommand = "ref",
13171
13617
  uiLocale = "ar",
13618
+ digitForm = "arabicIndic",
13172
13619
  onClose,
13173
13620
  onConfirm,
13174
13621
  onManageLabels
13175
13622
  }) {
13176
13623
  const messages = document2Messages(uiLocale);
13177
- const [selected, setSelected] = (0, import_react10.useState)(initialKeys);
13178
- const [refCommand, setRefCommand] = (0, import_react10.useState)(initialRefCommand);
13179
- (0, import_react10.useEffect)(() => {
13624
+ const documentDirection = uiLocale === "ar" ? "rtl" : "ltr";
13625
+ const [selected, setSelected] = (0, import_react12.useState)(initialKeys);
13626
+ const [refCommand, setRefCommand] = (0, import_react12.useState)(initialRefCommand);
13627
+ (0, import_react12.useEffect)(() => {
13180
13628
  if (open) {
13181
13629
  setSelected(initialKeys);
13182
13630
  setRefCommand(initialRefCommand);
@@ -13203,16 +13651,18 @@ function RefPickerPopover({
13203
13651
  ] }),
13204
13652
  labels.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "butex-document2-widget__cite-picker-empty", children: messages.noLabelsYet }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ul", { className: "butex-document2-widget__cite-picker-list", children: labels.map((entry) => {
13205
13653
  const checked = selected.includes(entry.key);
13654
+ const title = formatFloatCaptionTitle(entry.kind, entry.number, {
13655
+ uiLocale,
13656
+ digitForm,
13657
+ documentDirection
13658
+ });
13206
13659
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "butex-document2-widget__cite-picker-item", children: [
13207
13660
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "radio", name: "butex-ref-key", checked, onChange: () => selectKey(entry.key, entry.kind) }),
13208
13661
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { children: [
13209
13662
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("strong", { children: [
13210
- "[",
13211
- entry.kind,
13663
+ title,
13212
13664
  " ",
13213
- entry.number,
13214
- "] ",
13215
- entry.key
13665
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "butex-document2-widget__refs-item-key", children: entry.key })
13216
13666
  ] }),
13217
13667
  entry.caption ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "butex-document2-widget__cite-picker-meta", children: entry.caption }) : null
13218
13668
  ] })
@@ -14404,6 +14854,24 @@ var DOCUMENT2_WIDGET_CSS = `
14404
14854
  width: 100%;
14405
14855
  }
14406
14856
 
14857
+ .butex-document2-widget__field-error {
14858
+ color: #b42318;
14859
+ font-size: 0.85em;
14860
+ line-height: 1.35;
14861
+ margin: 0;
14862
+ }
14863
+
14864
+ .butex-document2-widget__field-hint {
14865
+ color: var(--butex-document2-muted);
14866
+ font-size: 0.82em;
14867
+ line-height: 1.35;
14868
+ margin: 0;
14869
+ }
14870
+
14871
+ .butex-document2-widget__refs-field input[aria-invalid='true'] {
14872
+ border-color: color-mix(in srgb, #b42318 55%, var(--butex-document2-border));
14873
+ }
14874
+
14407
14875
  .butex-document2-widget__refs-item {
14408
14876
  border: 1px solid var(--butex-document2-border);
14409
14877
  border-radius: 10px;
@@ -14412,6 +14880,58 @@ var DOCUMENT2_WIDGET_CSS = `
14412
14880
  padding: 0.75rem;
14413
14881
  }
14414
14882
 
14883
+ .butex-document2-widget__refs-item-key {
14884
+ color: var(--butex-document2-muted);
14885
+ font-size: 0.9em;
14886
+ font-weight: 500;
14887
+ }
14888
+
14889
+ .butex-document2-widget__modal-preview {
14890
+ background: color-mix(in srgb, var(--butex-document2-panel) 88%, var(--butex-document2-accent-bg));
14891
+ border: 1px dashed color-mix(in srgb, var(--butex-document2-accent) 30%, var(--butex-document2-border));
14892
+ border-radius: 8px;
14893
+ color: inherit;
14894
+ font-size: 0.95em;
14895
+ line-height: 1.55;
14896
+ padding: 0.55rem 0.7rem;
14897
+ text-align: center;
14898
+ }
14899
+
14900
+ .butex-document2-widget__modal-preview-number {
14901
+ color: var(--butex-document2-muted);
14902
+ font-weight: 600;
14903
+ }
14904
+
14905
+ .butex-document2-widget__modal-preview-url {
14906
+ color: var(--butex-document2-accent);
14907
+ word-break: break-all;
14908
+ }
14909
+
14910
+ .butex-document2-widget__refs-separator-toggle {
14911
+ display: inline-flex;
14912
+ gap: 0.35rem;
14913
+ }
14914
+
14915
+ .butex-document2-widget__refs-separator-toggle button {
14916
+ background: var(--butex-document2-input-bg, var(--butex-document2-panel));
14917
+ border: 1px solid var(--butex-document2-border);
14918
+ border-radius: 6px;
14919
+ color: inherit;
14920
+ cursor: pointer;
14921
+ font: inherit;
14922
+ font-size: 1.15em;
14923
+ line-height: 1;
14924
+ min-width: 2.25rem;
14925
+ padding: 0.35rem 0.55rem;
14926
+ }
14927
+
14928
+ .butex-document2-widget__refs-separator-toggle button.is-active {
14929
+ background: var(--butex-document2-accent-bg);
14930
+ border-color: color-mix(in srgb, var(--butex-document2-accent) 45%, var(--butex-document2-border));
14931
+ color: var(--butex-document2-accent);
14932
+ font-weight: 700;
14933
+ }
14934
+
14415
14935
  .butex-document2-widget__refs-item-actions {
14416
14936
  display: inline-flex;
14417
14937
  gap: 0.25rem;
@@ -14903,36 +15423,36 @@ function ButexDocumentEditor2({
14903
15423
  onLatexChange
14904
15424
  }) {
14905
15425
  const messages = document2Messages(uiLocale);
14906
- const initialState = (0, import_react11.useMemo)(
15426
+ const initialState = (0, import_react13.useMemo)(
14907
15427
  () => resolveInitialDocument2(initialDocument, uiLocale, documentMeta),
14908
15428
  [initialDocument, documentMeta, uiLocale]
14909
15429
  );
14910
- const [documentNode, setDocumentNode] = (0, import_react11.useState)(initialState.document);
14911
- const [error, setError] = (0, import_react11.useState)(initialState.error);
14912
- const [editorOpen, setEditorOpen] = (0, import_react11.useState)(true);
14913
- const [previewOpen, setPreviewOpen] = (0, import_react11.useState)(true);
14914
- const [selectedMath, setSelectedMath] = (0, import_react11.useState)(null);
14915
- const [citePicker, setCitePicker] = (0, import_react11.useState)(null);
14916
- const [referencesOpen, setReferencesOpen] = (0, import_react11.useState)(false);
14917
- const [labelsOpen, setLabelsOpen] = (0, import_react11.useState)(false);
14918
- const [refPicker, setRefPicker] = (0, import_react11.useState)(null);
14919
- const [digitFormState, setDigitFormState] = (0, import_react11.useState)(null);
14920
- const [editorFocus, setEditorFocus] = (0, import_react11.useState)(createEmptyDocument2EditorFocus());
14921
- const [collapsedBlockIds, setCollapsedBlockIds] = (0, import_react11.useState)(() => /* @__PURE__ */ new Set());
14922
- const [blockSelectionState, setBlockSelectionState] = (0, import_react11.useState)(emptyBlockSelection);
14923
- const [historyTick, setHistoryTick] = (0, import_react11.useState)(0);
15430
+ const [documentNode, setDocumentNode] = (0, import_react13.useState)(initialState.document);
15431
+ const [error, setError] = (0, import_react13.useState)(initialState.error);
15432
+ const [editorOpen, setEditorOpen] = (0, import_react13.useState)(true);
15433
+ const [previewOpen, setPreviewOpen] = (0, import_react13.useState)(true);
15434
+ const [selectedMath, setSelectedMath] = (0, import_react13.useState)(null);
15435
+ const [citePicker, setCitePicker] = (0, import_react13.useState)(null);
15436
+ const [referencesOpen, setReferencesOpen] = (0, import_react13.useState)(false);
15437
+ const [labelsOpen, setLabelsOpen] = (0, import_react13.useState)(false);
15438
+ const [refPicker, setRefPicker] = (0, import_react13.useState)(null);
15439
+ const [digitFormState, setDigitFormState] = (0, import_react13.useState)(null);
15440
+ const [editorFocus, setEditorFocus] = (0, import_react13.useState)(createEmptyDocument2EditorFocus());
15441
+ const [collapsedBlockIds, setCollapsedBlockIds] = (0, import_react13.useState)(() => /* @__PURE__ */ new Set());
15442
+ const [blockSelectionState, setBlockSelectionState] = (0, import_react13.useState)(emptyBlockSelection);
15443
+ const [historyTick, setHistoryTick] = (0, import_react13.useState)(0);
14924
15444
  const digitForm = digitFormProp ?? digitFormState ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
14925
- const historyRef = (0, import_react11.useRef)(createDocument2History());
14926
- const documentRef = (0, import_react11.useRef)(documentNode);
14927
- const textSnapshotArmedRef = (0, import_react11.useRef)(false);
14928
- const textDebounceRef = (0, import_react11.useRef)(null);
14929
- const widgetRef = (0, import_react11.useRef)(null);
14930
- const articleMetaPanelRef = (0, import_react11.useRef)(null);
14931
- const pendingFocusRef = (0, import_react11.useRef)(null);
15445
+ const historyRef = (0, import_react13.useRef)(createDocument2History());
15446
+ const documentRef = (0, import_react13.useRef)(documentNode);
15447
+ const textSnapshotArmedRef = (0, import_react13.useRef)(false);
15448
+ const textDebounceRef = (0, import_react13.useRef)(null);
15449
+ const widgetRef = (0, import_react13.useRef)(null);
15450
+ const articleMetaPanelRef = (0, import_react13.useRef)(null);
15451
+ const pendingFocusRef = (0, import_react13.useRef)(null);
14932
15452
  documentRef.current = documentNode;
14933
15453
  const latex = document2Latex(documentNode);
14934
- const documentLabels = (0, import_react11.useMemo)(() => collectDocument2Labels(documentNode), [documentNode]);
14935
- const preview = (0, import_react11.useMemo)(
15454
+ const documentLabels = (0, import_react13.useMemo)(() => collectDocument2Labels(documentNode), [documentNode]);
15455
+ const preview = (0, import_react13.useMemo)(
14936
15456
  () => document2Preview(documentNode, mathOutput, equationSide, {
14937
15457
  documentDirection,
14938
15458
  digitForm,
@@ -14940,7 +15460,7 @@ function ButexDocumentEditor2({
14940
15460
  }),
14941
15461
  [documentNode, documentDirection, digitForm, equationSide, mathOutput, uiLocale]
14942
15462
  );
14943
- const debugEnabled = (0, import_react11.useMemo)(() => {
15463
+ const debugEnabled = (0, import_react13.useMemo)(() => {
14944
15464
  if (debug) {
14945
15465
  return true;
14946
15466
  }
@@ -14949,8 +15469,8 @@ function ButexDocumentEditor2({
14949
15469
  }
14950
15470
  return new URLSearchParams(window.location.search).get("debug") === "1";
14951
15471
  }, [debug]);
14952
- const canUndo = (0, import_react11.useMemo)(() => document2HistoryCanUndo(historyRef.current), [historyTick, documentNode]);
14953
- const canRedo = (0, import_react11.useMemo)(() => document2HistoryCanRedo(historyRef.current), [historyTick, documentNode]);
15472
+ const canUndo = (0, import_react13.useMemo)(() => document2HistoryCanUndo(historyRef.current), [historyTick, documentNode]);
15473
+ const canRedo = (0, import_react13.useMemo)(() => document2HistoryCanRedo(historyRef.current), [historyTick, documentNode]);
14954
15474
  const blockSelection = normalizeBlockSelection(blockSelectionState.selection, documentNode.blocks.length);
14955
15475
  const selectionCount = blockSelection ? blockSelection.to - blockSelection.from + 1 : 0;
14956
15476
  const canMoveSelectionUp = Boolean(blockSelection && blockSelection.from > 0);
@@ -14992,15 +15512,15 @@ function ButexDocumentEditor2({
14992
15512
  applyDocument(removeDocument2BlockRange(documentRef.current, selection.from, selection.to), "immediate");
14993
15513
  clearBlockSelection();
14994
15514
  }
14995
- (0, import_react11.useEffect)(() => {
15515
+ (0, import_react13.useEffect)(() => {
14996
15516
  injectBuTeXDocument2Styles();
14997
15517
  }, []);
14998
- (0, import_react11.useEffect)(() => {
15518
+ (0, import_react13.useEffect)(() => {
14999
15519
  if (!editableEquations || previewOnly) {
15000
15520
  setSelectedMath(null);
15001
15521
  }
15002
15522
  }, [editableEquations, previewOnly]);
15003
- (0, import_react11.useEffect)(() => {
15523
+ (0, import_react13.useEffect)(() => {
15004
15524
  const next = resolveInitialDocument2(initialDocument, uiLocale, documentMeta);
15005
15525
  setDocumentNode(next.document);
15006
15526
  setError(next.error);
@@ -15009,13 +15529,13 @@ function ButexDocumentEditor2({
15009
15529
  historyRef.current = createDocument2History();
15010
15530
  setHistoryTick((tick) => tick + 1);
15011
15531
  }, [initialDocument, documentMeta, uiLocale]);
15012
- (0, import_react11.useEffect)(() => {
15532
+ (0, import_react13.useEffect)(() => {
15013
15533
  onDocumentChange?.(documentNode);
15014
15534
  }, [documentNode, onDocumentChange]);
15015
- (0, import_react11.useEffect)(() => {
15535
+ (0, import_react13.useEffect)(() => {
15016
15536
  onLatexChange?.(latex);
15017
15537
  }, [latex, onLatexChange]);
15018
- (0, import_react11.useEffect)(() => {
15538
+ (0, import_react13.useEffect)(() => {
15019
15539
  const pending = pendingFocusRef.current;
15020
15540
  const root = widgetRef.current;
15021
15541
  if (!pending || !root) {
@@ -15055,10 +15575,10 @@ function ButexDocumentEditor2({
15055
15575
  textarea.setSelectionRange(safeOffset, safeOffset);
15056
15576
  });
15057
15577
  }, [documentNode]);
15058
- const bumpHistoryUi = (0, import_react11.useCallback)(() => {
15578
+ const bumpHistoryUi = (0, import_react13.useCallback)(() => {
15059
15579
  setHistoryTick((tick) => tick + 1);
15060
15580
  }, []);
15061
- const applyDocument = (0, import_react11.useCallback)(
15581
+ const applyDocument = (0, import_react13.useCallback)(
15062
15582
  (next, mode = "immediate") => {
15063
15583
  if (mode === "immediate") {
15064
15584
  pushDocument2Snapshot(historyRef.current, documentRef.current);
@@ -15080,7 +15600,7 @@ function ButexDocumentEditor2({
15080
15600
  },
15081
15601
  [bumpHistoryUi]
15082
15602
  );
15083
- const afterBlockId = (0, import_react11.useCallback)(() => resolveInsertAfterBlockId(documentRef.current, editorFocus), [editorFocus]);
15603
+ const afterBlockId = (0, import_react13.useCallback)(() => resolveInsertAfterBlockId(documentRef.current, editorFocus), [editorFocus]);
15084
15604
  function undoDocument() {
15085
15605
  const restored = restoreDocument2Undo(historyRef.current, documentRef.current);
15086
15606
  if (!restored) {
@@ -15131,7 +15651,7 @@ function ButexDocumentEditor2({
15131
15651
  function openAllBlocks() {
15132
15652
  setCollapsedBlockIds(/* @__PURE__ */ new Set());
15133
15653
  }
15134
- (0, import_react11.useEffect)(() => {
15654
+ (0, import_react13.useEffect)(() => {
15135
15655
  const root = widgetRef.current;
15136
15656
  if (!root) {
15137
15657
  return;
@@ -15611,6 +16131,7 @@ function ButexDocumentEditor2({
15611
16131
  output: mathOutput,
15612
16132
  documentDirection,
15613
16133
  uiLocale,
16134
+ digitForm,
15614
16135
  resolveImageUrl
15615
16136
  }
15616
16137
  )
@@ -15640,6 +16161,9 @@ function ButexDocumentEditor2({
15640
16161
  uiLocale,
15641
16162
  labelEnabled: selectedMath.labelEnabled,
15642
16163
  label: selectedMath.label,
16164
+ labels: documentLabels,
16165
+ references: documentNode.references,
16166
+ ownerId: selectedMath.tokenId ?? void 0,
15643
16167
  onLabelEnabledChange: (enabled) => setSelectedMath((current) => current ? { ...current, labelEnabled: enabled } : current),
15644
16168
  onLabelChange: (nextLabel) => setSelectedMath((current) => current ? { ...current, label: nextLabel } : current),
15645
16169
  onMathModeChange: (mode) => setSelectedMath((current) => current ? { ...current, mathMode: mode } : current),
@@ -15655,6 +16179,7 @@ function ButexDocumentEditor2({
15655
16179
  references: documentNode.references,
15656
16180
  initialKeys: citePicker?.keys ?? [],
15657
16181
  uiLocale,
16182
+ digitForm,
15658
16183
  onClose: () => setCitePicker(null),
15659
16184
  onConfirm: confirmCiteKeys,
15660
16185
  onManageReferences: () => {
@@ -15671,6 +16196,7 @@ function ButexDocumentEditor2({
15671
16196
  initialKeys: refPicker?.keys ?? [],
15672
16197
  initialRefCommand: refPicker?.refCommand ?? "ref",
15673
16198
  uiLocale,
16199
+ digitForm,
15674
16200
  onClose: () => setRefPicker(null),
15675
16201
  onConfirm: confirmRefKeys,
15676
16202
  onManageLabels: () => {
@@ -15684,7 +16210,9 @@ function ButexDocumentEditor2({
15684
16210
  {
15685
16211
  open: referencesOpen,
15686
16212
  references: documentNode.references,
16213
+ labels: documentLabels,
15687
16214
  uiLocale,
16215
+ digitForm,
15688
16216
  onClose: () => setReferencesOpen(false),
15689
16217
  onAdd: (partial) => applyDocument(addDocument2Reference(documentRef.current, partial), "immediate"),
15690
16218
  onUpdate: (referenceId, patch) => applyDocument(updateDocument2Reference(documentRef.current, referenceId, patch), "immediate"),
@@ -15697,7 +16225,9 @@ function ButexDocumentEditor2({
15697
16225
  {
15698
16226
  open: labelsOpen,
15699
16227
  labels: documentLabels,
16228
+ references: documentNode.references,
15700
16229
  uiLocale,
16230
+ digitForm,
15701
16231
  onClose: () => setLabelsOpen(false),
15702
16232
  onUpdateFloat: (ownerId, kind, patch) => applyDocument(
15703
16233
  kind === "fig" ? updateDocument2ImageMeta(documentRef.current, ownerId, patch) : updateDocument2TableMeta(documentRef.current, ownerId, patch),