@nuucognition/ncm-ui 0.1.0-dev.1 → 0.1.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +90 -0
  2. package/dist/blocks/admonition/index.d.ts +2 -3
  3. package/dist/blocks/admonition/index.js +63 -12
  4. package/dist/blocks/aside/index.d.ts +2 -3
  5. package/dist/blocks/aside/index.js +63 -12
  6. package/dist/blocks/attribution/index.d.ts +2 -3
  7. package/dist/blocks/blockquote/index.d.ts +5 -4
  8. package/dist/blocks/blockquote/index.js +52 -7
  9. package/dist/blocks/chart/index.d.ts +2 -3
  10. package/dist/blocks/code/index.d.ts +2 -3
  11. package/dist/blocks/code/index.js +2 -2
  12. package/dist/blocks/container/index.d.ts +2 -3
  13. package/dist/blocks/container/index.js +50 -5
  14. package/dist/blocks/custom-code/index.d.ts +2 -3
  15. package/dist/blocks/dataview/index.d.ts +2 -3
  16. package/dist/blocks/definition/index.d.ts +2 -3
  17. package/dist/blocks/definition/index.js +63 -12
  18. package/dist/blocks/embed/index.d.ts +2 -3
  19. package/dist/blocks/embedding/index.d.ts +2 -3
  20. package/dist/blocks/embedding/index.js +50 -5
  21. package/dist/blocks/figure/index.d.ts +2 -3
  22. package/dist/blocks/figure/index.js +50 -5
  23. package/dist/blocks/footnote/index.d.ts +2 -3
  24. package/dist/blocks/footnote/index.js +63 -12
  25. package/dist/blocks/frontmatter/index.d.ts +2 -3
  26. package/dist/blocks/header/index.d.ts +2 -3
  27. package/dist/blocks/header/index.js +50 -5
  28. package/dist/blocks/horizontal-rule/index.d.ts +2 -3
  29. package/dist/blocks/html/index.d.ts +3 -4
  30. package/dist/blocks/index.d.ts +1 -2
  31. package/dist/blocks/index.js +63 -12
  32. package/dist/blocks/latex/index.d.ts +2 -3
  33. package/dist/blocks/link/index.d.ts +2 -3
  34. package/dist/blocks/list/index.d.ts +2 -3
  35. package/dist/blocks/list/index.js +57 -7
  36. package/dist/blocks/math/index.d.ts +2 -3
  37. package/dist/blocks/mermaid/index.d.ts +2 -3
  38. package/dist/blocks/page-breaker/index.d.ts +2 -3
  39. package/dist/blocks/paragraph/index.d.ts +2 -3
  40. package/dist/blocks/paragraph/index.js +50 -5
  41. package/dist/blocks/spoiler/index.d.ts +2 -3
  42. package/dist/blocks/spoiler/index.js +63 -12
  43. package/dist/blocks/table/index.d.ts +2 -3
  44. package/dist/blocks/table/index.js +50 -5
  45. package/dist/blocks/task-list/index.d.ts +2 -3
  46. package/dist/blocks/task-list/index.js +52 -6
  47. package/dist/components/index.d.ts +34 -4
  48. package/dist/components/index.js +101 -14
  49. package/dist/components/ncm-block.d.ts +2 -3
  50. package/dist/components/ncm-block.js +63 -12
  51. package/dist/components/ncm-document.d.ts +4 -4
  52. package/dist/components/ncm-document.js +63 -12
  53. package/dist/context/index.d.ts +2 -3
  54. package/dist/hooks/index.d.ts +1 -2
  55. package/dist/hooks/index.js +63 -12
  56. package/dist/hooks/use-block-renderer.js +63 -12
  57. package/dist/hooks/use-ncm-config.d.ts +1 -2
  58. package/dist/index.d.ts +3 -4
  59. package/dist/index.js +102 -15
  60. package/dist/inline/index.d.ts +4 -4
  61. package/dist/inline/index.js +51 -6
  62. package/dist/lib/defaults.js +63 -12
  63. package/dist/{references-Bs5wJybr.d.ts → references-BYW5pnj_.d.ts} +4 -4
  64. package/dist/styles/nuu.css +304 -42
  65. package/dist/styles/paper.css +62 -1
  66. package/dist/{use-ncm-config-D0doMYTH.d.ts → use-ncm-config-CnntcShj.d.ts} +55 -4
  67. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { createContext, useContext, useMemo, useRef, useId, useCallback, useState, createElement, useEffect, Component } from 'react';
