@nuucognition/ncm-ui 0.1.1-beta.0 → 0.1.1-beta.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.
Files changed (39) hide show
  1. package/dist/blocks/admonition/index.js +118 -46
  2. package/dist/blocks/aside/index.js +118 -46
  3. package/dist/blocks/blockquote/index.d.ts +7 -5
  4. package/dist/blocks/blockquote/index.js +1218 -36
  5. package/dist/blocks/chart/index.js +2 -1
  6. package/dist/blocks/container/index.js +72 -31
  7. package/dist/blocks/custom-code/index.js +1 -1
  8. package/dist/blocks/dataview/index.js +2 -1
  9. package/dist/blocks/definition/index.js +117 -45
  10. package/dist/blocks/embedding/index.js +72 -31
  11. package/dist/blocks/figure/index.js +72 -31
  12. package/dist/blocks/footnote/index.js +118 -46
  13. package/dist/blocks/header/index.js +72 -31
  14. package/dist/blocks/html/index.js +2 -1
  15. package/dist/blocks/index.js +118 -46
  16. package/dist/blocks/latex/index.js +2 -2
  17. package/dist/blocks/list/index.js +72 -31
  18. package/dist/blocks/math/index.js +3 -2
  19. package/dist/blocks/mermaid/index.js +2 -1
  20. package/dist/blocks/paragraph/index.js +72 -31
  21. package/dist/blocks/spoiler/index.js +118 -46
  22. package/dist/blocks/table/index.js +73 -32
  23. package/dist/blocks/task-list/index.js +72 -31
  24. package/dist/components/index.js +157 -65
  25. package/dist/components/ncm-block.js +118 -46
  26. package/dist/components/ncm-document.js +157 -65
  27. package/dist/context/index.d.ts +1 -1
  28. package/dist/context/index.js +119 -44
  29. package/dist/hooks/index.js +118 -46
  30. package/dist/hooks/use-block-renderer.js +118 -46
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +164 -58
  33. package/dist/inline/index.d.ts +2 -3
  34. package/dist/inline/index.js +72 -31
  35. package/dist/lib/defaults.js +118 -46
  36. package/dist/references-BM-lvGrq.d.ts +99 -0
  37. package/dist/styles/nuu.css +39 -16
  38. package/package.json +3 -4
  39. package/dist/references-BYW5pnj_.d.ts +0 -63
