@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
package/README.md CHANGED
@@ -102,6 +102,81 @@ import { NcmDocument, SanitizedHtmlBlock } from "@nuucognition/ncm-ui"
102
102
  markup. Keep `HtmlBlock` as the default for untrusted documents. Use
103
103
  `SanitizedHtmlBlock` only when the surface intentionally supports HTML.
104
104
 
105
+ ## Embeds
106
+
107
+ `![[target]]` and `![alt](url)` render through `EmbeddingsConfig` on `NcmConfig`.
108
+ Everything below is optional; a config that omits a key gets the behaviour the
109
+ package has always had.
110
+
111
+ | Key | Effect |
112
+ |---|---|
113
+ | `resolveUrl(target, embedType)` | Turn an authored target into a fetchable URL. |
114
+ | `renderers` | Per-embed-type block renderers. |
115
+ | `imageClassName` / `videoClassName` / `audioClassName` | Class names on the media elements. |
116
+ | `renderImageError` | Draw a failed image instead of leaving the browser's broken-image box. |
117
+ | `onEmbedClick` | Make a non-media embed a real control instead of an `<a href>`. |
118
+
119
+ ### Failed images
120
+
121
+ Whether an `<img>` actually loads is only learned by trying, and what to say
122
+ about the failure is the host's vocabulary — a mesh embedder can retry against
123
+ its own blob cache; a static-site embedder has nothing to retry.
124
+
125
+ ```tsx
126
+ <NcmProvider config={{
127
+ embeddings: {
128
+ renderImageError: ({ target, retry }) => (
129
+ <button type="button" onClick={() => { myCache.refresh(target); retry() }}>
130
+ {target} didn’t load — retry
131
+ </button>
132
+ ),
133
+ },
134
+ }}>
135
+ ```
136
+
137
+ **Opt-in, strictly.** With no renderer supplied the `<img>` carries no `onError`
138
+ handler at all, so the emitted DOM is identical to what it has always been — not
139
+ merely visually identical. `retry` re-keys the element, so it is a real second
140
+ request rather than the browser replaying its cached failure.
141
+
142
+ ### Non-media embeds
143
+
144
+ An `![[target]]` with no player — an embedded document, or any unrecognised type
145
+ — renders as `<a href={resolveUrl(...)}>`. That is only honest when the target
146
+ really has a URL. In a title-addressed mesh a document does not: the host
147
+ navigates in its own state, so the href ends up being the raw target.
148
+
149
+ Supply `onEmbedClick` and the same content renders as a `<button>` instead,
150
+ claiming nothing about URLs — the shape `inline.onWikiLinkClick` already
151
+ produces for a wikilink with no href.
152
+
153
+ ```tsx
154
+ <NcmProvider config={{
155
+ embeddings: {
156
+ onEmbedClick: (target, result) => openDocument(result?.resolved?.title ?? target),
157
+ },
158
+ }}>
159
+ ```
160
+
161
+ ### Reference states in the shipped themes
162
+
163
+ `nuu.css` and `paper.css` paint three states of a wikilink or embed, and they
164
+ mean the same thing in both themes:
165
+
166
+ | State | Treatment | Why |
167
+ |---|---|---|
168
+ | resolved | link colour, solid underline | it goes somewhere |
169
+ | `missing` | muted foreground, **dashed** | not an error — a link to a document that is not in this mesh is very often a plan. Matches Obsidian, where an unresolved link is the link colour faded, never red. |
170
+ | `ambiguous` | warning amber, **dotted** | several targets match; something to decide, nothing has failed |
171
+
172
+ Red is reserved for genuine failure — an embed whose bytes did not arrive.
173
+
174
+ > **Changed in the 513 batch:** `ambiguous` used to be painted with
175
+ > `--fire-text`/`--destructive`, i.e. red, in both themes. That is a deliberate
176
+ > visual change for every embedder. It was made because the editor surface in
177
+ > the same product paints red for a *missing* link, so one hue carried two
178
+ > different facts depending on which mode a reader was in.
179
+
105
180
  ## Math And Code Rendering
106
181
 