2
+ import { createContext, useContext, useMemo, useRef, useId, useCallback, useState, useEffect, createElement, Component } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import { serializeInlineContent, sanitizeHtml, isTypedNestedList } from '@nuucognition/ncm';
4
+ import { serializeInlineContent, sanitizeHtml, isTypedNestedList, parseNcm } from '@nuucognition/ncm';
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
@@ -614,9 +614,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
614
614
  case "image": {
615
615
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
616
616
  return /* @__PURE__ */ jsx(
617
- "img",
617
+ EmbedImage,
618
618
  {
619
- "data-ncm-token": "image",
619
+ attrs: { "data-ncm-token": "image" },
620
+ target: token.src,
620
621
  src,
621
622
  alt: token.alt,
622
623
  title: token.title
@@ -650,10 +651,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
650
651
  }
651
652
  if (embedType === "image") {
652
653
  return /* @__PURE__ */ jsx(
653
- "img",
654
+ EmbedImage,
654
655
  {
655
- "data-ncm-token": "wiki_embed",
656
- "data-ncm-wikiembed-type": embedType,
656
+ attrs: {
657
+ "data-ncm-token": "wiki_embed",
658
+ "data-ncm-wikiembed-type": embedType
659
+ },
660
+ target: token.target,
657
661
  src: url,
658
662
  alt: token.display ?? token.target,
659
663
  className: config.embeddings?.imageClassName
@@ -684,6 +688,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
684
688
  }
685
689
  );
686
690
  }
691
+ const onEmbedClick = config.embeddings?.onEmbedClick;
692
+ if (onEmbedClick) {
693
+ const handleClick = (e) => {
694
+ onEmbedClick(token.target, result, e);
695
+ };
696
+ return /* @__PURE__ */ jsx(
697
+ "button",
698
+ {
699
+ type: "button",
700
+ "data-ncm-token": "wiki_embed",
701
+ "data-ncm-wikiembed-type": embedType,
702
+ onClick: handleClick,
703
+ children: token.display ?? token.target
704
+ }
705
+ );
706
+ }
687
707
  return /* @__PURE__ */ jsx(
688
708
  "a",
689
709
  {
@@ -702,6 +722,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
702
722
  return null;
703
723
  }
704
724
  }
725
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
726
+ const config = useNcmConfig();
727
+ const Fallback = config.embeddings?.renderImageError;
728
+ const [failedSrc, setFailedSrc] = useState(null);
729
+ useEffect(() => {
730
+ setFailedSrc(null);
731
+ }, [src]);
732
+ if (!Fallback) {
733
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
734
+ }
735
+ if (failedSrc === src) {
736
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
737
+ }
738
+ return /* @__PURE__ */ jsx(
739
+ "img",
740
+ {
741
+ ...attrs,
742
+ src,
743
+ alt,
744
+ title,
745
+ className,
746
+ onError: () => setFailedSrc(src)
747
+ }
748
+ );
749
+ }
705
750
  function renderReadingText(content, opts) {
706
751
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
707
752
  const { bionic = false, beeline = false } = opts;
@@ -743,7 +788,7 @@ function renderBeelineText(content) {
743
788
  return renderReadingText(content, { beeline: true });
744
789
  }
745
790
  function BlockquoteBlock({ block, className }) {
746
- const lines = block.content.split("\n").filter((line) => line.trim() !== "");
791
+ const lines = block.content.split("\n");
747
792
  return /* @__PURE__ */ jsx(
748
793
  "blockquote",
749
794
  {
@@ -753,7 +798,7 @@ function BlockquoteBlock({ block, className }) {
753
798
  "data-block-id": block.id,
754
799
  "data-ncm-blockquote": "",
755
800
  className,
756
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(InlineContent, { content: line }) }, index))
801
+ 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))
757
802
  }
