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

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 (74) 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 +79 -23
  4. package/dist/blocks/aside/index.d.ts +2 -3
  5. package/dist/blocks/aside/index.js +79 -23
  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/chart/index.js +2 -1
  11. package/dist/blocks/code/index.d.ts +2 -3
  12. package/dist/blocks/code/index.js +2 -2
  13. package/dist/blocks/container/index.d.ts +2 -3
  14. package/dist/blocks/container/index.js +50 -5
  15. package/dist/blocks/custom-code/index.d.ts +2 -3
  16. package/dist/blocks/custom-code/index.js +1 -1
  17. package/dist/blocks/dataview/index.d.ts +2 -3
  18. package/dist/blocks/dataview/index.js +2 -1
  19. package/dist/blocks/definition/index.d.ts +2 -3
  20. package/dist/blocks/definition/index.js +79 -23
  21. package/dist/blocks/embed/index.d.ts +2 -3
  22. package/dist/blocks/embedding/index.d.ts +2 -3
  23. package/dist/blocks/embedding/index.js +50 -5
  24. package/dist/blocks/figure/index.d.ts +2 -3
  25. package/dist/blocks/figure/index.js +50 -5
  26. package/dist/blocks/footnote/index.d.ts +2 -3
  27. package/dist/blocks/footnote/index.js +79 -23
  28. package/dist/blocks/frontmatter/index.d.ts +2 -3
  29. package/dist/blocks/header/index.d.ts +2 -3
  30. package/dist/blocks/header/index.js +50 -5
  31. package/dist/blocks/horizontal-rule/index.d.ts +2 -3
  32. package/dist/blocks/html/index.d.ts +3 -4
  33. package/dist/blocks/html/index.js +2 -1
  34. package/dist/blocks/index.d.ts +1 -2
  35. package/dist/blocks/index.js +79 -23
  36. package/dist/blocks/latex/index.d.ts +2 -3
  37. package/dist/blocks/latex/index.js +2 -2
  38. package/dist/blocks/link/index.d.ts +2 -3
  39. package/dist/blocks/list/index.d.ts +2 -3
  40. package/dist/blocks/list/index.js +57 -7
  41. package/dist/blocks/math/index.d.ts +2 -3
  42. package/dist/blocks/math/index.js +3 -2
  43. package/dist/blocks/mermaid/index.d.ts +2 -3
  44. package/dist/blocks/mermaid/index.js +2 -1
  45. package/dist/blocks/page-breaker/index.d.ts +2 -3
  46. package/dist/blocks/paragraph/index.d.ts +2 -3
  47. package/dist/blocks/paragraph/index.js +50 -5
  48. package/dist/blocks/spoiler/index.d.ts +2 -3
  49. package/dist/blocks/spoiler/index.js +79 -23
  50. package/dist/blocks/table/index.d.ts +2 -3
  51. package/dist/blocks/table/index.js +51 -6
  52. package/dist/blocks/task-list/index.d.ts +2 -3
  53. package/dist/blocks/task-list/index.js +52 -6
  54. package/dist/components/index.d.ts +34 -4
  55. package/dist/components/index.js +117 -25
  56. package/dist/components/ncm-block.d.ts +2 -3
  57. package/dist/components/ncm-block.js +79 -23
  58. package/dist/components/ncm-document.d.ts +4 -4
  59. package/dist/components/ncm-document.js +79 -23
  60. package/dist/context/index.d.ts +2 -3
  61. package/dist/hooks/index.d.ts +1 -2
  62. package/dist/hooks/index.js +79 -23
  63. package/dist/hooks/use-block-renderer.js +79 -23
  64. package/dist/hooks/use-ncm-config.d.ts +1 -2
  65. package/dist/index.d.ts +3 -4
  66. package/dist/index.js +118 -26
  67. package/dist/inline/index.d.ts +4 -4
  68. package/dist/inline/index.js +51 -6
  69. package/dist/lib/defaults.js +79 -23
  70. package/dist/{references-Bs5wJybr.d.ts → references-BYW5pnj_.d.ts} +4 -4
  71. package/dist/styles/nuu.css +329 -44
  72. package/dist/styles/paper.css +62 -1
  73. package/dist/{use-ncm-config-D0doMYTH.d.ts → use-ncm-config-CnntcShj.d.ts} +55 -4
  74. package/package.json +5 -5
