@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
@@ -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 }) })
@@ -1268,10 +1313,12 @@ function LinkBlock({ block, className }) {
1268
1313
  function ListBlock({ block, className }) {
1269
1314
  const isOrdered = block.type === "list_ordered";
1270
1315
  const Tag = isOrdered ? "ol" : "ul";
1316
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1271
1317
  return /* @__PURE__ */ jsx(
1272
1318
  Tag,
1273
1319
  {
1274
1320
  role: "list",
1321
+ start,
1275
1322
  "data-ncm-block": block.id,
1276
1323
  "data-ncm-stable": block.stableId,
1277
1324
  "data-ncm-type": block.type,
@@ -1283,6 +1330,9 @@ function ListBlock({ block, className }) {
1283
1330
  }
1284
1331
  );
1285
1332
  }
1333
+ function ItemContent({ content }) {
1334
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1335
+ }
1286
1336
  function nestedItemIdKey(id) {
1287
1337
  if (!id) {
1288
1338
  return void 0;
@@ -1299,7 +1349,7 @@ function ListItems({ items, itemIds, ordered }) {
1299
1349
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1300
1350
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1301
1351
  if (typeof item === "string") {
1302
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1352
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1303
1353
  }
1304
1354
  if (isTypedNestedList(item)) {
1305
1355
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1309,7 +1359,7 @@ function ListItems({ items, itemIds, ordered }) {
1309
1359
  const content = typeof first === "string" ? first : "";
1310
1360
  const nestedContent = processNestedItems(rest, ordered);
1311
1361
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1312
- /* @__PURE__ */ jsx(InlineContent, { content }),
1362
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1313
1363
  nestedContent
1314
1364
  ] }, key);
1315
1365
  }
@@ -1468,6 +1518,7 @@ function TableBlock({ block, className }) {
1468
1518
  function TaskItems({ items }) {
1469
1519
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1470
1520
  const status = item.checked ? "Completed" : "Incomplete";
1521
+ const text = serializeInlineContent(item.content);
1471
1522
  return /* @__PURE__ */ jsxs(
1472
1523
  "li",
1473
1524
  {
@@ -1494,7 +1545,7 @@ function TaskItems({ items }) {
1494
1545
  ":",
1495
1546
  " "
1496
1547
  ] }),
1497
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1548
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1498
1549
  ] })
1499
1550
  ] }),