758
803
  );
759
804
  }
@@ -893,7 +938,7 @@ function CodeBlock({ block, className }) {
893
938
  "data-ncm-language": block.language,
894
939
  className: cn("relative", className),
895
940
  children: [
896
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
941
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
897
942
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
898
943
  languageLabel
899
944
  ]
@@ -912,7 +957,7 @@ function CodeBlock({ block, className }) {
912
957
  "data-ncm-language": block.language,
913
958
  className: cn("relative", className),
914
959
  children: [
915
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
960
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
916
961
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
917
962
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
918
963
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -1387,10 +1432,12 @@ function LinkBlock({ block, className }) {
1387
1432
  function ListBlock({ block, className }) {
1388
1433
  const isOrdered = block.type === "list_ordered";
1389
1434
  const Tag = isOrdered ? "ol" : "ul";
1435
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1390
1436
  return /* @__PURE__ */ jsx(
1391
1437
  Tag,
1392
1438
  {
1393
1439
  role: "list",
1440
+ start,
1394
1441
  "data-ncm-block": block.id,
1395
1442
  "data-ncm-stable": block.stableId,
1396
1443
  "data-ncm-type": block.type,
@@ -1402,6 +1449,9 @@ function ListBlock({ block, className }) {
1402
1449
  }
1403
1450
  );
1404
1451
  }
1452
+ function ItemContent({ content }) {
1453
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1454
+ }
1405
1455
  function nestedItemIdKey(id) {
1406
1456
  if (!id) {
1407
1457
  return void 0;
@@ -1418,7 +1468,7 @@ function ListItems({ items, itemIds, ordered }) {
1418
1468
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1419
1469
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1420
1470
  if (typeof item === "string") {
1421
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1471
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1422
1472
  }
1423
1473
  if (isTypedNestedList(item)) {
1424
1474
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1428,7 +1478,7 @@ function ListItems({ items, itemIds, ordered }) {
1428
1478
  const content = typeof first === "string" ? first : "";
1429
1479
  const nestedContent = processNestedItems(rest, ordered);
1430
1480
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1431
- /* @__PURE__ */ jsx(InlineContent, { content }),
1481
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1432
1482
  nestedContent
1433
1483
  ] }, key);
1434
1484
  }
@@ -1587,6 +1637,7 @@ function TableBlock({ block, className }) {
1587
1637
  function TaskItems({ items }) {
1588
1638
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1589
1639
  const status = item.checked ? "Completed" : "Incomplete";
1640
+ const text = serializeInlineContent(item.content);
1590
1641
  return /* @__PURE__ */ jsxs(
1591
1642
  "li",
1592
1643
  {
@@ -1613,7 +1664,7 @@ function TaskItems({ items }) {
1613
1664
  ":",
1614
1665
  " "
1615
1666
  ] }),
1616
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1667
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1617
1668
  ] })
1618
1669
  ] }),
1619
1670
  item.children ? /* @__PURE__ */ jsx("ul", { role: "list", "data-ncm-list-nested": "", className: "ml-6 list-none", children: /* @__PURE__ */ jsx(TaskItems, { items: item.children.items }) }) : null
@@ -1865,6 +1916,42 @@ function NcmDocument({
1865
1916
  }
1866
1917
  );
1867
1918
  }
1919
+ function NcmBlockPreview({
1920
+ source,
1921
+ expectedType,
1922
+ theme = "nuu",
1923
+ config,
1924
+ className
1925
+ }) {
1926
+ const parsed = useMemo(() => {
1927
+ try {
1928
+ const doc = parseNcm(source, {
1929
+ preset: "ncm-full",
1930
+ allowMissingFrontmatter: true,
1931
+ rawHtml: true
1932
+ });
1933
+ const all = doc.blocks ?? [];
1934
+ const blocks = expectedType ? all.filter((b) => b.type === expectedType) : all;
1935
+ return { blocks, failed: blocks.length === 0 };
1936
+ } catch {
1937
+ return { blocks: [], failed: true };
1938
+ }
1939
+ }, [source, expectedType]);
1940
+ if (parsed.failed) {
1941
+ return /* @__PURE__ */ jsx(
1942
+ "div",
1943
+ {
1944
+ "data-ncm-parse-warning": "",
1945
+ "data-ncm-theme": theme,
1946
+ className: `ncm-theme-${theme}${className ? ` ${className}` : ""}`,
1947
+ role: "status",
1948
+ children: expectedType ? `Cannot be parsed as ${expectedType}` : "Cannot be parsed"
1949
+ }
1950
+ );
1951
+ }
1952
+ const document2 = /* @__PURE__ */ jsx(NcmDocument, { blocks: parsed.blocks, theme, className });
1953
+ return config ? /* @__PURE__ */ jsx(NcmProvider, { config, children: document2 }) : document2;
1954
+ }
1868
1955
 
1869
1956
  // src/hooks/use-block-renderer.ts
1870
1957
  function useBlockRenderer(blockType) {
@@ -1884,4 +1971,4 @@ function useCustomCodeRenderer(language) {
1884
1971
  return customCodeRenderers[language];
1885
1972
  }
1886
1973
 
1887
- export { AdmonitionBlock, AsideBlock, AttributionBlock, BlockReferenceScope, BlockShell, BlockquoteBlock, ChartBlock, ChildBlocks, CodeBlock, ContainerBlock, CustomCodeBlock, DataviewBlock, DefinitionBlock, EmbeddingBlock, FigureBlock, FootnoteBlock, FrontmatterBlock, HeaderBlock, HorizontalRuleBlock, HtmlBlock, InertReferenceScope, InlineContent, LatexDisplayBlock, LinkBlock, ListBlock, MathBlock, MermaidBlock, NcmBlock, NcmDocument, NcmProvider, NcmReferencesProvider, PageBreakerBlock, ParagraphBlock, ReferenceMarker, SanitizedHtmlBlock, SpoilerBlock, TableBlock, TaskListBlock, blockDataAttributes, blockKey, cn, computeReferenceBases, defaultRenderers, parseInline, renderBeelineText, renderBionicText, renderReadingText, useBlockReferenceScope, useBlockRenderer, useCustomCodeRenderer, useNcmConfig };
1974
+ export { AdmonitionBlock, AsideBlock, AttributionBlock, BlockReferenceScope, BlockShell, BlockquoteBlock, ChartBlock, ChildBlocks, CodeBlock, ContainerBlock, CustomCodeBlock, DataviewBlock, DefinitionBlock, EmbeddingBlock, FigureBlock, FootnoteBlock, FrontmatterBlock, HeaderBlock, HorizontalRuleBlock, HtmlBlock, InertReferenceScope, InlineContent, LatexDisplayBlock, LinkBlock, ListBlock, MathBlock, MermaidBlock, NcmBlock, NcmBlockPreview, NcmDocument, NcmProvider, NcmReferencesProvider, PageBreakerBlock, ParagraphBlock, ReferenceMarker, SanitizedHtmlBlock, SpoilerBlock, TableBlock, TaskListBlock, blockDataAttributes, blockKey, cn, computeReferenceBases, defaultRenderers, parseInline, renderBeelineText, renderBionicText, renderReadingText, useBlockReferenceScope, useBlockRenderer, useCustomCodeRenderer, useNcmConfig };
@@ -1,7 +1,7 @@
1
1
  import { b as InlineToken } from '../inline-DwUYUmk4.js';
2
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { d as ReferenceKind } from '../references-Bs5wJybr.js';
4
+ import { d as ReferenceKind } from '../references-BYW5pnj_.js';
5
5
  import '@nuucognition/ncm';
6
6
 
7
7
  /**
@@ -41,7 +41,7 @@ interface InlineContentProps {
41
41
  * Emits semantic HTML and `data-ncm-token` attributes; visual styling is owned
42
42
  * by the parent document's stylesheet (nuu.css or paper.css).
43
43
  */
44
- declare function InlineContent({ content, className, disableBionic, disableBeeline, }: InlineContentProps): react_jsx_runtime.JSX.Element;
44
+ declare function InlineContent({ content, className, disableBionic, disableBeeline, }: InlineContentProps): react.JSX.Element;
45
45
  interface RenderReadingTextOptions {
46
46
  bionic?: boolean;
47
47
  bionicRatio?: number;
@@ -103,6 +103,6 @@ interface ReferenceMarkerProps {
103
103
  * so it never spills outside the reading pane — measured lazily, only for the
104
104
  * marker actually being hovered/focused, so the common case stays JS-free.
105
105
  */
106
- declare function ReferenceMarker({ kind, number, children }: ReferenceMarkerProps): react_jsx_runtime.JSX.Element;
106
+ declare function ReferenceMarker({ kind, number, children }: ReferenceMarkerProps): react.JSX.Element;
107
107
 
108
108
  export { InlineContent, type InlineContentProps, ReferenceMarker, type ReferenceMarkerProps, type RenderReadingTextOptions, parseInline, renderBeelineText, renderBionicText, renderReadingText };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { createContext, useId, useRef, useCallback, useMemo, useContext, useState, useEffect } from 'react';
2
+ import { createContext, useId, useRef, useCallback, useMemo, useState, useEffect, useContext } from 'react';
3
3
  import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import '@nuucognition/ncm';
@@ -466,9 +466,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
466
466
  case "image": {
467
467
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
468
468
  return /* @__PURE__ */ jsx(
469
- "img",
469
+ EmbedImage,
470
470
  {
471
- "data-ncm-token": "image",
471
+ attrs: { "data-ncm-token": "image" },
472
+ target: token.src,
472
473
  src,
473
474
  alt: token.alt,
474
475
  title: token.title
@@ -502,10 +503,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
502
503
  }
503
504
  if (embedType === "image") {
504
505
  return /* @__PURE__ */ jsx(
505
- "img",
506
+ EmbedImage,
506
507
  {
507
- "data-ncm-token": "wiki_embed",
508
- "data-ncm-wikiembed-type": embedType,
508
+ attrs: {
509
+ "data-ncm-token": "wiki_embed",
510
+ "data-ncm-wikiembed-type": embedType
511
+ },
512
+ target: token.target,
509
513
  src: url,
510
514
  alt: token.display ?? token.target,
511
515
  className: config.embeddings?.imageClassName
@@ -536,6 +540,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
536
540
  }
537
541
  );
538
542
  }
543
+ const onEmbedClick = config.embeddings?.onEmbedClick;
544
+ if (onEmbedClick) {
545
+ const handleClick = (e) => {
546
+ onEmbedClick(token.target, result, e);
547
+ };
548
+ return /* @__PURE__ */ jsx(
549
+ "button",
550
+ {
551
+ type: "button",
552
+ "data-ncm-token": "wiki_embed",
553
+ "data-ncm-wikiembed-type": embedType,
554
+ onClick: handleClick,
555
+ children: token.display ?? token.target
556
+ }
557
+ );
558
+ }
539
559
  return /* @__PURE__ */ jsx(
540
560
  "a",
541
561
  {
@@ -554,6 +574,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
554
574
  return null;
555
575
  }
556
576
  }
577
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
578
+ const config = useNcmConfig();
579
+ const Fallback = config.embeddings?.renderImageError;
580
+ const [failedSrc, setFailedSrc] = useState(null);
581
+ useEffect(() => {
582
+ setFailedSrc(null);
583
+ }, [src]);
584
+ if (!Fallback) {
585
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
586
+ }
587
+ if (failedSrc === src) {
588
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
589
+ }
590
+ return /* @__PURE__ */ jsx(
591
+ "img",
592
+ {
593
+ ...attrs,
594
+ src,
595
+ alt,
596
+ title,
597
+ className,
598
+ onError: () => setFailedSrc(src)
599
+ }
600
+ );
601
+ }
557
602
  function renderReadingText(content, opts) {
558
603
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
559
604
  const { bionic = false, beeline = false } = opts;
@@ -650,9 +650,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
650
650
  case "image": {
651
651
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
652
652
  return /* @__PURE__ */ jsx(
653
- "img",
653
+ EmbedImage,
654
654
  {
655
- "data-ncm-token": "image",
655
+ attrs: { "data-ncm-token": "image" },
656
+ target: token.src,
656
657
  src,
657
658
  alt: token.alt,
658
659
  title: token.title
@@ -686,10 +687,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
686
687
  }
687
688
  if (embedType === "image") {
688
689
  return /* @__PURE__ */ jsx(
689
- "img",
690
+ EmbedImage,
690
691
  {
691
- "data-ncm-token": "wiki_embed",
692
- "data-ncm-wikiembed-type": embedType,
692
+ attrs: {
693
+ "data-ncm-token": "wiki_embed",
694
+ "data-ncm-wikiembed-type": embedType
695
+ },
696
+ target: token.target,
693
697
  src: url,
694
698
  alt: token.display ?? token.target,
695
699
  className: config.embeddings?.imageClassName
@@ -720,6 +724,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
720
724
  }
721
725
  );
722
726
  }
727
+ const onEmbedClick = config.embeddings?.onEmbedClick;
728
+ if (onEmbedClick) {
729
+ const handleClick = (e) => {
730
+ onEmbedClick(token.target, result, e);
731
+ };
732
+ return /* @__PURE__ */ jsx(
733
+ "button",
734
+ {
735
+ type: "button",
736
+ "data-ncm-token": "wiki_embed",
737
+ "data-ncm-wikiembed-type": embedType,
738
+ onClick: handleClick,
739
+ children: token.display ?? token.target
740
+ }
741
+ );
742
+ }
723
743
  return /* @__PURE__ */ jsx(
724
744
  "a",
725
745
  {
@@ -738,6 +758,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
738
758
  return null;
739
759
  }
740
760
  }
761
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
762
+ const config = useNcmConfig();
763
+ const Fallback = config.embeddings?.renderImageError;
764
+ const [failedSrc, setFailedSrc] = useState(null);
765
+ useEffect(() => {
766
+ setFailedSrc(null);
767
+ }, [src]);
768
+ if (!Fallback) {
769
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
770
+ }
771
+ if (failedSrc === src) {
772
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
773
+ }
774
+ return /* @__PURE__ */ jsx(
775
+ "img",
776
+ {
777
+ ...attrs,
778
+ src,
779
+ alt,
780
+ title,
781
+ className,
782
+ onError: () => setFailedSrc(src)
783
+ }
784
+ );
785
+ }
741
786
  function renderReadingText(content, opts) {
742
787
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
743
788
  const { bionic = false, beeline = false } = opts;
@@ -773,7 +818,7 @@ function renderReadingText(content, opts) {
773
818
  return /* @__PURE__ */ jsx(Fragment, { children: pieces });
774
819
  }
775
820
  function BlockquoteBlock({ block, className }) {
776
- const lines = block.content.split("\n").filter((line) => line.trim() !== "");
821
+ const lines = block.content.split("\n");
777
822
  return /* @__PURE__ */ jsx(
778
823
  "blockquote",
779
824
  {
@@ -783,7 +828,7 @@ function BlockquoteBlock({ block, className }) {
783
828
  "data-block-id": block.id,
784
829
  "data-ncm-blockquote": "",
785
830
  className,
786
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(InlineContent, { content: line }) }, index))
831
+ 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))
787
832
  }
788
833
  );
789
834
  }
@@ -923,7 +968,7 @@ function CodeBlock({ block, className }) {
923
968
  "data-ncm-language": block.language,
924
969
  className: cn("relative", className),
925
970
  children: [
926
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
971
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
927
972
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
928
973
  languageLabel
929
974
  ]
@@ -942,7 +987,7 @@ function CodeBlock({ block, className }) {
942
987
  "data-ncm-language": block.language,
943
988
  className: cn("relative", className),
944
989
  children: [
945
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
990
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
946
991
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
947
992
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
948
993
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -1394,10 +1439,12 @@ function LinkBlock({ block, className }) {
1394
1439
  function ListBlock({ block, className }) {
1395
1440
  const isOrdered = block.type === "list_ordered";
1396
1441
  const Tag = isOrdered ? "ol" : "ul";
1442
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1397
1443
  return /* @__PURE__ */ jsx(
1398
1444
  Tag,
1399
1445
  {
1400
1446
  role: "list",
1447
+ start,
1401
1448
  "data-ncm-block": block.id,
1402
1449
  "data-ncm-stable": block.stableId,
1403
1450
  "data-ncm-type": block.type,
@@ -1409,6 +1456,9 @@ function ListBlock({ block, className }) {
1409
1456
  }
1410
1457
  );
1411
1458
  }
1459
+ function ItemContent({ content }) {
1460
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1461
+ }
1412
1462
  function nestedItemIdKey(id) {
1413
1463
  if (!id) {
1414
1464
  return void 0;
@@ -1425,7 +1475,7 @@ function ListItems({ items, itemIds, ordered }) {
1425
1475
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1426
1476
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1427
1477
  if (typeof item === "string") {
1428
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1478
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1429
1479
  }
1430
1480
  if (isTypedNestedList(item)) {
1431
1481
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1435,7 +1485,7 @@ function ListItems({ items, itemIds, ordered }) {
1435
1485
  const content = typeof first === "string" ? first : "";
1436
1486
  const nestedContent = processNestedItems(rest, ordered);
1437
1487
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1438
- /* @__PURE__ */ jsx(InlineContent, { content }),
1488
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1439
1489
  nestedContent
1440
1490
  ] }, key);
1441
1491
  }
@@ -1594,6 +1644,7 @@ function TableBlock({ block, className }) {
1594
1644
  function TaskItems({ items }) {
1595
1645
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1596
1646
  const status = item.checked ? "Completed" : "Incomplete";
1647
+ const text = serializeInlineContent(item.content);
1597
1648
  return /* @__PURE__ */ jsxs(
1598
1649
  "li",
1599
1650
  {
@@ -1620,7 +1671,7 @@ function TaskItems({ items }) {
1620
1671
  ":",
1621
1672
  " "
1622
1673
  ] }),
1623
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1674
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1624
1675
  ] })
1625
1676
  ] }),
1626
1677
  item.children ? /* @__PURE__ */ jsx("ul", { role: "list", "data-ncm-list-nested": "", className: "ml-6 list-none", children: /* @__PURE__ */ jsx(TaskItems, { items: item.children.items }) }) : null
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { Block } from '@nuucognition/ncm';
4
4
 
@@ -37,7 +37,7 @@ interface NcmReferencesProviderProps {
37
37
  children: ReactNode;
38
38
  }
39
39
  /** Document-root provider — runs the numbering pre-pass over `blocks`. */
40
- declare function NcmReferencesProvider({ blocks, children }: NcmReferencesProviderProps): react_jsx_runtime.JSX.Element;
40
+ declare function NcmReferencesProvider({ blocks, children }: NcmReferencesProviderProps): react.JSX.Element;
41
41
  interface BlockReferenceScopeProps {
42
42
  /** Block id; resolves the base offset from the document pre-pass. */
43
43
  blockId?: string;
@@ -48,7 +48,7 @@ interface BlockReferenceScopeProps {
48
48
  * on every render and hands out sequential numbers as markers render. Resetting
49
49
  * each render keeps numbering idempotent under React re-renders / StrictMode.
50
50
  */
51
- declare function BlockReferenceScope({ blockId, children }: BlockReferenceScopeProps): react_jsx_runtime.JSX.Element;
51
+ declare function BlockReferenceScope({ blockId, children }: BlockReferenceScopeProps): react.JSX.Element;
52
52
  /** Read the active per-block reference scope, if any. */
53
53
  declare function useBlockReferenceScope(): BlockReferenceScopeValue | null;
54
54
  /**
@@ -58,6 +58,6 @@ declare function useBlockReferenceScope(): BlockReferenceScopeValue | null;
58
58
  */
59
59
  declare function InertReferenceScope({ children }: {
60
60
  children: ReactNode;
61
- }): react_jsx_runtime.JSX.Element;
61
+ }): react.JSX.Element;
62
62
 
63
63
  export { BlockReferenceScope as B, InertReferenceScope as I, NcmReferencesProvider as N, type ReferenceCounts as R, type BlockReferenceScopeProps as a, type BlockReferenceScopeValue as b, type NcmReferencesProviderProps as c, type ReferenceKind as d, computeReferenceBases as e, useBlockReferenceScope as u };