@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
@@ -473,9 +473,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
473
473
  case "image": {
474
474
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
475
475
  return /* @__PURE__ */ jsx(
476
- "img",
476
+ EmbedImage,
477
477
  {
478
- "data-ncm-token": "image",
478
+ attrs: { "data-ncm-token": "image" },
479
+ target: token.src,
479
480
  src,
480
481
  alt: token.alt,
481
482
  title: token.title
@@ -509,10 +510,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
509
510
  }
510
511
  if (embedType === "image") {
511
512
  return /* @__PURE__ */ jsx(
512
- "img",
513
+ EmbedImage,
513
514
  {
514
- "data-ncm-token": "wiki_embed",
515
- "data-ncm-wikiembed-type": embedType,
515
+ attrs: {
516
+ "data-ncm-token": "wiki_embed",
517
+ "data-ncm-wikiembed-type": embedType
518
+ },
519
+ target: token.target,
516
520
  src: url,
517
521
  alt: token.display ?? token.target,
518
522
  className: config.embeddings?.imageClassName
@@ -543,6 +547,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
543
547
  }
544
548
  );
545
549
  }
550
+ const onEmbedClick = config.embeddings?.onEmbedClick;
551
+ if (onEmbedClick) {
552
+ const handleClick = (e) => {
553
+ onEmbedClick(token.target, result, e);
554
+ };
555
+ return /* @__PURE__ */ jsx(
556
+ "button",
557
+ {
558
+ type: "button",
559
+ "data-ncm-token": "wiki_embed",
560
+ "data-ncm-wikiembed-type": embedType,
561
+ onClick: handleClick,
562
+ children: token.display ?? token.target
563
+ }
564
+ );
565
+ }
546
566
  return /* @__PURE__ */ jsx(
547
567
  "a",
548
568
  {
@@ -561,6 +581,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
561
581
  return null;
562
582
  }
563
583
  }
584
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
585
+ const config = useNcmConfig();
586
+ const Fallback = config.embeddings?.renderImageError;
587
+ const [failedSrc, setFailedSrc] = useState(null);
588
+ useEffect(() => {
589
+ setFailedSrc(null);
590
+ }, [src]);
591
+ if (!Fallback) {
592
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
593
+ }
594
+ if (failedSrc === src) {
595
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
596
+ }
597
+ return /* @__PURE__ */ jsx(
598
+ "img",
599
+ {
600
+ ...attrs,
601
+ src,
602
+ alt,
603
+ title,
604
+ className,
605
+ onError: () => setFailedSrc(src)
606
+ }
607
+ );
608
+ }
564
609
  function renderReadingText(content, opts) {
565
610
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
566
611
  const { bionic = false, beeline = false } = opts;
@@ -617,6 +662,7 @@ function BlockShell({
617
662
  function TaskItems({ items }) {
618
663
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
619
664
  const status = item.checked ? "Completed" : "Incomplete";
665
+ const text = serializeInlineContent(item.content);
620
666
  return /* @__PURE__ */ jsxs(
621
667
  "li",
622
668
  {
@@ -643,7 +689,7 @@ function TaskItems({ items }) {
643
689
  ":",
644
690
  " "
645
691
  ] }),
646
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
692
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
647
693
  ] })
648
694
  ] }),
649
695
  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
@@ -2,10 +2,10 @@ import * as react from 'react';
2
2
  import { HTMLAttributes, ReactNode } from 'react';
3
3
  import { Block } from '@nuucognition/ncm';
4
4
  export { NcmBlock, NcmBlockProps } from './ncm-block.js';
5
- export { NcmDocument, NcmDocumentProps, NcmTheme } from './ncm-document.js';
6
- import 'react/jsx-runtime';
5
+ import { N as NcmConfig } from '../use-ncm-config-CnntcShj.js';
6
+ import { NcmTheme } from './ncm-document.js';
7
+ export { NcmDocument, NcmDocumentProps } from './ncm-document.js';
7
8
  import '../renderers-C5f41FCy.js';
8
- import '../use-ncm-config-D0doMYTH.js';
9
9
  import '@nuucognition/mesh-core';
