@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
@@ -468,9 +468,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
468
468
  case "image": {
469
469
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
470
470
  return /* @__PURE__ */ jsx(
471
- "img",
471
+ EmbedImage,
472
472
  {
473
- "data-ncm-token": "image",
473
+ attrs: { "data-ncm-token": "image" },
474
+ target: token.src,
474
475
  src,
475
476
  alt: token.alt,
476
477
  title: token.title
@@ -504,10 +505,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
504
505
  }
505
506
  if (embedType === "image") {
506
507
  return /* @__PURE__ */ jsx(
507
- "img",
508
+ EmbedImage,
508
509
  {
509
- "data-ncm-token": "wiki_embed",
510
- "data-ncm-wikiembed-type": embedType,
510
+ attrs: {
511
+ "data-ncm-token": "wiki_embed",
512
+ "data-ncm-wikiembed-type": embedType
513
+ },
514
+ target: token.target,
511
515
  src: url,
512
516
  alt: token.display ?? token.target,
513
517
  className: config.embeddings?.imageClassName
@@ -538,6 +542,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
538
542
  }
539
543
  );
540
544
  }
545
+ const onEmbedClick = config.embeddings?.onEmbedClick;
546
+ if (onEmbedClick) {
547
+ const handleClick = (e) => {
548
+ onEmbedClick(token.target, result, e);
549
+ };
550
+ return /* @__PURE__ */ jsx(
551
+ "button",
552
+ {
553
+ type: "button",
554
+ "data-ncm-token": "wiki_embed",
555
+ "data-ncm-wikiembed-type": embedType,
556
+ onClick: handleClick,
557
+ children: token.display ?? token.target
558
+ }
559
+ );
560
+ }
541
561
  return /* @__PURE__ */ jsx(
542
562
  "a",
543
563
  {
@@ -556,6 +576,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
556
576
  return null;
557
577
  }
558
578
  }
579
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
580
+ const config = useNcmConfig();
581
+ const Fallback = config.embeddings?.renderImageError;
582
+ const [failedSrc, setFailedSrc] = useState(null);
583
+ useEffect(() => {
584
+ setFailedSrc(null);
585
+ }, [src]);
586
+ if (!Fallback) {
587
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
588
+ }
589
+ if (failedSrc === src) {
590
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
591
+ }
592
+ return /* @__PURE__ */ jsx(
593
+ "img",
594
+ {
595
+ ...attrs,
596
+ src,
597
+ alt,
598
+ title,
599
+ className,
600
+ onError: () => setFailedSrc(src)
601
+ }
602
+ );
603
+ }
559
604
  function renderReadingText(content, opts) {
560
605
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
561
606
  const { bionic = false, beeline = false } = opts;
@@ -593,10 +638,12 @@ function renderReadingText(content, opts) {
593
638
  function ListBlock({ block, className }) {
594
639
  const isOrdered = block.type === "list_ordered";
595
640
  const Tag = isOrdered ? "ol" : "ul";
641
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
596
642
  return /* @__PURE__ */ jsx(
597
643
  Tag,
598
644
  {
599
645
  role: "list",
646
+ start,
600
647
  "data-ncm-block": block.id,
601
648
  "data-ncm-stable": block.stableId,
602
649
  "data-ncm-type": block.type,
@@ -608,6 +655,9 @@ function ListBlock({ block, className }) {
608
655
  }
609
656
  );
610
657
  }
658
+ function ItemContent({ content }) {
659
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
660
+ }
611
661
  function nestedItemIdKey(id) {
612
662
  if (!id) {
613
663
  return void 0;
@@ -624,7 +674,7 @@ function ListItems({ items, itemIds, ordered }) {
624
674
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
625
675
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
626
676
  if (typeof item === "string") {
627
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
677
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
628
678
  }
629
679
  if (isTypedNestedList(item)) {
630
680
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -634,7 +684,7 @@ function ListItems({ items, itemIds, ordered }) {
634
684
  const content = typeof first === "string" ? first : "";
635
685
  const nestedContent = processNestedItems(rest, ordered);
636
686
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
637
- /* @__PURE__ */ jsx(InlineContent, { content }),
687
+ /* @__PURE__ */ jsx(ItemContent, { content }),
638
688
  nestedContent
639
689
  ] }, key);
640
690
  }
@@ -1,13 +1,12 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { MathBlock as MathBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type MathBlockProps = BlockRendererProps<MathBlock$1>;
7
6
  /**
8
7
  * Math renderer — promoted ```math fences rendered as display KaTeX (mirrors
9
8
  * LatexDisplayBlock). Falls back to escaped source on KaTeX errors.
10
9
  */
11
- declare function MathBlock({ block, className }: MathBlockProps): react_jsx_runtime.JSX.Element;
10
+ declare function MathBlock({ block, className }: MathBlockProps): react.JSX.Element;
12
11
 
13
12
  export { MathBlock, type MathBlockProps };
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { MermaidBlock as MermaidBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type MermaidBlockProps = BlockRendererProps<MermaidBlock$1>;
7
6
  /**
@@ -9,6 +8,6 @@ type MermaidBlockProps = BlockRendererProps<MermaidBlock$1>;
9
8
  * is bundled in this package). Consumers wire a live renderer by overriding the
10
9
  * `mermaid` renderer key. `data-ncm-diagram-type` exposes the detected kind.
11
10
  */
12
- declare function MermaidBlock({ block, className }: MermaidBlockProps): react_jsx_runtime.JSX.Element;
11
+ declare function MermaidBlock({ block, className }: MermaidBlockProps): react.JSX.Element;
13
12
 
14
13
  export { MermaidBlock, type MermaidBlockProps };
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { PageBreakerBlock as PageBreakerBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type PageBreakerBlockProps = BlockRendererProps<PageBreakerBlock$1>;
7
6
  /**
@@ -11,6 +10,6 @@ type PageBreakerBlockProps = BlockRendererProps<PageBreakerBlock$1>;
11
10
  * can locate where each source PDF page begins (e.g. to scroll-sync rendered
12
11
  * markdown against the original PDF). It produces no visible output.
13
12
  */
14
- declare function PageBreakerBlock({ block, className }: PageBreakerBlockProps): react_jsx_runtime.JSX.Element;
13
+ declare function PageBreakerBlock({ block, className }: PageBreakerBlockProps): react.JSX.Element;
15
14
 
16
15
  export { PageBreakerBlock, type PageBreakerBlockProps };
@@ -1,9 +1,8 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ParagraphBlock as ParagraphBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type ParagraphBlockProps = BlockRendererProps<ParagraphBlock$1>;
7
- declare function ParagraphBlock({ block, className }: ParagraphBlockProps): react_jsx_runtime.JSX.Element;
6
+ declare function ParagraphBlock({ block, className }: ParagraphBlockProps): react.JSX.Element;
8
7
 
9
8
  export { ParagraphBlock, type ParagraphBlockProps };
@@ -468,9 +468,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
468
468
  case "image": {
469
469
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
470
470
  return /* @__PURE__ */ jsx(
471
- "img",
471
+ EmbedImage,
472
472
  {
473
- "data-ncm-token": "image",
473
+ attrs: { "data-ncm-token": "image" },
474
+ target: token.src,
474
475
  src,
475
476
  alt: token.alt,
476
477
  title: token.title
@@ -504,10 +505,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
504
505
  }
505
506
  if (embedType === "image") {
506
507
  return /* @__PURE__ */ jsx(
507
- "img",
508
+ EmbedImage,
508
509
  {
509
- "data-ncm-token": "wiki_embed",
510
- "data-ncm-wikiembed-type": embedType,
510
+ attrs: {
511
+ "data-ncm-token": "wiki_embed",
512
+ "data-ncm-wikiembed-type": embedType
513
+ },
514
+ target: token.target,
511
515
  src: url,
512
516
  alt: token.display ?? token.target,
513
517
  className: config.embeddings?.imageClassName
@@ -538,6 +542,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
538
542
  }
539
543
  );
540
544
  }
545
+ const onEmbedClick = config.embeddings?.onEmbedClick;
546
+ if (onEmbedClick) {
547
+ const handleClick = (e) => {
548
+ onEmbedClick(token.target, result, e);
549
+ };
550
+ return /* @__PURE__ */ jsx(
551
+ "button",
552
+ {
553
+ type: "button",
554
+ "data-ncm-token": "wiki_embed",
555
+ "data-ncm-wikiembed-type": embedType,
556
+ onClick: handleClick,
557
+ children: token.display ?? token.target
558
+ }
559
+ );
560
+ }
541
561
  return /* @__PURE__ */ jsx(
542
562
  "a",
543
563
  {
@@ -556,6 +576,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
556
576
  return null;
557
577
  }
558
578
  }
579
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
580
+ const config = useNcmConfig();
581
+ const Fallback = config.embeddings?.renderImageError;
582
+ const [failedSrc, setFailedSrc] = useState(null);
583
+ useEffect(() => {
584
+ setFailedSrc(null);
585
+ }, [src]);
586
+ if (!Fallback) {
587
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
588
+ }
589
+ if (failedSrc === src) {
590
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
591
+ }
592
+ return /* @__PURE__ */ jsx(
593
+ "img",
594
+ {
595
+ ...attrs,
596
+ src,
597
+ alt,
598
+ title,
599
+ className,
600
+ onError: () => setFailedSrc(src)
601
+ }
602
+ );
603
+ }
559
604
  function renderReadingText(content, opts) {
560
605
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
561
606
  const { bionic = false, beeline = false } = opts;
@@ -1,13 +1,12 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { SpoilerBlock as SpoilerBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type SpoilerBlockProps = BlockRendererProps<SpoilerBlock$1>;
7
6
  /**
8
7
  * Spoiler renderer — collapsible hidden content (`>!` or `<details>`). Child
9
8
  * blocks render through `NcmBlock`.
10
9
  */
11
- declare function SpoilerBlock({ block, className }: SpoilerBlockProps): react_jsx_runtime.JSX.Element;
10
+ declare function SpoilerBlock({ block, className }: SpoilerBlockProps): react.JSX.Element;
12
11
 
13
12
  export { SpoilerBlock, type SpoilerBlockProps };
@@ -543,9 +543,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
543
543
  case "image": {
544
544
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
545
545
  return /* @__PURE__ */ jsx(
546
- "img",
546
+ EmbedImage,
547
547
  {
548
- "data-ncm-token": "image",
548
+ attrs: { "data-ncm-token": "image" },
549
+ target: token.src,
549
550
  src,
550
551
  alt: token.alt,
551
552
  title: token.title
@@ -579,10 +580,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
579
580
  }
580
581
  if (embedType === "image") {
581
582
  return /* @__PURE__ */ jsx(
582
- "img",
583
+ EmbedImage,
583
584
  {
584
- "data-ncm-token": "wiki_embed",
585
- "data-ncm-wikiembed-type": embedType,
585
+ attrs: {
586
+ "data-ncm-token": "wiki_embed",
587
+ "data-ncm-wikiembed-type": embedType
588
+ },
589
+ target: token.target,
586
590
  src: url,
587
591
  alt: token.display ?? token.target,
588
592
  className: config.embeddings?.imageClassName
@@ -613,6 +617,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
613
617
  }
614
618
  );
615
619
  }
620
+ const onEmbedClick = config.embeddings?.onEmbedClick;
621
+ if (onEmbedClick) {
622
+ const handleClick = (e) => {
623
+ onEmbedClick(token.target, result, e);
624
+ };
625
+ return /* @__PURE__ */ jsx(
626
+ "button",
627
+ {
628
+ type: "button",
629
+ "data-ncm-token": "wiki_embed",
630
+ "data-ncm-wikiembed-type": embedType,
631
+ onClick: handleClick,
632
+ children: token.display ?? token.target
633
+ }
634
+ );
635
+ }
616
636
  return /* @__PURE__ */ jsx(
617
637
  "a",
618
638
  {
@@ -631,6 +651,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
631
651
  return null;
632
652
  }
633
653
  }
654
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
655
+ const config = useNcmConfig();
656
+ const Fallback = config.embeddings?.renderImageError;
657
+ const [failedSrc, setFailedSrc] = useState(null);
658
+ useEffect(() => {
659
+ setFailedSrc(null);
660
+ }, [src]);
661
+ if (!Fallback) {
662
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
663
+ }
664
+ if (failedSrc === src) {
665
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
666
+ }
667
+ return /* @__PURE__ */ jsx(
668
+ "img",
669
+ {
670
+ ...attrs,
671
+ src,
672
+ alt,
673
+ title,
674
+ className,
675
+ onError: () => setFailedSrc(src)
676
+ }
677
+ );
678
+ }
634
679
  function renderReadingText(content, opts) {
635
680
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
636
681
  const { bionic = false, beeline = false } = opts;
@@ -666,7 +711,7 @@ function renderReadingText(content, opts) {
666
711
  return /* @__PURE__ */ jsx(Fragment, { children: pieces });
667
712
  }
668
713
  function BlockquoteBlock({ block, className }) {
669
- const lines = block.content.split("\n").filter((line) => line.trim() !== "");
714
+ const lines = block.content.split("\n");
670
715
  return /* @__PURE__ */ jsx(
671
716
  "blockquote",
672
717
  {
@@ -676,7 +721,7 @@ function BlockquoteBlock({ block, className }) {
676
721
  "data-block-id": block.id,
677
722
  "data-ncm-blockquote": "",
678
723
  className,
679
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(InlineContent, { content: line }) }, index))
724
+ 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))
680
725
  }
681
726
  );
682
727
  }
@@ -816,7 +861,7 @@ function CodeBlock({ block, className }) {
816
861
  "data-ncm-language": block.language,
817
862
  className: cn("relative", className),
818
863
  children: [
819
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
864
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
820
865
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
821
866
  languageLabel
822
867
  ]
@@ -835,7 +880,7 @@ function CodeBlock({ block, className }) {
835
880
  "data-ncm-language": block.language,
836
881
  className: cn("relative", className),
837
882
  children: [
838
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
883
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
839
884
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
840
885
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
841
886
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -1287,10 +1332,12 @@ function LinkBlock({ block, className }) {
1287
1332
  function ListBlock({ block, className }) {
1288
1333
  const isOrdered = block.type === "list_ordered";
1289
1334
  const Tag = isOrdered ? "ol" : "ul";
1335
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1290
1336
  return /* @__PURE__ */ jsx(
1291
1337
  Tag,
1292
1338
  {
1293
1339
  role: "list",
1340
+ start,
1294
1341
  "data-ncm-block": block.id,
1295
1342
  "data-ncm-stable": block.stableId,
1296
1343
  "data-ncm-type": block.type,
@@ -1302,6 +1349,9 @@ function ListBlock({ block, className }) {
1302
1349
  }
1303
1350
  );
1304
1351
  }
1352
+ function ItemContent({ content }) {
1353
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1354
+ }
1305
1355
  function nestedItemIdKey(id) {
1306
1356
  if (!id) {
1307
1357
  return void 0;
@@ -1318,7 +1368,7 @@ function ListItems({ items, itemIds, ordered }) {
1318
1368
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1319
1369
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1320
1370
  if (typeof item === "string") {
1321
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1371
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1322
1372
  }
1323
1373
  if (isTypedNestedList(item)) {
1324
1374
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1328,7 +1378,7 @@ function ListItems({ items, itemIds, ordered }) {
1328
1378
  const content = typeof first === "string" ? first : "";
1329
1379
  const nestedContent = processNestedItems(rest, ordered);
1330
1380
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1331
- /* @__PURE__ */ jsx(InlineContent, { content }),
1381
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1332
1382
  nestedContent
1333
1383
  ] }, key);
1334
1384
  }
@@ -1471,6 +1521,7 @@ function TableBlock({ block, className }) {
1471
1521
  function TaskItems({ items }) {
1472
1522
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1473
1523
  const status = item.checked ? "Completed" : "Incomplete";
1524
+ const text = serializeInlineContent(item.content);
1474
1525
  return /* @__PURE__ */ jsxs(
1475
1526
  "li",
1476
1527
  {
@@ -1497,7 +1548,7 @@ function TaskItems({ items }) {
1497
1548
  ":",
1498
1549
  " "
1499
1550
  ] }),
1500
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1551
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1501
1552
  ] })
1502
1553
  ] }),
1503
1554
  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,9 +1,8 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { TableBlock as TableBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type TableBlockProps = BlockRendererProps<TableBlock$1>;
7
- declare function TableBlock({ block, className }: TableBlockProps): react_jsx_runtime.JSX.Element;
6
+ declare function TableBlock({ block, className }: TableBlockProps): react.JSX.Element;
8
7
 
9
8
  export { TableBlock, type TableBlockProps };
@@ -470,9 +470,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
470
470
  case "image": {
471
471
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
472
472
  return /* @__PURE__ */ jsx(
473
- "img",
473
+ EmbedImage,
474
474
  {
475
- "data-ncm-token": "image",
475
+ attrs: { "data-ncm-token": "image" },
476
+ target: token.src,
476
477
  src,
477
478
  alt: token.alt,
478
479
  title: token.title
@@ -506,10 +507,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
506
507
  }
507
508
  if (embedType === "image") {
508
509
  return /* @__PURE__ */ jsx(
509
- "img",
510
+ EmbedImage,
510
511
  {
511
- "data-ncm-token": "wiki_embed",
512
- "data-ncm-wikiembed-type": embedType,
512
+ attrs: {
513
+ "data-ncm-token": "wiki_embed",
514
+ "data-ncm-wikiembed-type": embedType
515
+ },
516
+ target: token.target,
513
517
  src: url,
514
518
  alt: token.display ?? token.target,
515
519
  className: config.embeddings?.imageClassName
@@ -540,6 +544,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
540
544
  }
541
545
  );
542
546
  }
547
+ const onEmbedClick = config.embeddings?.onEmbedClick;
548
+ if (onEmbedClick) {
549
+ const handleClick = (e) => {
550
+ onEmbedClick(token.target, result, e);
551
+ };
552
+ return /* @__PURE__ */ jsx(
553
+ "button",
554
+ {
555
+ type: "button",
556
+ "data-ncm-token": "wiki_embed",
557
+ "data-ncm-wikiembed-type": embedType,
558
+ onClick: handleClick,
559
+ children: token.display ?? token.target
560
+ }
561
+ );
562
+ }
543
563
  return /* @__PURE__ */ jsx(
544
564
  "a",
545
565
  {
@@ -558,6 +578,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
558
578
  return null;
559
579
  }
560
580
  }
581
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
582
+ const config = useNcmConfig();
583
+ const Fallback = config.embeddings?.renderImageError;
584
+ const [failedSrc, setFailedSrc] = useState(null);
585
+ useEffect(() => {
586
+ setFailedSrc(null);
587
+ }, [src]);
588
+ if (!Fallback) {
589
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
590
+ }
591
+ if (failedSrc === src) {
592
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
593
+ }
594
+ return /* @__PURE__ */ jsx(
595
+ "img",
596
+ {
597
+ ...attrs,
598
+ src,
599
+ alt,
600
+ title,
601
+ className,
602
+ onError: () => setFailedSrc(src)
603
+ }
604
+ );
605
+ }
561
606
  function renderReadingText(content, opts) {
562
607
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
563
608
  const { bionic = false, beeline = false } = opts;
@@ -1,13 +1,12 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { TaskListBlock as TaskListBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type TaskListBlockProps = BlockRendererProps<TaskListBlock$1>;
7
6
  /**
8
7
  * Task-list renderer — a checkbox list promoted from `[ ]` / `[x]` items.
9
8
  * Checkboxes are display-only (disabled); nested task lists recurse.
10
9
  */
11
- declare function TaskListBlock({ block, className }: TaskListBlockProps): react_jsx_runtime.JSX.Element;
10
+ declare function TaskListBlock({ block, className }: TaskListBlockProps): react.JSX.Element;
12
11
 
13
12
  export { TaskListBlock, type TaskListBlockProps };