@@ -3,8 +3,8 @@ import { createContext, useMemo, useContext, createElement, useRef, Component, u
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
+ import { serializeInlineContent, isTypedNestedList, parseNcm } from '@nuucognition/ncm';
6
7
  import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
7
- import { serializeInlineContent, isTypedNestedList } from '@nuucognition/ncm';
8
8
 
9
9
  function blockKey(block) {
10
10
  return block.stableId ? `${block.id}:${block.stableId}` : block.id;
@@ -153,6 +153,52 @@ function tryParseInlineRef(input) {
153
153
  }
154
154
  return { token: { type: "inline_ref", kind: "footnote", content: inner.trim() }, length };
155
155
  }
156
+ function runLength(input, index, char) {
157
+ let end = index;
158
+ while (end < input.length && input[end] === char) end++;
159
+ return end - index;
160
+ }
161
+ function tryParseEmphasis(input) {
162
+ const char = input[0];
163
+ if (char !== "*" && char !== "_") return null;
164
+ const open = Math.min(3, runLength(input, 0, char));
165
+ const need = open;
166
+ let i = open;
167
+ while (i < input.length) {
168
+ const ch = input[i];
169
+ if (ch === "`") {
170
+ const close = input.indexOf("`", i + 1);
171
+ if (close === -1) break;
172
+ i = close + 1;
173
+ continue;
174
+ }
175
+ if (ch !== char) {
176
+ i++;
177
+ continue;
178
+ }
179
+ const run = runLength(input, i, char);
180
+ const closes = need === 1 ? run % 2 === 1 : run >= need;
181
+ if (!closes) {
182
+ i += run;
183
+ continue;
184
+ }
185
+ const extra = run - need;
186
+ const inner = input.slice(open, i + extra);
187
+ if (inner.length === 0) return null;
188
+ const length = i + run;
189
+ const children = parseInline(inner);
190
+ let token;
191
+ if (need === 3) {
192
+ token = { type: "bold", children: [{ type: "italic", children }] };
193
+ } else if (need === 2) {
194
+ token = { type: "bold", children };
195
+ } else {
196
+ token = { type: "italic", children };
197
+ }
198
+ return { token, length };
199
+ }
200
+ return null;
201
+ }
156
202
  function parseInline(content) {
157
203
  if (!content) return [];
158
204
  const tokens = [];
@@ -224,17 +270,11 @@ function parseInline(content) {
224
270
  remaining = remaining.slice(linkMatch[0].length);
225
271
  continue;
226
272
  }
227
- const boldMatch = remaining.match(/^\*\*(.+?)\*\*|^__(.+?)__/);
228
- if (boldMatch) {
229
- const innerContent = boldMatch[1] ?? boldMatch[2];
230
- if (innerContent !== void 0) {
231
- tokens.push({
232
- type: "bold",
233
- children: parseInline(innerContent)
234
- });
235
- remaining = remaining.slice(boldMatch[0].length);
236
- continue;
237
- }
273
+ const emphasis = tryParseEmphasis(remaining);
274
+ if (emphasis) {
275
+ tokens.push(emphasis.token);
276
+ remaining = remaining.slice(emphasis.length);
277
+ continue;
238
278
  }
239
279
  const strikeMatch = remaining.match(/^~~(.+?)~~/);
240
280
  if (strikeMatch && strikeMatch[1] !== void 0) {
@@ -245,18 +285,6 @@ function parseInline(content) {
245
285
  remaining = remaining.slice(strikeMatch[0].length);
246
286
  continue;
247
287
  }
248
- const italicMatch = remaining.match(/^\*([^*]+)\*|^_([^_]+)_/);
249
- if (italicMatch) {
250
- const innerContent = italicMatch[1] ?? italicMatch[2];
251
- if (innerContent !== void 0) {
252
- tokens.push({
253
- type: "italic",
254
- children: parseInline(innerContent)
255
- });
256
- remaining = remaining.slice(italicMatch[0].length);
257
- continue;
258
- }
259
- }
260
288
  const nextSpecial = findNextSpecialChar(remaining);
261
289
  if (nextSpecial > 0) {
262
290
  tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
@@ -407,48 +435,81 @@ function collectListStrings(items) {
407
435
  }
408
436
  return out;
409
437
  }
410
- function countInlineRefs(tokens, acc) {
438
+ function normalizeReferenceContent(content) {
439
+ return content.replace(/\s+/g, " ").trim().toLowerCase();
440
+ }
441
+ var BIBLIOGRAPHY_ENTRY_RE = /^\s*\[(\d+)\]\s+([\s\S]+?)\s*$/;
442
+ function collectBibliography(blocks) {
443
+ const entries = /* @__PURE__ */ new Map();
444
+ for (const block of blocks) {
445
+ if (block.type !== "paragraph") continue;
446
+ const content = block.content ?? "";
447
+ const match = BIBLIOGRAPHY_ENTRY_RE.exec(content);
448
+ if (!match || !match[1] || !match[2]) continue;
449
+ const key = normalizeReferenceContent(match[2]);
450
+ if (key && !entries.has(key)) entries.set(key, Number(match[1]));
451
+ }
452
+ return entries;
453
+ }
454
+ function walkInlineRefs(tokens, visit) {
411
455
  for (const token of tokens) {
412
456
  if (token.type === "inline_ref") {
413
- acc[token.kind] += 1;
457
+ visit(token);
414
458
  } else if ("children" in token) {
415
- countInlineRefs(token.children, acc);
459
+ walkInlineRefs(token.children, visit);
416
460
  }
417
461
  }
418
462
  }
419
- function countBlock(block) {
420
- const acc = { ref: 0, footnote: 0 };
421
- for (const str of collectInlineStrings(block)) {
422
- if (str) countInlineRefs(parseInline(str), acc);
423
- }
424
- return acc;
425
- }
426
- function computeReferenceBases(blocks) {
427
- const bases = /* @__PURE__ */ new Map();
428
- const acc = { ref: 0, footnote: 0 };
463
+ function computeReferenceNumbering(blocks) {
464
+ const bibliography = collectBibliography(blocks);
465
+ let maxBibliography = 0;
466
+ for (const n of bibliography.values()) maxBibliography = Math.max(maxBibliography, n);
467
+ const numbering = { ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() };
468
+ let nextRef = maxBibliography;
469
+ let nextFootnote = 0;
429
470
  for (const block of blocks) {
430
- bases.set(block.id, { ...acc });
431
- const counts = countBlock(block);
432
- acc.ref += counts.ref;
433
- acc.footnote += counts.footnote;
471
+ for (const str of collectInlineStrings(block)) {
472
+ if (!str) continue;
473
+ walkInlineRefs(parseInline(str), (token) => {
474
+ const key = normalizeReferenceContent(token.content);
475
+ const map = numbering[token.kind];
476
+ if (map.has(key)) return;
477
+ if (token.kind === "ref") {
478
+ const fromBibliography = bibliography.get(key);
479
+ map.set(key, fromBibliography ?? ++nextRef);
480
+ } else {
481
+ map.set(key, ++nextFootnote);
482
+ }
483
+ });
484
+ }
434
485
  }
435
- return bases;
486
+ return numbering;
436
487
  }
437
- var ReferenceBasesContext = createContext(null);
488
+ var ReferenceNumberingContext = createContext(null);
438
489
  var BlockReferenceScopeContext = createContext(null);
439
490
  function NcmReferencesProvider({ blocks, children }) {
440
- const bases = useMemo(() => computeReferenceBases(blocks), [blocks]);
441
- return /* @__PURE__ */ jsx(ReferenceBasesContext.Provider, { value: bases, children });
491
+ const numbering = useMemo(() => computeReferenceNumbering(blocks), [blocks]);
492
+ return /* @__PURE__ */ jsx(ReferenceNumberingContext.Provider, { value: numbering, children });
442
493
  }
443
- function BlockReferenceScope({ blockId, children }) {
444
- const bases = useContext(ReferenceBasesContext);
445
- const base = (blockId ? bases?.get(blockId) : void 0) ?? { ref: 0, footnote: 0 };
494
+ function BlockReferenceScope({ children }) {
495
+ const numbering = useContext(ReferenceNumberingContext);
496
+ const local = useRef({ ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() });
446
497
  const counter = useRef({ ref: 0, footnote: 0 });
447
- counter.current = { ref: 0, footnote: 0 };
448
498
  const value = {
499
+ numberFor(kind, content) {
500
+ const key = normalizeReferenceContent(content);
501
+ const fromDocument = numbering?.[kind].get(key);
502
+ if (fromDocument !== void 0) return fromDocument;
503
+ const map = local.current[kind];
504
+ const existing = map.get(key);
505
+ if (existing !== void 0) return existing;
506
+ counter.current[kind] += 1;
507
+ map.set(key, counter.current[kind]);
508
+ return counter.current[kind];
509
+ },
449
510
  next(kind) {
450
511
  counter.current[kind] += 1;
451
- return base[kind] + counter.current[kind];
512
+ return counter.current[kind];
452
513
  }
453
514
  };
454
515
  return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value, children });
@@ -456,7 +517,7 @@ function BlockReferenceScope({ blockId, children }) {
456
517
  function useBlockReferenceScope() {
457
518
  return useContext(BlockReferenceScopeContext);
458
519
  }
459
- var INERT_SCOPE = { next: () => 0 };
520
+ var INERT_SCOPE = { numberFor: () => 0, next: () => 0 };
460
521
  function InertReferenceScope({ children }) {
461
522
  return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value: INERT_SCOPE, children });
462
523
  }
@@ -747,7 +808,7 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
747
808
  );
748
809
  }
749
810
  case "inline_ref": {
750
- const number = refScope?.next(token.kind) ?? 0;
811
+ const number = refScope?.numberFor(token.kind, token.content) ?? 0;
751
812
  return /* @__PURE__ */ jsx(ReferenceMarker, { kind: token.kind, number, children: token.content ? /* @__PURE__ */ jsx(InertReferenceScope, { children: /* @__PURE__ */ jsx(InlineContent, { content: token.content, disableBionic: true, disableBeeline: true }) }) : null });
752
813
  }
753
814
  default:
@@ -813,8 +874,32 @@ function renderReadingText(content, opts) {
813
874
  if (cursor < content.length) pieces.push(content.slice(cursor));
814
875
  return /* @__PURE__ */ jsx(Fragment, { children: pieces });
815
876
  }
877
+ function quoteBlocks(block) {
878
+ try {
879
+ const doc = parseNcm(block.content, {
880
+ preset: "ncm-full",
881
+ allowMissingFrontmatter: true,
882
+ // Attribution off, as the NUU Editor's bridge keeps it: the promoter's
883
+ // trigger is any last quote line starting with `-`, so a nested quote
884
+ // ending in a list item would lose that item to a `— Author` line.
885
+ blockOptions: { extensions: { attribution: false } }
886
+ });
887
+ const blocks = doc.blocks ?? [];
888
+ if (blocks.length === 0 || blocks.some((child) => child.type === "frontmatter")) {
889
+ return null;
890
+ }
891
+ return blocks.map((child, index) => ({ ...child, id: `${block.id}.${index + 1}`, stableId: void 0 }));
892
+ } catch {
893
+ return null;
894
+ }
895
+ }
896
+ function QuotedLines({ content }) {
897
+ const lines = content.split("\n");
898
+ return /* @__PURE__ */ jsx(Fragment, { children: lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: line.trim().length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: line }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" }) }, index)) });
899
+ }
816
900
  function BlockquoteBlock({ block, className }) {
817
- const lines = block.content.split("\n");
901
+ const multiline = block.content.includes("\n");
902
+ const blocks = useMemo(() => multiline ? quoteBlocks(block) : null, [block, multiline]);
818
903
  return /* @__PURE__ */ jsx(
819
904
  "blockquote",
820
905
  {
@@ -824,7 +909,9 @@ function BlockquoteBlock({ block, className }) {
824
909
  "data-block-id": block.id,
825
910
  "data-ncm-blockquote": "",
826
911
  className,
827
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: line.trim().length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: line }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" }) }, index))
912
+ children: !multiline ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : blocks === null ? /* @__PURE__ */ jsx(QuotedLines, { content: block.content }) : blocks.map(
913
+ (child) => child.type === "paragraph" ? /* @__PURE__ */ jsx(QuotedLines, { content: child.content ?? "" }, blockKey(child)) : /* @__PURE__ */ jsx(NcmBlock, { block: child }, blockKey(child))
914
+ )
828
915
  }
829
916
  );
830
917
  }
@@ -839,7 +926,8 @@ function ChartBlock({ block, className }) {
839
926
  "data-ncm-chart": "",
840
927
  "data-ncm-chart-type": block.chartType ?? "unknown",
841
928
  className: cn(
842
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
929
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
930
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
843
931
  className
844
932
  ),
845
933
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1019,7 +1107,8 @@ function DataviewBlock({ block, className }) {
1019
1107
  "data-ncm-dataview": "",
1020
1108
  "data-ncm-query-type": block.queryType,
1021
1109
  className: cn(
1022
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1110
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
1111
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1023
1112
  className
1024
1113
  ),
1025
1114
  children: /* @__PURE__ */ jsx("code", { children: block.query })
@@ -1358,7 +1447,8 @@ function HtmlBlock({ block, className }) {
1358
1447
  "data-block-id": block.id,
1359
1448
  "data-ncm-html": "",
1360
1449
  className: cn(
1361
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1450
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
1451
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1362
1452
  className
1363
1453
  ),
1364
1454
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1396,7 +1486,7 @@ function LatexDisplayBlock({ block, className }) {
1396
1486
  "data-ncm-type": block.type,
1397
1487
  "data-block-id": block.id,
1398
1488
  "data-ncm-latex-display": "",
1399
- className: cn("overflow-x-auto", className),
1489
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1400
1490
  dangerouslySetInnerHTML: { __html: html }
1401
1491
  }
1402
1492
  );
@@ -1411,7 +1501,7 @@ function LatexDisplayBlock({ block, className }) {
1411
1501
  "data-ncm-type": block.type,
1412
1502
  "data-block-id": block.id,
1413
1503
  "data-ncm-latex-display": "",
1414
- className: cn("overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
1504
+ className: cn("overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
1415
1505
  children: /* @__PURE__ */ jsx("code", { children: block.content })
1416
1506
  }
1417
1507
  );
@@ -1531,7 +1621,7 @@ function MathBlock({ block, className }) {
1531
1621
  "data-ncm-type": block.type,
1532
1622
  "data-block-id": block.id,
1533
1623
  "data-ncm-math": "",
1534
- className: cn("overflow-x-auto", className),
1624
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1535
1625
  dangerouslySetInnerHTML: { __html: html }
1536
1626
  }
1537
1627
  );
@@ -1547,7 +1637,8 @@ function MathBlock({ block, className }) {
1547
1637
  "data-block-id": block.id,
1548
1638
  "data-ncm-math": "",
1549
1639
  className: cn(
1550
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1640
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
1641
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1551
1642
  className
1552
1643
  ),
1553
1644
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1565,7 +1656,8 @@ function MermaidBlock({ block, className }) {
1565
1656
  "data-ncm-mermaid": "",
1566
1657
  "data-ncm-diagram-type": block.diagramType,
1567
1658
  className: cn(
1568
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1659
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
1660
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1569
1661
  className
1570
1662
  ),
1571
1663
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1626,7 +1718,7 @@ function TableBlock({ block, className }) {
1626
1718
  "data-ncm-type": block.type,
1627
1719
  "data-block-id": block.id,
1628
1720
  "data-ncm-table": "",
1629
- className: cn("w-full overflow-x-auto", className),
1721
+ className: cn("w-full overflow-x-auto overflow-y-hidden", className),
1630
1722
  children: /* @__PURE__ */ jsxs("table", { role: "table", "data-ncm-table-element": "", children: [
1631
1723
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { "data-ncm-table-row": "", children: block.headers.map((header, index) => /* @__PURE__ */ jsx("th", { "data-ncm-table-header": "", children: /* @__PURE__ */ jsx(InlineContent, { content: header }) }, index)) }) }),
1632
1724
  /* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => {
@@ -1712,7 +1804,7 @@ function FallbackBlock({ block, className }) {
1712
1804
  "data-block-id": block.id,
1713
1805
  "data-ncm-fallback": "",
1714
1806
  className: cn(
1715
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1807
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1716
1808
  className
1717
1809
  )
1718
1810
  },
@@ -1768,7 +1860,7 @@ function CustomCodeBlock({ block, className }) {
1768
1860
  "data-block-id": block.id,
1769
1861
  "data-ncm-custom-code": "",
1770
1862
  "data-ncm-language": block.language,
1771
- className: cn("overflow-x-auto", className),
1863
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1772
1864
  children: [
1773
1865
  /* @__PURE__ */ jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: block.language }),
1774
1866
  /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: block.content }) })
@@ -1,5 +1,5 @@
1
1
  export { C as CodeConfig, E as EmbeddingsConfig, I as ImageErrorProps, a as InlineConfig, N as NcmConfig, b as NcmProvider, c as NcmProviderProps, u as useNcmConfig } from '../use-ncm-config-CnntcShj.js';
2
- export { B as BlockReferenceScope, a as BlockReferenceScopeProps, b as BlockReferenceScopeValue, I as InertReferenceScope, N as NcmReferencesProvider, c as NcmReferencesProviderProps, R as ReferenceCounts, d as ReferenceKind, e as computeReferenceBases, u as useBlockReferenceScope } from '../references-BYW5pnj_.js';
2
+ export { B as BlockReferenceScope, a as BlockReferenceScopeProps, b as BlockReferenceScopeValue, I as InertReferenceScope, N as NcmReferencesProvider, c as NcmReferencesProviderProps, R as ReferenceCounts, d as ReferenceKind, e as ReferenceNumbering, f as collectBibliography, g as computeReferenceBases, h as computeReferenceNumbering, n as normalizeReferenceContent, u as useBlockReferenceScope } from '../references-BM-lvGrq.js';
3
3
  import 'react';
4
4
  import '@nuucognition/mesh-core';
5
5
  import '@nuucognition/ncm';
@@ -53,6 +53,52 @@ function tryParseInlineRef(input) {
53
53
  }
54
54
  return { token: { type: "inline_ref", kind: "footnote", content: inner.trim() }, length };
55
55
  }
56
+ function runLength(input, index, char) {
57
+ let end = index;
58
+ while (end < input.length && input[end] === char) end++;
59
+ return end - index;
60
+ }
61
+ function tryParseEmphasis(input) {
62
+ const char = input[0];
63
+ if (char !== "*" && char !== "_") return null;
64
+ const open = Math.min(3, runLength(input, 0, char));
65
+ const need = open;
66
+ let i = open;
67
+ while (i < input.length) {
68
+ const ch = input[i];
69
+ if (ch === "`") {
70
+ const close = input.indexOf("`", i + 1);
71
+ if (close === -1) break;
72
+ i = close + 1;
73
+ continue;
74
+ }
75
+ if (ch !== char) {
76
+ i++;
77
+ continue;
78
+ }
79
+ const run = runLength(input, i, char);
80
+ const closes = need === 1 ? run % 2 === 1 : run >= need;
81
+ if (!closes) {
82
+ i += run;
83
+ continue;
84
+ }
85
+ const extra = run - need;
86
+ const inner = input.slice(open, i + extra);
87
+ if (inner.length === 0) return null;
88
+ const length = i + run;
89
+ const children = parseInline(inner);
90
+ let token;
91
+ if (need === 3) {
92
+ token = { type: "bold", children: [{ type: "italic", children }] };
93
+ } else if (need === 2) {
94
+ token = { type: "bold", children };
95
+ } else {
96
+ token = { type: "italic", children };
97
+ }
98
+ return { token, length };
99
+ }
100
+ return null;
101
+ }
56
102
  function parseInline(content) {
57
103
  if (!content) return [];
58
104
  const tokens = [];
@@ -124,17 +170,11 @@ function parseInline(content) {
124
170
  remaining = remaining.slice(linkMatch[0].length);
125
171
  continue;
126
172
  }
127
- const boldMatch = remaining.match(/^\*\*(.+?)\*\*|^__(.+?)__/);
128
- if (boldMatch) {
129
- const innerContent = boldMatch[1] ?? boldMatch[2];
130
- if (innerContent !== void 0) {
131
- tokens.push({
132
- type: "bold",
133
- children: parseInline(innerContent)
134
- });
135
- remaining = remaining.slice(boldMatch[0].length);
136
- continue;
137
- }
173
+ const emphasis = tryParseEmphasis(remaining);
174
+ if (emphasis) {
175
+ tokens.push(emphasis.token);
176
+ remaining = remaining.slice(emphasis.length);
177
+ continue;
138
178
  }
139
179
  const strikeMatch = remaining.match(/^~~(.+?)~~/);
140
180
  if (strikeMatch && strikeMatch[1] !== void 0) {
@@ -145,18 +185,6 @@ function parseInline(content) {
145
185
  remaining = remaining.slice(strikeMatch[0].length);
146
186
  continue;
147
187
  }
148
- const italicMatch = remaining.match(/^\*([^*]+)\*|^_([^_]+)_/);
149
- if (italicMatch) {
150
- const innerContent = italicMatch[1] ?? italicMatch[2];
151
- if (innerContent !== void 0) {
152
- tokens.push({
153
- type: "italic",
154
- children: parseInline(innerContent)
155
- });
156
- remaining = remaining.slice(italicMatch[0].length);
157
- continue;
158
- }
159
- }
160
188
  const nextSpecial = findNextSpecialChar(remaining);
161
189
  if (nextSpecial > 0) {
162
190
  tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
@@ -227,48 +255,95 @@ function collectListStrings(items) {
227
255
  }
228
256
  return out;
229
257
  }
230
- function countInlineRefs(tokens, acc) {
258
+ function normalizeReferenceContent(content) {
259
+ return content.replace(/\s+/g, " ").trim().toLowerCase();
260
+ }
261
+ var BIBLIOGRAPHY_ENTRY_RE = /^\s*\[(\d+)\]\s+([\s\S]+?)\s*$/;
262
+ function collectBibliography(blocks) {
263
+ const entries = /* @__PURE__ */ new Map();
264
+ for (const block of blocks) {
265
+ if (block.type !== "paragraph") continue;
266
+ const content = block.content ?? "";
267
+ const match = BIBLIOGRAPHY_ENTRY_RE.exec(content);
268
+ if (!match || !match[1] || !match[2]) continue;
269
+ const key = normalizeReferenceContent(match[2]);
270
+ if (key && !entries.has(key)) entries.set(key, Number(match[1]));
271
+ }
272
+ return entries;
273
+ }
274
+ function walkInlineRefs(tokens, visit) {
231
275
  for (const token of tokens) {
232
276
  if (token.type === "inline_ref") {
233
- acc[token.kind] += 1;
277
+ visit(token);
234
278
  } else if ("children" in token) {
235
- countInlineRefs(token.children, acc);
279
+ walkInlineRefs(token.children, visit);
236
280
  }
237
281
  }
238
282
  }
239
- function countBlock(block) {
240
- const acc = { ref: 0, footnote: 0 };
241
- for (const str of collectInlineStrings(block)) {
242
- if (str) countInlineRefs(parseInline(str), acc);
283
+ function computeReferenceNumbering(blocks) {
284
+ const bibliography = collectBibliography(blocks);
285
+ let maxBibliography = 0;
286
+ for (const n of bibliography.values()) maxBibliography = Math.max(maxBibliography, n);
287
+ const numbering = { ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() };
288
+ let nextRef = maxBibliography;
289
+ let nextFootnote = 0;
290
+ for (const block of blocks) {
291
+ for (const str of collectInlineStrings(block)) {
292
+ if (!str) continue;
293
+ walkInlineRefs(parseInline(str), (token) => {
294
+ const key = normalizeReferenceContent(token.content);
295
+ const map = numbering[token.kind];
296
+ if (map.has(key)) return;
297
+ if (token.kind === "ref") {
298
+ const fromBibliography = bibliography.get(key);
299
+ map.set(key, fromBibliography ?? ++nextRef);
300
+ } else {
301
+ map.set(key, ++nextFootnote);
302
+ }
303
+ });
304
+ }
243
305
  }
244
- return acc;
306
+ return numbering;
245
307
  }
246
308
  function computeReferenceBases(blocks) {
247
309
  const bases = /* @__PURE__ */ new Map();
248
310
  const acc = { ref: 0, footnote: 0 };
249
311
  for (const block of blocks) {
250
312
  bases.set(block.id, { ...acc });
251
- const counts = countBlock(block);
252
- acc.ref += counts.ref;
253
- acc.footnote += counts.footnote;
313
+ for (const str of collectInlineStrings(block)) {
314
+ if (!str) continue;
315
+ walkInlineRefs(parseInline(str), (token) => {
316
+ acc[token.kind] += 1;
317
+ });
318
+ }
254
319
  }
255
320
  return bases;
256
321
  }
257
- var ReferenceBasesContext = createContext(null);
322
+ var ReferenceNumberingContext = createContext(null);
258
323
  var BlockReferenceScopeContext = createContext(null);
259
324
  function NcmReferencesProvider({ blocks, children }) {
260
- const bases = useMemo(() => computeReferenceBases(blocks), [blocks]);
261
- return /* @__PURE__ */ jsx(ReferenceBasesContext.Provider, { value: bases, children });
325
+ const numbering = useMemo(() => computeReferenceNumbering(blocks), [blocks]);
326
+ return /* @__PURE__ */ jsx(ReferenceNumberingContext.Provider, { value: numbering, children });
262
327
  }
263
- function BlockReferenceScope({ blockId, children }) {
264
- const bases = useContext(ReferenceBasesContext);
265
- const base = (blockId ? bases?.get(blockId) : void 0) ?? { ref: 0, footnote: 0 };
328
+ function BlockReferenceScope({ children }) {
329
+ const numbering = useContext(ReferenceNumberingContext);
330
+ const local = useRef({ ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() });
266
331
  const counter = useRef({ ref: 0, footnote: 0 });
267
- counter.current = { ref: 0, footnote: 0 };
268
332
  const value = {
333
+ numberFor(kind, content) {
334
+ const key = normalizeReferenceContent(content);
335
+ const fromDocument = numbering?.[kind].get(key);
336
+ if (fromDocument !== void 0) return fromDocument;
337
+ const map = local.current[kind];
338
+ const existing = map.get(key);
339
+ if (existing !== void 0) return existing;
340
+ counter.current[kind] += 1;
341
+ map.set(key, counter.current[kind]);
342
+ return counter.current[kind];
343
+ },
269
344
  next(kind) {
270
345
  counter.current[kind] += 1;
271
- return base[kind] + counter.current[kind];
346
+ return counter.current[kind];
272
347
  }
273
348
  };
274
349
  return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value, children });
@@ -276,9 +351,9 @@ function BlockReferenceScope({ blockId, children }) {
276
351
  function useBlockReferenceScope() {
277
352
  return useContext(BlockReferenceScopeContext);
278
353
  }
279
- var INERT_SCOPE = { next: () => 0 };
354
+ var INERT_SCOPE = { numberFor: () => 0, next: () => 0 };
280
355
  function InertReferenceScope({ children }) {
281
356
  return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value: INERT_SCOPE, children });
282
357
  }
283
358
 
284
- export { BlockReferenceScope, InertReferenceScope, NcmProvider, NcmReferencesProvider, computeReferenceBases, useBlockReferenceScope, useNcmConfig };
359
+ export { BlockReferenceScope, InertReferenceScope, NcmProvider, NcmReferencesProvider, collectBibliography, computeReferenceBases, computeReferenceNumbering, normalizeReferenceContent, useBlockReferenceScope, useNcmConfig };