@@ -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
  }
@@ -691,7 +736,8 @@ function ChartBlock({ block, className }) {
691
736
  "data-ncm-chart": "",
692
737
  "data-ncm-chart-type": block.chartType ?? "unknown",
693
738
  className: cn(
694
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
739
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
740
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
695
741
  className
696
742
  ),
697
743
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -816,7 +862,7 @@ function CodeBlock({ block, className }) {
816
862
  "data-ncm-language": block.language,
817
863
  className: cn("relative", className),
818
864
  children: [
819
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
865
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
820
866
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
821
867
  languageLabel
822
868
  ]
@@ -835,7 +881,7 @@ function CodeBlock({ block, className }) {
835
881
  "data-ncm-language": block.language,
836
882
  className: cn("relative", className),
837
883
  children: [
838
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
884
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
839
885
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
840
886
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
841
887
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -871,7 +917,8 @@ function DataviewBlock({ block, className }) {
871
917
  "data-ncm-dataview": "",
872
918
  "data-ncm-query-type": block.queryType,
873
919
  className: cn(
874
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
920
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
921
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
875
922
  className
876
923
  ),
877
924
  children: /* @__PURE__ */ jsx("code", { children: block.query })
@@ -1210,7 +1257,8 @@ function HtmlBlock({ block, className }) {
1210
1257
  "data-block-id": block.id,
1211
1258
  "data-ncm-html": "",
1212
1259
  className: cn(
1213
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1260
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
1261
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1214
1262
  className
1215
1263
  ),
1216
1264
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1248,7 +1296,7 @@ function LatexDisplayBlock({ block, className }) {
1248
1296
  "data-ncm-type": block.type,
1249
1297
  "data-block-id": block.id,
1250
1298
  "data-ncm-latex-display": "",
1251
- className: cn("overflow-x-auto", className),
1299
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1252
1300
  dangerouslySetInnerHTML: { __html: html }
1253
1301
  }
1254
1302
  );
@@ -1263,7 +1311,7 @@ function LatexDisplayBlock({ block, className }) {
1263
1311
  "data-ncm-type": block.type,
1264
1312
  "data-block-id": block.id,
1265
1313
  "data-ncm-latex-display": "",
1266
- className: cn("overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
1314
+ className: cn("overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
1267
1315
  children: /* @__PURE__ */ jsx("code", { children: block.content })
1268
1316
  }
1269
1317
  );
@@ -1287,10 +1335,12 @@ function LinkBlock({ block, className }) {
1287
1335
  function ListBlock({ block, className }) {
1288
1336
  const isOrdered = block.type === "list_ordered";
1289
1337
  const Tag = isOrdered ? "ol" : "ul";
1338
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1290
1339
  return /* @__PURE__ */ jsx(
1291
1340
  Tag,
1292
1341
  {
1293
1342
  role: "list",
1343
+ start,
1294
1344
  "data-ncm-block": block.id,
1295
1345
  "data-ncm-stable": block.stableId,
1296
1346
  "data-ncm-type": block.type,
@@ -1302,6 +1352,9 @@ function ListBlock({ block, className }) {
1302
1352
  }
1303
1353
  );
1304
1354
  }
1355
+ function ItemContent({ content }) {
1356
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1357
+ }
1305
1358
  function nestedItemIdKey(id) {
1306
1359
  if (!id) {
1307
1360
  return void 0;
@@ -1318,7 +1371,7 @@ function ListItems({ items, itemIds, ordered }) {
1318
1371
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1319
1372
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1320
1373
  if (typeof item === "string") {
1321
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1374
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1322
1375
  }
1323
1376
  if (isTypedNestedList(item)) {
1324
1377
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1328,7 +1381,7 @@ function ListItems({ items, itemIds, ordered }) {
1328
1381
  const content = typeof first === "string" ? first : "";
1329
1382
  const nestedContent = processNestedItems(rest, ordered);
1330
1383
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1331
- /* @__PURE__ */ jsx(InlineContent, { content }),
1384
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1332
1385
  nestedContent
1333
1386
  ] }, key);
1334
1387
  }
@@ -1378,7 +1431,7 @@ function MathBlock({ block, className }) {
1378
1431
  "data-ncm-type": block.type,
1379
1432
  "data-block-id": block.id,
1380
1433
  "data-ncm-math": "",
1381
- className: cn("overflow-x-auto", className),
1434
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1382
1435
  dangerouslySetInnerHTML: { __html: html }
1383
1436
  }
1384
1437
  );
@@ -1394,7 +1447,8 @@ function MathBlock({ block, className }) {
1394
1447
  "data-block-id": block.id,
1395
1448
  "data-ncm-math": "",
1396
1449
  className: cn(
1397
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1450
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
1451
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1398
1452
  className
1399
1453
  ),
1400
1454
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1412,7 +1466,8 @@ function MermaidBlock({ block, className }) {
1412
1466
  "data-ncm-mermaid": "",
1413
1467
  "data-ncm-diagram-type": block.diagramType,
1414
1468
  className: cn(
1415
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1469
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
1470
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1416
1471
  className
1417
1472
  ),
1418
1473
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1457,7 +1512,7 @@ function TableBlock({ block, className }) {
1457
1512
  "data-ncm-type": block.type,
1458
1513
  "data-block-id": block.id,
1459
1514
  "data-ncm-table": "",
1460
- className: cn("w-full overflow-x-auto", className),
1515
+ className: cn("w-full overflow-x-auto overflow-y-hidden", className),
1461
1516
  children: /* @__PURE__ */ jsxs("table", { role: "table", "data-ncm-table-element": "", children: [
1462
1517
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { "data-ncm-table-row": "", children: block.headers.map((header, index) => /* @__PURE__ */ jsx("th", { "data-ncm-table-header": "", children: /* @__PURE__ */ jsx(InlineContent, { content: header }) }, index)) }) }),
1463
1518
  /* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => {
@@ -1471,6 +1526,7 @@ function TableBlock({ block, className }) {
1471
1526
  function TaskItems({ items }) {
1472
1527
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1473
1528
  const status = item.checked ? "Completed" : "Incomplete";
1529
+ const text = serializeInlineContent(item.content);
1474
1530
  return /* @__PURE__ */ jsxs(
1475
1531
  "li",
1476
1532
  {
@@ -1497,7 +1553,7 @@ function TaskItems({ items }) {
1497
1553
  ":",
1498
1554
  " "
1499
1555
  ] }),
1500
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1556
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1501
1557
  ] })
1502
1558
  ] }),
1503
1559
  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
@@ -1542,7 +1598,7 @@ function FallbackBlock({ block, className }) {
1542
1598
  "data-block-id": block.id,
1543
1599
  "data-ncm-fallback": "",
1544
1600
  className: cn(
1545
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1601
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1546
1602
  className
1547
1603
  )
1548
1604
  },
@@ -1598,7 +1654,7 @@ function CustomCodeBlock({ block, className }) {
1598
1654
  "data-block-id": block.id,
1599
1655
  "data-ncm-custom-code": "",
1600
1656
  "data-ncm-language": block.language,
1601
- className: cn("overflow-x-auto", className),
1657
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1602
1658
  children: [
1603
1659
  /* @__PURE__ */ jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: block.language }),
1604
1660
  /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: block.content }) })
@@ -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;
@@ -604,7 +649,7 @@ function TableBlock({ block, className }) {
604
649
  "data-ncm-type": block.type,
605
650
  "data-block-id": block.id,
606
651
  "data-ncm-table": "",
607
- className: cn("w-full overflow-x-auto", className),
652
+ className: cn("w-full overflow-x-auto overflow-y-hidden", className),
608
653
  children: /* @__PURE__ */ jsxs("table", { role: "table", "data-ncm-table-element": "", children: [
609
654
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { "data-ncm-table-row": "", children: block.headers.map((header, index) => /* @__PURE__ */ jsx("th", { "data-ncm-table-header": "", children: /* @__PURE__ */ jsx(InlineContent, { content: header }) }, index)) }) }),
610
655
  /* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => {
@@ -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 };
@@ -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 };