10
10
 
11
11
  type BlockShellTag = "aside" | "details" | "div" | "dl" | "figure" | "section" | "ul";
@@ -596,4 +596,34 @@ declare function ChildBlocks({ as, blocks, ...props }: ChildBlocksProps): react.
596
596
  onTransitionStartCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
597
597
  }, HTMLElement>;
598
598
 
599
- export { BlockShell, type BlockShellProps, ChildBlocks, type ChildBlocksProps, blockDataAttributes, blockKey };
599
+ interface NcmBlockPreviewProps {
600
+ /** The block's markdown source, verbatim. */
601
+ source: string;
602
+ /**
603
+ * The NCM block type the source is expected to parse as. When set and the
604
+ * parse produces no block of this type, the preview shows the parse warning
605
+ * instead of falling back to whatever did parse. Absent, every parsed block
606
+ * renders.
607
+ */
608
+ expectedType?: string;
609
+ theme?: NcmTheme;
610
+ /** Optional provider config (renderers, code, inline …), mounted internally. */
611
+ config?: NcmConfig;
612
+ className?: string;
613
+ }
614
+ /**
615
+ * The one-block reader preview.
616
+ *
617
+ * Give it a source string, get the ncm-ui rendering back — or a quiet
618
+ * "cannot be parsed" state when the source does not parse as the expected
619
+ * block type. Self-sufficient by design: it mounts its own provider, so a
620
+ * host can render it anywhere (the NUU Editor's node views render it through
621
+ * the `previewProviders` seam, outside any app provider tree).
622
+ *
623
+ * Parse options mirror the playground gallery's (`ncm-full`, raw HTML,
624
+ * frontmatter optional), so the preview and the gallery agree on what a
625
+ * block's source means.
626
+ */
627
+ declare function NcmBlockPreview({ source, expectedType, theme, config, className, }: NcmBlockPreviewProps): react.JSX.Element;
628
+
629
+ export { BlockShell, type BlockShellProps, ChildBlocks, type ChildBlocksProps, NcmBlockPreview, type NcmBlockPreviewProps, NcmTheme, blockDataAttributes, blockKey };
@@ -4,7 +4,7 @@ import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
7
- import { serializeInlineContent, isTypedNestedList } from '@nuucognition/ncm';
7
+ import { parseNcm, serializeInlineContent, isTypedNestedList } from '@nuucognition/ncm';
8
8
 
9
9
  // src/components/block-shell.tsx
10
10
  function cn(...inputs) {
@@ -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;
@@ -737,7 +782,7 @@ function renderReadingText(content, opts) {
737
782
  return /* @__PURE__ */ jsx(Fragment, { children: pieces });
738
783
  }
739
784
  function BlockquoteBlock({ block, className }) {
740
- const lines = block.content.split("\n").filter((line) => line.trim() !== "");
785
+ const lines = block.content.split("\n");
741
786
  return /* @__PURE__ */ jsx(
742
787
  "blockquote",
743
788
  {
@@ -747,7 +792,7 @@ function BlockquoteBlock({ block, className }) {
747
792
  "data-block-id": block.id,
748
793
  "data-ncm-blockquote": "",
749
794
  className,
750
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(InlineContent, { content: line }) }, index))
795
+ 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))
751
796
  }
752
797
  );
753
798
  }