1500
1551
  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,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { FrontmatterBlock as FrontmatterBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type FrontmatterBlockProps = BlockRendererProps<FrontmatterBlock$1>;
7
6
  /**
@@ -11,6 +10,6 @@ type FrontmatterBlockProps = BlockRendererProps<FrontmatterBlock$1>;
11
10
  * is a neutral default so the block is never silently dropped. Override the
12
11
  * `frontmatter` renderer key to hide it or render a richer header.
13
12
  */
14
- declare function FrontmatterBlock({ block, className }: FrontmatterBlockProps): react_jsx_runtime.JSX.Element;
13
+ declare function FrontmatterBlock({ block, className }: FrontmatterBlockProps): react.JSX.Element;
15
14
 
16
15
  export { FrontmatterBlock, type FrontmatterBlockProps };
@@ -1,9 +1,8 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { HeaderBlock as HeaderBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type HeaderBlockProps = BlockRendererProps<HeaderBlock$1>;
7
- declare function HeaderBlock({ block, className }: HeaderBlockProps): react_jsx_runtime.JSX.Element;
6
+ declare function HeaderBlock({ block, className }: HeaderBlockProps): react.JSX.Element;
8
7
 
9
8
  export { HeaderBlock, type HeaderBlockProps };
@@ -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,9 +1,8 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { HorizontalRuleBlock as HorizontalRuleBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type HorizontalRuleBlockProps = BlockRendererProps<HorizontalRuleBlock$1>;
7
- declare function HorizontalRuleBlock({ block, className }: HorizontalRuleBlockProps): react_jsx_runtime.JSX.Element;
6
+ declare function HorizontalRuleBlock({ block, className }: HorizontalRuleBlockProps): react.JSX.Element;
8
7
 
9
8
  export { HorizontalRuleBlock, type HorizontalRuleBlockProps };
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { HtmlBlock as HtmlBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type HtmlBlockProps = BlockRendererProps<HtmlBlock$1>;
7
6
  interface SanitizedHtmlBlockProps extends HtmlBlockProps {
@@ -19,13 +18,13 @@ interface SanitizedHtmlBlockProps extends HtmlBlockProps {
19
18
  * a sanitization step override the `html` renderer key to inject trusted
20
19
  * markup.
21
20
  */
22
- declare function HtmlBlock({ block, className }: HtmlBlockProps): react_jsx_runtime.JSX.Element;
21
+ declare function HtmlBlock({ block, className }: HtmlBlockProps): react.JSX.Element;
23
22
  /**
24
23
  * Opt-in HTML renderer for consumers that want sanitized HTML injection.
25
24
  *
26
25
  * `HtmlBlock` remains the safe default and renders source as text. Use this
27
26
  * renderer as an explicit `html` override when your surface supports HTML.
28
27
  */
29
- declare function SanitizedHtmlBlock({ block, className, rawHtml, allowDataImages, }: SanitizedHtmlBlockProps): react_jsx_runtime.JSX.Element;
28
+ declare function SanitizedHtmlBlock({ block, className, rawHtml, allowDataImages, }: SanitizedHtmlBlockProps): react.JSX.Element;
30
29
 
31
30
  export { HtmlBlock, type HtmlBlockProps, SanitizedHtmlBlock, type SanitizedHtmlBlockProps };
@@ -26,7 +26,6 @@ export { ParagraphBlock, ParagraphBlockProps } from './paragraph/index.js';
26
26
  export { SpoilerBlock, SpoilerBlockProps } from './spoiler/index.js';
27
27
  export { TableBlock, TableBlockProps } from './table/index.js';
28
28
  export { TaskListBlock, TaskListBlockProps } from './task-list/index.js';
29
- import 'react/jsx-runtime';
29
+ import 'react';
30
30
  import '@nuucognition/ncm';
31
31
  import '../renderers-C5f41FCy.js';
32
- import 'react';
@@ -506,9 +506,10 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
506
506
  case "image": {
507
507
  const src = config.inline?.resolveAssetPath?.(token.src) ?? token.src;
508
508
  return /* @__PURE__ */ jsx(
509
- "img",
509
+ EmbedImage,
510
510
  {
511
- "data-ncm-token": "image",
511
+ attrs: { "data-ncm-token": "image" },
512
+ target: token.src,
512
513
  src,
513
514
  alt: token.alt,
514
515
  title: token.title
@@ -542,10 +543,13 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
542
543
  }
543
544
  if (embedType === "image") {
544
545
  return /* @__PURE__ */ jsx(
545
- "img",
546
+ EmbedImage,
546
547
  {
547
- "data-ncm-token": "wiki_embed",
548
- "data-ncm-wikiembed-type": embedType,
548
+ attrs: {
549
+ "data-ncm-token": "wiki_embed",
550
+ "data-ncm-wikiembed-type": embedType
551
+ },
552
+ target: token.target,
549
553
  src: url,
550
554
  alt: token.display ?? token.target,
551
555
  className: config.embeddings?.imageClassName
@@ -576,6 +580,22 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
576
580
  }
577
581
  );
578
582
  }
583
+ const onEmbedClick = config.embeddings?.onEmbedClick;
584
+ if (onEmbedClick) {
585
+ const handleClick = (e) => {
586
+ onEmbedClick(token.target, result, e);
587
+ };
588
+ return /* @__PURE__ */ jsx(
589
+ "button",
590
+ {
591
+ type: "button",
592
+ "data-ncm-token": "wiki_embed",
593
+ "data-ncm-wikiembed-type": embedType,
594
+ onClick: handleClick,
595
+ children: token.display ?? token.target
596
+ }
597
+ );
598
+ }
579
599
  return /* @__PURE__ */ jsx(
580
600
  "a",
581
601
  {
@@ -594,6 +614,31 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
594
614
  return null;
595
615
  }
596
616
  }
617
+ function EmbedImage({ attrs, target, src, alt, title, className }) {
618
+ const config = useNcmConfig();
619
+ const Fallback = config.embeddings?.renderImageError;
620
+ const [failedSrc, setFailedSrc] = useState(null);
621
+ useEffect(() => {
622
+ setFailedSrc(null);
623
+ }, [src]);
624
+ if (!Fallback) {
625
+ return /* @__PURE__ */ jsx("img", { ...attrs, src, alt, title, className });
626
+ }
627
+ if (failedSrc === src) {
628
+ return /* @__PURE__ */ jsx(Fallback, { target, src, alt, retry: () => setFailedSrc(null) });
629
+ }
630
+ return /* @__PURE__ */ jsx(
631
+ "img",
632
+ {
633
+ ...attrs,
634
+ src,
635
+ alt,
636
+ title,
637
+ className,
638
+ onError: () => setFailedSrc(src)
639
+ }
640
+ );
641
+ }
597
642
  function renderReadingText(content, opts) {
598
643
  if (!content) return /* @__PURE__ */ jsx(Fragment, { children: content });
599
644
  const { bionic = false, beeline = false } = opts;
@@ -629,7 +674,7 @@ function renderReadingText(content, opts) {
629
674
  return /* @__PURE__ */ jsx(Fragment, { children: pieces });
630
675
  }
631
676
  function BlockquoteBlock({ block, className }) {
632
- const lines = block.content.split("\n").filter((line) => line.trim() !== "");
677
+ const lines = block.content.split("\n");
633
678
  return /* @__PURE__ */ jsx(
634
679
  "blockquote",
635
680
  {
@@ -639,7 +684,7 @@ function BlockquoteBlock({ block, className }) {
639
684
  "data-block-id": block.id,
640
685
  "data-ncm-blockquote": "",
641
686
  className,
642
- children: lines.length <= 1 ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : lines.map((line, index) => /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx(InlineContent, { content: line }) }, index))
687
+ 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))
643
688
  }
644
689
  );
645
690
  }
@@ -779,7 +824,7 @@ function CodeBlock({ block, className }) {
779
824
  "data-ncm-language": block.language,
780
825
  className: cn("relative", className),
781
826
  children: [
782
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
827
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
783
828
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
784
829
  languageLabel
785
830
  ]
@@ -798,7 +843,7 @@ function CodeBlock({ block, className }) {
798
843
  "data-ncm-language": block.language,
799
844
  className: cn("relative", className),
800
845
  children: [
801
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
846
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
802
847
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
803
848
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
804
849
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -1273,10 +1318,12 @@ function LinkBlock({ block, className }) {
1273
1318
  function ListBlock({ block, className }) {
1274
1319
  const isOrdered = block.type === "list_ordered";
1275
1320
  const Tag = isOrdered ? "ol" : "ul";
1321
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1276
1322
  return /* @__PURE__ */ jsx(
1277
1323
  Tag,
1278
1324
  {
1279
1325
  role: "list",
1326
+ start,
1280
1327
  "data-ncm-block": block.id,
1281
1328
  "data-ncm-stable": block.stableId,
1282
1329
  "data-ncm-type": block.type,
@@ -1288,6 +1335,9 @@ function ListBlock({ block, className }) {
1288
1335
  }
1289
1336
  );
1290
1337
  }
1338
+ function ItemContent({ content }) {
1339
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1340
+ }
1291
1341
  function nestedItemIdKey(id) {
1292
1342
  if (!id) {
1293
1343
  return void 0;
@@ -1304,7 +1354,7 @@ function ListItems({ items, itemIds, ordered }) {
1304
1354
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1305
1355
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1306
1356
  if (typeof item === "string") {
1307
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1357
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1308
1358
  }
1309
1359
  if (isTypedNestedList(item)) {
1310
1360
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1314,7 +1364,7 @@ function ListItems({ items, itemIds, ordered }) {
1314
1364
  const content = typeof first === "string" ? first : "";
1315
1365
  const nestedContent = processNestedItems(rest, ordered);
1316
1366
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1317
- /* @__PURE__ */ jsx(InlineContent, { content }),
1367
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1318
1368
  nestedContent
1319
1369
  ] }, key);
1320
1370
  }
@@ -1473,6 +1523,7 @@ function TableBlock({ block, className }) {
1473
1523
  function TaskItems({ items }) {
1474
1524
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1475
1525
  const status = item.checked ? "Completed" : "Incomplete";
1526
+ const text = serializeInlineContent(item.content);
1476
1527
  return /* @__PURE__ */ jsxs(
1477
1528
  "li",
1478
1529
  {
@@ -1499,7 +1550,7 @@ function TaskItems({ items }) {
1499
1550
  ":",
1500
1551
  " "
1501
1552
  ] }),
1502
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1553
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1503
1554
  ] })
1504
1555
  ] }),
1505
1556
  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 { LatexDisplayBlock as LatexDisplayBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type LatexDisplayBlockProps = BlockRendererProps<LatexDisplayBlock$1>;
7
- declare function LatexDisplayBlock({ block, className }: LatexDisplayBlockProps): react_jsx_runtime.JSX.Element;
6
+ declare function LatexDisplayBlock({ block, className }: LatexDisplayBlockProps): react.JSX.Element;
8
7
 
9
8
  export { LatexDisplayBlock, type LatexDisplayBlockProps };
@@ -1,7 +1,6 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { LinkBlock as LinkBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type LinkBlockProps = BlockRendererProps<LinkBlock$1>;
7
6
  /**
@@ -9,6 +8,6 @@ type LinkBlockProps = BlockRendererProps<LinkBlock$1>;
9
8
  * for card-style rendering. Default is a block-level anchor; override the `link`
10
9
  * renderer key for rich link previews.
11
10
  */
12
- declare function LinkBlock({ block, className }: LinkBlockProps): react_jsx_runtime.JSX.Element;
11
+ declare function LinkBlock({ block, className }: LinkBlockProps): react.JSX.Element;
13
12
 
14
13
  export { LinkBlock, type LinkBlockProps };
@@ -1,9 +1,8 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { ListBlock as ListBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type ListBlockProps = BlockRendererProps<ListBlock$1>;
7
- declare function ListBlock({ block, className }: ListBlockProps): react_jsx_runtime.JSX.Element;
6
+ declare function ListBlock({ block, className }: ListBlockProps): react.JSX.Element;
8
7
 
9
8
  export { ListBlock, type ListBlockProps };