107
182
  KaTeX is lazy-loaded and memoized, so documents without math do not pay the
@@ -116,8 +191,23 @@ pnpm --filter @nuucognition/ncm-ui lint
116
191
  pnpm --filter @nuucognition/ncm-ui typecheck
117
192
  pnpm --filter @nuucognition/ncm-ui build
118
193
  pnpm --filter @nuucognition/ncm-ui test
194
+ pnpm --filter @nuucognition/ncm-ui exec tsx scripts/render-compat.mjs
119
195
  ```
120
196
 
197
+ `render-compat.mjs` is the **published-API compatibility gate**. This package
198
+ has backward-compatibility obligations, so an added optional callback has one
199
+ test that matters: a consumer that does not pass it must get the same *bytes*.
200
+ The script renders fixed fixtures under a bare config, under the shape a real
201
+ host passes today, and under a config with every option supplied, and compares
202
+ against hand-written expected markup. The expectations are literal strings on
203
+ purpose — a snapshot a worker can re-bless is not a gate. It also mounts into
204
+ jsdom and dispatches a real `error` event, because a check written only against
205
+ server markup would report the failure path working while it was unreachable.
206
+
207
+ Note that `vitest.config.ts` pins `NODE_ENV=test`. React's production build does
208
+ not export `act`, so a shell that exports `NODE_ENV=production` makes four tests
209
+ fail for reasons that have nothing to do with this package.
210
+
121
211
  The root NCM gate runs both `@nuucognition/ncm-tests` and `@nuucognition/ncm-ui`:
122
212
 
123
213
  ```bash
@@ -1,13 +1,12 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { AdmonitionBlock as AdmonitionBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type AdmonitionBlockProps = BlockRendererProps<AdmonitionBlock$1>;
7
6
  /**
8
7
  * Admonition (callout) renderer. Collapsible admonitions render as `<details>`;
9
8
  * static ones as a titled region. Child blocks render through `NcmBlock`.
10
9
  */
11
- declare function AdmonitionBlock({ block, className }: AdmonitionBlockProps): react_jsx_runtime.JSX.Element;
10
+ declare function AdmonitionBlock({ block, className }: AdmonitionBlockProps): react.JSX.Element;
12
11
 
13
12
  export { AdmonitionBlock, type AdmonitionBlockProps };
@@ -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
  }