@@ -887,7 +932,7 @@ function CodeBlock({ block, className }) {
887
932
  "data-ncm-language": block.language,
888
933
  className: cn("relative", className),
889
934
  children: [
890
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
935
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
891
936
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
892
937
  languageLabel
893
938
  ]
@@ -906,7 +951,7 @@ function CodeBlock({ block, className }) {
906
951
  "data-ncm-language": block.language,
907
952
  className: cn("relative", className),
908
953
  children: [
909
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
954
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
910
955
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
911
956
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
912
957
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -1358,10 +1403,12 @@ function LinkBlock({ block, className }) {
1358
1403
  function ListBlock({ block, className }) {
1359
1404
  const isOrdered = block.type === "list_ordered";
1360
1405
  const Tag = isOrdered ? "ol" : "ul";
1406
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1361
1407
  return /* @__PURE__ */ jsx(
1362
1408
  Tag,
1363
1409
  {
1364
1410
  role: "list",
1411
+ start,
1365
1412
  "data-ncm-block": block.id,
1366
1413
  "data-ncm-stable": block.stableId,
1367
1414
  "data-ncm-type": block.type,
@@ -1373,6 +1420,9 @@ function ListBlock({ block, className }) {
1373
1420
  }
1374
1421
  );
1375
1422
  }
1423
+ function ItemContent({ content }) {
1424
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1425
+ }
1376
1426
  function nestedItemIdKey(id) {
1377
1427
  if (!id) {
1378
1428
  return void 0;
@@ -1389,7 +1439,7 @@ function ListItems({ items, itemIds, ordered }) {
1389
1439
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1390
1440
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1391
1441
  if (typeof item === "string") {
1392
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1442
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1393
1443
  }
1394
1444
  if (isTypedNestedList(item)) {
1395
1445
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1399,7 +1449,7 @@ function ListItems({ items, itemIds, ordered }) {
1399
1449
  const content = typeof first === "string" ? first : "";
1400
1450
  const nestedContent = processNestedItems(rest, ordered);
1401
1451
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1402
- /* @__PURE__ */ jsx(InlineContent, { content }),
1452
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1403
1453
  nestedContent
1404
1454
  ] }, key);
1405
1455
  }
@@ -1558,6 +1608,7 @@ function TableBlock({ block, className }) {
1558
1608
  function TaskItems({ items }) {
1559
1609
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1560
1610
  const status = item.checked ? "Completed" : "Incomplete";
1611
+ const text = serializeInlineContent(item.content);
1561
1612
  return /* @__PURE__ */ jsxs(
1562
1613
  "li",
1563
1614
  {
@@ -1584,7 +1635,7 @@ function TaskItems({ items }) {
1584
1635
  ":",
1585
1636
  " "
1586
1637
  ] }),
1587
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1638
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1588
1639
  ] })
1589
1640
  ] }),
1590
1641
  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
@@ -1836,5 +1887,41 @@ function NcmDocument({
1836
1887
  }
1837
1888
  );
1838
1889
  }
1890
+ function NcmBlockPreview({
1891
+ source,
1892
+ expectedType,
1893
+ theme = "nuu",
1894
+ config,
1895
+ className
1896
+ }) {
1897
+ const parsed = useMemo(() => {
1898
+ try {
1899
+ const doc = parseNcm(source, {
1900
+ preset: "ncm-full",
1901
+ allowMissingFrontmatter: true,
1902
+ rawHtml: true
1903
+ });
1904
+ const all = doc.blocks ?? [];
1905
+ const blocks = expectedType ? all.filter((b) => b.type === expectedType) : all;
1906
+ return { blocks, failed: blocks.length === 0 };
1907
+ } catch {
1908
+ return { blocks: [], failed: true };
1909
+ }
1910
+ }, [source, expectedType]);
1911
+ if (parsed.failed) {
1912
+ return /* @__PURE__ */ jsx(
1913
+ "div",
1914
+ {
1915
+ "data-ncm-parse-warning": "",
1916
+ "data-ncm-theme": theme,
1917
+ className: `ncm-theme-${theme}${className ? ` ${className}` : ""}`,
1918
+ role: "status",
1919
+ children: expectedType ? `Cannot be parsed as ${expectedType}` : "Cannot be parsed"
1920
+ }
1921
+ );
1922
+ }
1923
+ const document2 = /* @__PURE__ */ jsx(NcmDocument, { blocks: parsed.blocks, theme, className });
1924
+ return config ? /* @__PURE__ */ jsx(NcmProvider, { config, children: document2 }) : document2;
1925
+ }
1839
1926
 
1840
- export { BlockShell, ChildBlocks, NcmBlock, NcmDocument, blockDataAttributes, blockKey };
1927
+ export { BlockShell, ChildBlocks, NcmBlock, NcmBlockPreview, NcmDocument, blockDataAttributes, blockKey };
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { Block } from '@nuucognition/ncm';
3
3
  import { b as BlockRendererRegistry } from '../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  interface NcmBlockProps {
7
6
  block: Block;
@@ -23,6 +22,6 @@ interface NcmBlockProps {
23
22
  * />
24
23
  * ```
25
24
  */
26
- declare function NcmBlock({ block, className, renderers }: NcmBlockProps): react_jsx_runtime.JSX.Element;
25
+ declare function NcmBlock({ block, className, renderers }: NcmBlockProps): react.JSX.Element;
27
26
 
28
27
  export { NcmBlock, type NcmBlockProps };
@@ -575,9 +575,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
575
575
  case "image": {
576
576
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
577
577
  return /* @__PURE__ */ jsx(
578
- "img",
578
+ EmbedImage,
579
579
  {
580
- "data-ncm-token": "image",
580
+ attrs: { "data-ncm-token": "image" },
581
+ target: token.src,
581
582
  src,
582
583
  alt: token.alt,
583
584
  title: token.title
@@ -611,10 +612,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
611
612
  }
612
613
  if (embedType === "image") {
613
614
  return /* @__PURE__ */ jsx(
614
- "img",
615
+ EmbedImage,
615
616
  {
616
- "data-ncm-token": "wiki_embed",
617
- "data-ncm-wikiembed-type": embedType,
617
+ attrs: {
618
+ "data-ncm-token": "wiki_embed",
619
+ "data-ncm-wikiembed-type": embedType
620
+ },
621
+ target: token.target,
618
622
  src: url,
619
623
  alt: token.display ?? token.target,
620
624
  className: config.embeddings?.imageClassName
@@ -645,6 +649,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
645
649
  }
646
650
  );
647
651
  }
652
+ const onEmbedClick = config.embeddings?.onEmbedClick;
653
+ if (onEmbedClick) {
654
+ const handleClick = (e) => {
655
+ onEmbedClick(token.target, result, e);
656
+ };
657
+ return /* @__PURE__ */ jsx(
658
+ "button",
659
+ {
660
+ type: "button",
661
+ "data-ncm-token": "wiki_embed",
662
+ "data-ncm-wikiembed-type": embedType,
663
+ onClick: handleClick,
664
+ children: token.display ?? token.target
665
+ }
666
+ );
667
+ }
648
668
  return /* @__PURE__ */ jsx(
649
669
  "a",
650
670
  {
@@ -663,6 +683,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
663
683
  return null;
664
684
  }
665
685
  }
686
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
687
+ const config = useNcmConfig();
688
+ const Fallback = config.embeddings?.renderImageError;
689
+ const [failedSrc, setFailedSrc] = useState(null);
690
+ useEffect(() => {
691
+ setFailedSrc(null);
692
+ }, [src]);
693
+ if (!Fallback) {
694
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
695
+ }
696
+ if (failedSrc === src) {
697
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
698
+ }
699
+ return /* @__PURE__ */ jsx(
700
+ "img",
701
+ {
702
+ ...attrs,
703
+ src,
704
+ alt,
705
+ title,
706
+ className,
707
+ onError: () => setFailedSrc(src)
708
+ }
709
+ );
710
+ }
666
711
  function renderReadingText(content, opts) {
667
712
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
668
713
  const { bionic = false, beeline = false } = opts;
@@ -698,7 +743,7 @@ function renderReadingText(content, opts) {
698
743
  return /* @__PURE__ */ jsx(Fragment, { children: pieces });
699
744
  }
700
745
  function BlockquoteBlock({ block, className }) {
701
- const lines = block.content.split("\n").filter((line) => line.trim() !== "");
746
+ const lines = block.content.split("\n");
702
747
  return /* @__PURE__ */ jsx(
703
748
  "blockquote",
704
749
  {
@@ -708,7 +753,7 @@ function BlockquoteBlock({ block, className }) {
708
753
  "data-block-id": block.id,
709
754
  "data-ncm-blockquote": "",
710
755
  className,
711
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(InlineContent, { content: line }) }, index))
756
+ 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))
712
757
  }
713
758
  );
714
759
  }
@@ -848,7 +893,7 @@ function CodeBlock({ block, className }) {
848
893
  "data-ncm-language": block.language,
849
894
  className: cn("relative", className),
850
895
  children: [
851
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
896
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
852
897
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
853
898
  languageLabel
854
899
  ]
@@ -867,7 +912,7 @@ function CodeBlock({ block, className }) {
867
912
  "data-ncm-language": block.language,
868
913
  className: cn("relative", className),
869
914
  children: [
870
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
915
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
871
916
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
872
917
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
873
918
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -1319,10 +1364,12 @@ function LinkBlock({ block, className }) {
1319
1364
  function ListBlock({ block, className }) {
1320
1365
  const isOrdered = block.type === "list_ordered";
1321
1366
  const Tag = isOrdered ? "ol" : "ul";
1367
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1322
1368
  return /* @__PURE__ */ jsx(
1323
1369
  Tag,
1324
1370
  {
1325
1371
  role: "list",
1372
+ start,
1326
1373
  "data-ncm-block": block.id,
1327
1374
  "data-ncm-stable": block.stableId,
1328
1375
  "data-ncm-type": block.type,
@@ -1334,6 +1381,9 @@ function ListBlock({ block, className }) {
1334
1381
  }
1335
1382
  );
1336
1383
  }
1384
+ function ItemContent({ content }) {
1385
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1386
+ }
1337
1387
  function nestedItemIdKey(id) {
1338
1388
  if (!id) {
1339
1389
  return void 0;
@@ -1350,7 +1400,7 @@ function ListItems({ items, itemIds, ordered }) {
1350
1400
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1351
1401
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1352
1402
  if (typeof item === "string") {
1353
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1403
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1354
1404
  }
1355
1405
  if (isTypedNestedList(item)) {
1356
1406
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1360,7 +1410,7 @@ function ListItems({ items, itemIds, ordered }) {
1360
1410
  const content = typeof first === "string" ? first : "";
1361
1411
  const nestedContent = processNestedItems(rest, ordered);
1362
1412
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1363
- /* @__PURE__ */ jsx(InlineContent, { content }),
1413
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1364
1414
  nestedContent
1365
1415
  ] }, key);
1366
1416
  }
@@ -1519,6 +1569,7 @@ function TableBlock({ block, className }) {
1519
1569
  function TaskItems({ items }) {
1520
1570
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1521
1571
  const status = item.checked ? "Completed" : "Incomplete";
1572
+ const text = serializeInlineContent(item.content);
1522
1573
  return /* @__PURE__ */ jsxs(
1523
1574
  "li",
1524
1575
  {
@@ -1545,7 +1596,7 @@ function TaskItems({ items }) {
1545
1596
  ":",
1546
1597
  " "
1547
1598
  ] }),
1548
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1599
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1549
1600
  ] })
1550
1601
  ] }),
1551
1602
  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,8 +1,8 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Block } from '@nuucognition/ncm';
1
+ import * as react from 'react';
3
2
  import { ReactNode } from 'react';
3
+ import { Block } from '@nuucognition/ncm';
4
4
  import { b as BlockRendererRegistry } from '../renderers-C5f41FCy.js';
5
- import { I as InlineConfig, E as EmbeddingsConfig } from '../use-ncm-config-D0doMYTH.js';
5
+ import { a as InlineConfig, E as EmbeddingsConfig } from '../use-ncm-config-CnntcShj.js';
6
6
  import '@nuucognition/mesh-core';
7
7
 
8
8
  type NcmTheme = "nuu" | "paper";
@@ -43,6 +43,6 @@ interface NcmDocumentProps {
43
43
  * <NcmDocument blocks={blocks} theme="paper" />
44
44
  * ```
45
45
  */
46
- declare function NcmDocument({ blocks, theme, className, renderers: propsRenderers, blockClassName, renderBlock, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, }: NcmDocumentProps): react_jsx_runtime.JSX.Element;
46
+ declare function NcmDocument({ blocks, theme, className, renderers: propsRenderers, blockClassName, renderBlock, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, }: NcmDocumentProps): react.JSX.Element;
47
47
 
48
48
  export { NcmDocument, type NcmDocumentProps, type NcmTheme };