@@ -654,7 +699,8 @@ function ChartBlock({ block, className }) {
654
699
  "data-ncm-chart": "",
655
700
  "data-ncm-chart-type": block.chartType ?? "unknown",
656
701
  className: cn(
657
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
702
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
703
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
658
704
  className
659
705
  ),
660
706
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -779,7 +825,7 @@ function CodeBlock({ block, className }) {
779
825
  "data-ncm-language": block.language,
780
826
  className: cn("relative", className),
781
827
  children: [
782
- codeConfig.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
828
+ codeConfig.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
783
829
  /* @__PURE__ */ jsx(CustomRenderer, { code: block.content, language: block.language }),
784
830
  languageLabel
785
831
  ]
@@ -798,7 +844,7 @@ function CodeBlock({ block, className }) {
798
844
  "data-ncm-language": block.language,
799
845
  className: cn("relative", className),
800
846
  children: [
801
- codeConfig?.copyButton !== false && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
847
+ codeConfig?.copyButton === true && /* @__PURE__ */ jsx(CopyButton, { content: block.content }),
802
848
  /* @__PURE__ */ jsx("pre", { "data-ncm-code-pre": "", children: /* @__PURE__ */ jsxs("div", { className: "flex", children: [
803
849
  codeConfig?.lineNumbers && /* @__PURE__ */ jsx(LineNumbers, { count: lineCount }),
804
850
  /* @__PURE__ */ jsx("code", { "data-ncm-code": "", className: "flex-1", children: /* @__PURE__ */ jsx(DefaultShikiRenderer, { code: block.content, language: block.language }) })
@@ -834,7 +880,8 @@ function DataviewBlock({ block, className }) {
834
880
  "data-ncm-dataview": "",
835
881
  "data-ncm-query-type": block.queryType,
836
882
  className: cn(
837
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
883
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
884
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
838
885
  className
839
886
  ),
840
887
  children: /* @__PURE__ */ jsx("code", { children: block.query })
@@ -1173,7 +1220,8 @@ function HtmlBlock({ block, className }) {
1173
1220
  "data-block-id": block.id,
1174
1221
  "data-ncm-html": "",
1175
1222
  className: cn(
1176
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1223
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
1224
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1177
1225
  className
1178
1226
  ),
1179
1227
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1211,7 +1259,7 @@ function LatexDisplayBlock({ block, className }) {
1211
1259
  "data-ncm-type": block.type,
1212
1260
  "data-block-id": block.id,
1213
1261
  "data-ncm-latex-display": "",
1214
- className: cn("overflow-x-auto", className),
1262
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1215
1263
  dangerouslySetInnerHTML: { __html: html }
1216
1264
  }
1217
1265
  );
@@ -1226,7 +1274,7 @@ function LatexDisplayBlock({ block, className }) {
1226
1274
  "data-ncm-type": block.type,
1227
1275
  "data-block-id": block.id,
1228
1276
  "data-ncm-latex-display": "",
1229
- className: cn("overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
1277
+ className: cn("overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
1230
1278
  children: /* @__PURE__ */ jsx("code", { children: block.content })
1231
1279
  }
1232
1280
  );
@@ -1250,10 +1298,12 @@ function LinkBlock({ block, className }) {
1250
1298
  function ListBlock({ block, className }) {
1251
1299
  const isOrdered = block.type === "list_ordered";
1252
1300
  const Tag = isOrdered ? "ol" : "ul";
1301
+ const start = isOrdered && typeof block.marker === "number" && block.marker !== 1 ? block.marker : void 0;
1253
1302
  return /* @__PURE__ */ jsx(
1254
1303
  Tag,
1255
1304
  {
1256
1305
  role: "list",
1306
+ start,
1257
1307
  "data-ncm-block": block.id,
1258
1308
  "data-ncm-stable": block.stableId,
1259
1309
  "data-ncm-type": block.type,
@@ -1265,6 +1315,9 @@ function ListBlock({ block, className }) {
1265
1315
  }
1266
1316
  );
1267
1317
  }
1318
+ function ItemContent({ content }) {
1319
+ return content.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" });
1320
+ }
1268
1321
  function nestedItemIdKey(id) {
1269
1322
  if (!id) {
1270
1323
  return void 0;
@@ -1281,7 +1334,7 @@ function ListItems({ items, itemIds, ordered }) {
1281
1334
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item, index) => {
1282
1335
  const key = nestedItemIdKey(itemIds?.[index]) ?? `item-${index}`;
1283
1336
  if (typeof item === "string") {
1284
- return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(InlineContent, { content: item }) }, key);
1337
+ return /* @__PURE__ */ jsx("li", { "data-ncm-list-item": "", children: /* @__PURE__ */ jsx(ItemContent, { content: item }) }, key);
1285
1338
  }
1286
1339
  if (isTypedNestedList(item)) {
1287
1340
  return /* @__PURE__ */ jsx(NestedTypedList, { list: item }, key);
@@ -1291,7 +1344,7 @@ function ListItems({ items, itemIds, ordered }) {
1291
1344
  const content = typeof first === "string" ? first : "";
1292
1345
  const nestedContent = processNestedItems(rest, ordered);
1293
1346
  return /* @__PURE__ */ jsxs("li", { "data-ncm-list-item": "", children: [
1294
- /* @__PURE__ */ jsx(InlineContent, { content }),
1347
+ /* @__PURE__ */ jsx(ItemContent, { content }),
1295
1348
  nestedContent
1296
1349
  ] }, key);
1297
1350
  }
@@ -1341,7 +1394,7 @@ function MathBlock({ block, className }) {
1341
1394
  "data-ncm-type": block.type,
1342
1395
  "data-block-id": block.id,
1343
1396
  "data-ncm-math": "",
1344
- className: cn("overflow-x-auto", className),
1397
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1345
1398
  dangerouslySetInnerHTML: { __html: html }
1346
1399
  }
1347
1400
  );
@@ -1357,7 +1410,8 @@ function MathBlock({ block, className }) {
1357
1410
  "data-block-id": block.id,
1358
1411
  "data-ncm-math": "",
1359
1412
  className: cn(
1360
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1413
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
1414
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1361
1415
  className
1362
1416
  ),
1363
1417
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1375,7 +1429,8 @@ function MermaidBlock({ block, className }) {
1375
1429
  "data-ncm-mermaid": "",
1376
1430
  "data-ncm-diagram-type": block.diagramType,
1377
1431
  className: cn(
1378
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1432
+ // `overflow-y-hidden` pairs with `overflow-x-auto` on purpose see the note in `lib/defaults.ts`.
1433
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1379
1434
  className
1380
1435
  ),
1381
1436
  children: /* @__PURE__ */ jsx("code", { children: block.content })
@@ -1436,7 +1491,7 @@ function TableBlock({ block, className }) {
1436
1491
  "data-ncm-type": block.type,
1437
1492
  "data-block-id": block.id,
1438
1493
  "data-ncm-table": "",
1439
- className: cn("w-full overflow-x-auto", className),
1494
+ className: cn("w-full overflow-x-auto overflow-y-hidden", className),
1440
1495
  children: /* @__PURE__ */ jsxs("table", { role: "table", "data-ncm-table-element": "", children: [
1441
1496
  /* @__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)) }) }),
1442
1497
  /* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => {
@@ -1450,6 +1505,7 @@ function TableBlock({ block, className }) {
1450
1505
  function TaskItems({ items }) {
1451
1506
  return /* @__PURE__ */ jsx(Fragment, { children: items.map((item) => {
1452
1507
  const status = item.checked ? "Completed" : "Incomplete";
1508
+ const text = serializeInlineContent(item.content);
1453
1509
  return /* @__PURE__ */ jsxs(
1454
1510
  "li",
1455
1511
  {
@@ -1476,7 +1532,7 @@ function TaskItems({ items }) {
1476
1532
  ":",
1477
1533
  " "
1478
1534
  ] }),
1479
- /* @__PURE__ */ jsx(InlineContent, { content: serializeInlineContent(item.content) })
1535
+ text.length > 0 ? /* @__PURE__ */ jsx(InlineContent, { content: text }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xA0" })
1480
1536
  ] })
1481
1537
  ] }),
1482
1538
  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
@@ -1521,7 +1577,7 @@ function FallbackBlock({ block, className }) {
1521
1577
  "data-block-id": block.id,
1522
1578
  "data-ncm-fallback": "",
1523
1579
  className: cn(
1524
- "overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1580
+ "overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
1525
1581
  className
1526
1582
  )
1527
1583
  },
@@ -1577,7 +1633,7 @@ function CustomCodeBlock({ block, className }) {
1577
1633
  "data-block-id": block.id,
1578
1634
  "data-ncm-custom-code": "",
1579
1635
  "data-ncm-language": block.language,
1580
- className: cn("overflow-x-auto", className),
1636
+ className: cn("overflow-x-auto overflow-y-hidden", className),
1581
1637
  children: [
1582
1638
  /* @__PURE__ */ jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: block.language }),
1583
1639
  /* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: block.content }) })
@@ -1,13 +1,12 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
1
+ import * as react from 'react';
2
2
  import { AsideBlock as AsideBlock$1 } from '@nuucognition/ncm';
3
3
  import { a as BlockRendererProps } from '../../renderers-C5f41FCy.js';
4
- import 'react';
5
4
 
6
5
  type AsideBlockProps = BlockRendererProps<AsideBlock$1>;
7
6
  /**
8
7
  * Aside renderer — parenthetical / sidebar content wrapped in `(( ))`. Child
9
8
  * blocks render through `NcmBlock`.
10
9
  */
11
- declare function AsideBlock({ block, className }: AsideBlockProps): react_jsx_runtime.JSX.Element;
10
+ declare function AsideBlock({ block, className }: AsideBlockProps): react.JSX.Element;
12
11
 
13
12
  export { AsideBlock, type AsideBlockProps };