@nuucognition/ncm-ui 0.1.1-beta.0 → 0.1.1-beta.2
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.
- package/dist/blocks/admonition/index.js +118 -46
- package/dist/blocks/aside/index.js +118 -46
- package/dist/blocks/blockquote/index.d.ts +7 -5
- package/dist/blocks/blockquote/index.js +1218 -36
- package/dist/blocks/chart/index.js +2 -1
- package/dist/blocks/container/index.js +72 -31
- package/dist/blocks/custom-code/index.js +1 -1
- package/dist/blocks/dataview/index.js +2 -1
- package/dist/blocks/definition/index.js +117 -45
- package/dist/blocks/embedding/index.js +72 -31
- package/dist/blocks/figure/index.js +72 -31
- package/dist/blocks/footnote/index.js +118 -46
- package/dist/blocks/header/index.js +72 -31
- package/dist/blocks/html/index.js +2 -1
- package/dist/blocks/index.js +118 -46
- package/dist/blocks/latex/index.js +2 -2
- package/dist/blocks/list/index.js +72 -31
- package/dist/blocks/math/index.js +3 -2
- package/dist/blocks/mermaid/index.js +2 -1
- package/dist/blocks/paragraph/index.js +72 -31
- package/dist/blocks/spoiler/index.js +118 -46
- package/dist/blocks/table/index.js +73 -32
- package/dist/blocks/task-list/index.js +72 -31
- package/dist/components/index.js +157 -65
- package/dist/components/ncm-block.js +118 -46
- package/dist/components/ncm-document.js +157 -65
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +119 -44
- package/dist/hooks/index.js +118 -46
- package/dist/hooks/use-block-renderer.js +118 -46
- package/dist/index.d.ts +1 -1
- package/dist/index.js +164 -58
- package/dist/inline/index.d.ts +2 -3
- package/dist/inline/index.js +72 -31
- package/dist/lib/defaults.js +118 -46
- package/dist/references-BM-lvGrq.d.ts +99 -0
- package/dist/styles/nuu.css +39 -16
- package/package.json +3 -4
- package/dist/references-BYW5pnj_.d.ts +0 -63
package/dist/lib/defaults.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createContext, useState, createElement,
|
|
2
|
+
import { createContext, useMemo, useState, createElement, useContext, useCallback, useEffect, useRef, Component, useId } from 'react';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
|
-
import { serializeInlineContent, isTypedNestedList } from '@nuucognition/ncm';
|
|
6
|
+
import { serializeInlineContent, isTypedNestedList, parseNcm } from '@nuucognition/ncm';
|
|
7
7
|
import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
|
|
8
8
|
|
|
9
9
|
// src/lib/defaults.ts
|
|
@@ -22,7 +22,7 @@ function CustomCodeBlock({ block, className }) {
|
|
|
22
22
|
"data-block-id": block.id,
|
|
23
23
|
"data-ncm-custom-code": "",
|
|
24
24
|
"data-ncm-language": block.language,
|
|
25
|
-
className: cn("overflow-x-auto", className),
|
|
25
|
+
className: cn("overflow-x-auto overflow-y-hidden", className),
|
|
26
26
|
children: [
|
|
27
27
|
/* @__PURE__ */ jsx("div", { className: "mb-2 text-xs font-medium text-muted-foreground", children: block.language }),
|
|
28
28
|
/* @__PURE__ */ jsx("pre", { children: /* @__PURE__ */ jsx("code", { children: block.content }) })
|
|
@@ -71,6 +71,52 @@ function tryParseInlineRef(input) {
|
|
|
71
71
|
}
|
|
72
72
|
return { token: { type: "inline_ref", kind: "footnote", content: inner.trim() }, length };
|
|
73
73
|
}
|
|
74
|
+
function runLength(input, index, char) {
|
|
75
|
+
let end = index;
|
|
76
|
+
while (end < input.length && input[end] === char) end++;
|
|
77
|
+
return end - index;
|
|
78
|
+
}
|
|
79
|
+
function tryParseEmphasis(input) {
|
|
80
|
+
const char = input[0];
|
|
81
|
+
if (char !== "*" && char !== "_") return null;
|
|
82
|
+
const open = Math.min(3, runLength(input, 0, char));
|
|
83
|
+
const need = open;
|
|
84
|
+
let i = open;
|
|
85
|
+
while (i < input.length) {
|
|
86
|
+
const ch = input[i];
|
|
87
|
+
if (ch === "`") {
|
|
88
|
+
const close = input.indexOf("`", i + 1);
|
|
89
|
+
if (close === -1) break;
|
|
90
|
+
i = close + 1;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (ch !== char) {
|
|
94
|
+
i++;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const run = runLength(input, i, char);
|
|
98
|
+
const closes = need === 1 ? run % 2 === 1 : run >= need;
|
|
99
|
+
if (!closes) {
|
|
100
|
+
i += run;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const extra = run - need;
|
|
104
|
+
const inner = input.slice(open, i + extra);
|
|
105
|
+
if (inner.length === 0) return null;
|
|
106
|
+
const length = i + run;
|
|
107
|
+
const children = parseInline(inner);
|
|
108
|
+
let token;
|
|
109
|
+
if (need === 3) {
|
|
110
|
+
token = { type: "bold", children: [{ type: "italic", children }] };
|
|
111
|
+
} else if (need === 2) {
|
|
112
|
+
token = { type: "bold", children };
|
|
113
|
+
} else {
|
|
114
|
+
token = { type: "italic", children };
|
|
115
|
+
}
|
|
116
|
+
return { token, length };
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
74
120
|
function parseInline(content) {
|
|
75
121
|
if (!content) return [];
|
|
76
122
|
const tokens = [];
|
|
@@ -142,17 +188,11 @@ function parseInline(content) {
|
|
|
142
188
|
remaining = remaining.slice(linkMatch[0].length);
|
|
143
189
|
continue;
|
|
144
190
|
}
|
|
145
|
-
const
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
type: "bold",
|
|
151
|
-
children: parseInline(innerContent)
|
|
152
|
-
});
|
|
153
|
-
remaining = remaining.slice(boldMatch[0].length);
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
191
|
+
const emphasis = tryParseEmphasis(remaining);
|
|
192
|
+
if (emphasis) {
|
|
193
|
+
tokens.push(emphasis.token);
|
|
194
|
+
remaining = remaining.slice(emphasis.length);
|
|
195
|
+
continue;
|
|
156
196
|
}
|
|
157
197
|
const strikeMatch = remaining.match(/^~~(.+?)~~/);
|
|
158
198
|
if (strikeMatch && strikeMatch[1] !== void 0) {
|
|
@@ -163,18 +203,6 @@ function parseInline(content) {
|
|
|
163
203
|
remaining = remaining.slice(strikeMatch[0].length);
|
|
164
204
|
continue;
|
|
165
205
|
}
|
|
166
|
-
const italicMatch = remaining.match(/^\*([^*]+)\*|^_([^_]+)_/);
|
|
167
|
-
if (italicMatch) {
|
|
168
|
-
const innerContent = italicMatch[1] ?? italicMatch[2];
|
|
169
|
-
if (innerContent !== void 0) {
|
|
170
|
-
tokens.push({
|
|
171
|
-
type: "italic",
|
|
172
|
-
children: parseInline(innerContent)
|
|
173
|
-
});
|
|
174
|
-
remaining = remaining.slice(italicMatch[0].length);
|
|
175
|
-
continue;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
206
|
const nextSpecial = findNextSpecialChar(remaining);
|
|
179
207
|
if (nextSpecial > 0) {
|
|
180
208
|
tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
|
|
@@ -209,17 +237,30 @@ function mergeAdjacentText(tokens) {
|
|
|
209
237
|
}
|
|
210
238
|
return result;
|
|
211
239
|
}
|
|
212
|
-
|
|
240
|
+
function normalizeReferenceContent(content) {
|
|
241
|
+
return content.replace(/\s+/g, " ").trim().toLowerCase();
|
|
242
|
+
}
|
|
243
|
+
var ReferenceNumberingContext = createContext(null);
|
|
213
244
|
var BlockReferenceScopeContext = createContext(null);
|
|
214
|
-
function BlockReferenceScope({
|
|
215
|
-
const
|
|
216
|
-
const
|
|
245
|
+
function BlockReferenceScope({ children }) {
|
|
246
|
+
const numbering = useContext(ReferenceNumberingContext);
|
|
247
|
+
const local = useRef({ ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() });
|
|
217
248
|
const counter = useRef({ ref: 0, footnote: 0 });
|
|
218
|
-
counter.current = { ref: 0, footnote: 0 };
|
|
219
249
|
const value = {
|
|
250
|
+
numberFor(kind, content) {
|
|
251
|
+
const key = normalizeReferenceContent(content);
|
|
252
|
+
const fromDocument = numbering?.[kind].get(key);
|
|
253
|
+
if (fromDocument !== void 0) return fromDocument;
|
|
254
|
+
const map = local.current[kind];
|
|
255
|
+
const existing = map.get(key);
|
|
256
|
+
if (existing !== void 0) return existing;
|
|
257
|
+
counter.current[kind] += 1;
|
|
258
|
+
map.set(key, counter.current[kind]);
|
|
259
|
+
return counter.current[kind];
|
|
260
|
+
},
|
|
220
261
|
next(kind) {
|
|
221
262
|
counter.current[kind] += 1;
|
|
222
|
-
return
|
|
263
|
+
return counter.current[kind];
|
|
223
264
|
}
|
|
224
265
|
};
|
|
225
266
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value, children });
|
|
@@ -227,7 +268,7 @@ function BlockReferenceScope({ blockId, children }) {
|
|
|
227
268
|
function useBlockReferenceScope() {
|
|
228
269
|
return useContext(BlockReferenceScopeContext);
|
|
229
270
|
}
|
|
230
|
-
var INERT_SCOPE = { next: () => 0 };
|
|
271
|
+
var INERT_SCOPE = { numberFor: () => 0, next: () => 0 };
|
|
231
272
|
function InertReferenceScope({ children }) {
|
|
232
273
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value: INERT_SCOPE, children });
|
|
233
274
|
}
|
|
@@ -751,7 +792,7 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
|
|
|
751
792
|
);
|
|
752
793
|
}
|
|
753
794
|
case "inline_ref": {
|
|
754
|
-
const number = refScope?.
|
|
795
|
+
const number = refScope?.numberFor(token.kind, token.content) ?? 0;
|
|
755
796
|
return /* @__PURE__ */ jsx(ReferenceMarker, { kind: token.kind, number, children: token.content ? /* @__PURE__ */ jsx(InertReferenceScope, { children: /* @__PURE__ */ jsx(InlineContent, { content: token.content, disableBionic: true, disableBeeline: true }) }) : null });
|
|
756
797
|
}
|
|
757
798
|
default:
|
|
@@ -817,8 +858,32 @@ function renderReadingText(content, opts) {
|
|
|
817
858
|
if (cursor < content.length) pieces.push(content.slice(cursor));
|
|
818
859
|
return /* @__PURE__ */ jsx(Fragment, { children: pieces });
|
|
819
860
|
}
|
|
861
|
+
function quoteBlocks(block) {
|
|
862
|
+
try {
|
|
863
|
+
const doc = parseNcm(block.content, {
|
|
864
|
+
preset: "ncm-full",
|
|
865
|
+
allowMissingFrontmatter: true,
|
|
866
|
+
// Attribution off, as the NUU Editor's bridge keeps it: the promoter's
|
|
867
|
+
// trigger is any last quote line starting with `-`, so a nested quote
|
|
868
|
+
// ending in a list item would lose that item to a `— Author` line.
|
|
869
|
+
blockOptions: { extensions: { attribution: false } }
|
|
870
|
+
});
|
|
871
|
+
const blocks = doc.blocks ?? [];
|
|
872
|
+
if (blocks.length === 0 || blocks.some((child) => child.type === "frontmatter")) {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
return blocks.map((child, index) => ({ ...child, id: `${block.id}.${index + 1}`, stableId: void 0 }));
|
|
876
|
+
} catch {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function QuotedLines({ content }) {
|
|
881
|
+
const lines = content.split("\n");
|
|
882
|
+
return /* @__PURE__ */ jsx(Fragment, { children: 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)) });
|
|
883
|
+
}
|
|
820
884
|
function BlockquoteBlock({ block, className }) {
|
|
821
|
-
const
|
|
885
|
+
const multiline = block.content.includes("\n");
|
|
886
|
+
const blocks = useMemo(() => multiline ? quoteBlocks(block) : null, [block, multiline]);
|
|
822
887
|
return /* @__PURE__ */ jsx(
|
|
823
888
|
"blockquote",
|
|
824
889
|
{
|
|
@@ -828,7 +893,9 @@ function BlockquoteBlock({ block, className }) {
|
|
|
828
893
|
"data-block-id": block.id,
|
|
829
894
|
"data-ncm-blockquote": "",
|
|
830
895
|
className,
|
|
831
|
-
children:
|
|
896
|
+
children: !multiline ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : blocks === null ? /* @__PURE__ */ jsx(QuotedLines, { content: block.content }) : blocks.map(
|
|
897
|
+
(child) => child.type === "paragraph" ? /* @__PURE__ */ jsx(QuotedLines, { content: child.content ?? "" }, blockKey(child)) : /* @__PURE__ */ jsx(NcmBlock, { block: child }, blockKey(child))
|
|
898
|
+
)
|
|
832
899
|
}
|
|
833
900
|
);
|
|
834
901
|
}
|
|
@@ -843,7 +910,8 @@ function ChartBlock({ block, className }) {
|
|
|
843
910
|
"data-ncm-chart": "",
|
|
844
911
|
"data-ncm-chart-type": block.chartType ?? "unknown",
|
|
845
912
|
className: cn(
|
|
846
|
-
|
|
913
|
+
// `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
|
|
914
|
+
"overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
847
915
|
className
|
|
848
916
|
),
|
|
849
917
|
children: /* @__PURE__ */ jsx("code", { children: block.content })
|
|
@@ -1023,7 +1091,8 @@ function DataviewBlock({ block, className }) {
|
|
|
1023
1091
|
"data-ncm-dataview": "",
|
|
1024
1092
|
"data-ncm-query-type": block.queryType,
|
|
1025
1093
|
className: cn(
|
|
1026
|
-
|
|
1094
|
+
// `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
|
|
1095
|
+
"overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
1027
1096
|
className
|
|
1028
1097
|
),
|
|
1029
1098
|
children: /* @__PURE__ */ jsx("code", { children: block.query })
|
|
@@ -1362,7 +1431,8 @@ function HtmlBlock({ block, className }) {
|
|
|
1362
1431
|
"data-block-id": block.id,
|
|
1363
1432
|
"data-ncm-html": "",
|
|
1364
1433
|
className: cn(
|
|
1365
|
-
|
|
1434
|
+
// `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
|
|
1435
|
+
"overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
1366
1436
|
className
|
|
1367
1437
|
),
|
|
1368
1438
|
children: /* @__PURE__ */ jsx("code", { children: block.content })
|
|
@@ -1400,7 +1470,7 @@ function LatexDisplayBlock({ block, className }) {
|
|
|
1400
1470
|
"data-ncm-type": block.type,
|
|
1401
1471
|
"data-block-id": block.id,
|
|
1402
1472
|
"data-ncm-latex-display": "",
|
|
1403
|
-
className: cn("overflow-x-auto", className),
|
|
1473
|
+
className: cn("overflow-x-auto overflow-y-hidden", className),
|
|
1404
1474
|
dangerouslySetInnerHTML: { __html: html }
|
|
1405
1475
|
}
|
|
1406
1476
|
);
|
|
@@ -1415,7 +1485,7 @@ function LatexDisplayBlock({ block, className }) {
|
|
|
1415
1485
|
"data-ncm-type": block.type,
|
|
1416
1486
|
"data-block-id": block.id,
|
|
1417
1487
|
"data-ncm-latex-display": "",
|
|
1418
|
-
className: cn("overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
|
|
1488
|
+
className: cn("overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm", className),
|
|
1419
1489
|
children: /* @__PURE__ */ jsx("code", { children: block.content })
|
|
1420
1490
|
}
|
|
1421
1491
|
);
|
|
@@ -1535,7 +1605,7 @@ function MathBlock({ block, className }) {
|
|
|
1535
1605
|
"data-ncm-type": block.type,
|
|
1536
1606
|
"data-block-id": block.id,
|
|
1537
1607
|
"data-ncm-math": "",
|
|
1538
|
-
className: cn("overflow-x-auto", className),
|
|
1608
|
+
className: cn("overflow-x-auto overflow-y-hidden", className),
|
|
1539
1609
|
dangerouslySetInnerHTML: { __html: html }
|
|
1540
1610
|
}
|
|
1541
1611
|
);
|
|
@@ -1551,7 +1621,8 @@ function MathBlock({ block, className }) {
|
|
|
1551
1621
|
"data-block-id": block.id,
|
|
1552
1622
|
"data-ncm-math": "",
|
|
1553
1623
|
className: cn(
|
|
1554
|
-
|
|
1624
|
+
// `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
|
|
1625
|
+
"overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
1555
1626
|
className
|
|
1556
1627
|
),
|
|
1557
1628
|
children: /* @__PURE__ */ jsx("code", { children: block.content })
|
|
@@ -1569,7 +1640,8 @@ function MermaidBlock({ block, className }) {
|
|
|
1569
1640
|
"data-ncm-mermaid": "",
|
|
1570
1641
|
"data-ncm-diagram-type": block.diagramType,
|
|
1571
1642
|
className: cn(
|
|
1572
|
-
|
|
1643
|
+
// `overflow-y-hidden` pairs with `overflow-x-auto` on purpose — see the note in `lib/defaults.ts`.
|
|
1644
|
+
"overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
1573
1645
|
className
|
|
1574
1646
|
),
|
|
1575
1647
|
children: /* @__PURE__ */ jsx("code", { children: block.content })
|
|
@@ -1630,7 +1702,7 @@ function TableBlock({ block, className }) {
|
|
|
1630
1702
|
"data-ncm-type": block.type,
|
|
1631
1703
|
"data-block-id": block.id,
|
|
1632
1704
|
"data-ncm-table": "",
|
|
1633
|
-
className: cn("w-full overflow-x-auto", className),
|
|
1705
|
+
className: cn("w-full overflow-x-auto overflow-y-hidden", className),
|
|
1634
1706
|
children: /* @__PURE__ */ jsxs("table", { role: "table", "data-ncm-table-element": "", children: [
|
|
1635
1707
|
/* @__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)) }) }),
|
|
1636
1708
|
/* @__PURE__ */ jsx("tbody", { children: block.rows.map((row, rowIndex) => {
|
|
@@ -1716,7 +1788,7 @@ function FallbackBlock({ block, className }) {
|
|
|
1716
1788
|
"data-block-id": block.id,
|
|
1717
1789
|
"data-ncm-fallback": "",
|
|
1718
1790
|
className: cn(
|
|
1719
|
-
"overflow-x-auto rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
1791
|
+
"overflow-x-auto overflow-y-hidden rounded-lg border border-border bg-muted p-4 font-mono text-sm",
|
|
1720
1792
|
className
|
|
1721
1793
|
)
|
|
1722
1794
|
},
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { Block } from '@nuucognition/ncm';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Numbering for inline references (`^[ref: ...]` / `^[footnote: ...]`).
|
|
7
|
+
*
|
|
8
|
+
* The two kinds are counted **independently**: refs produce `[1] [2] …` and
|
|
9
|
+
* footnotes produce `¹ ² …`.
|
|
10
|
+
*
|
|
11
|
+
* Numbers are assigned by a pure pre-pass over the `blocks` array and looked up
|
|
12
|
+
* by **token content**, never by render order. That makes the marker number a
|
|
13
|
+
* function of the document alone: it is stable under React re-renders,
|
|
14
|
+
* StrictMode double rendering, virtualised or out-of-order block rendering,
|
|
15
|
+
* and it gives every citation of the same source the same number.
|
|
16
|
+
*
|
|
17
|
+
* Refs additionally honour the document's own bibliography. When a paragraph
|
|
18
|
+
* reads `[16] Google Gemini Team. Gemini: …` and a `^[ref: Google Gemini
|
|
19
|
+
* Team. Gemini: …]` token carries that entry, the marker shows `[16]` — the
|
|
20
|
+
* number the source document uses — so the inline citation, the reference
|
|
21
|
+
* list, and the original paper all agree. Refs with no bibliography match are
|
|
22
|
+
* numbered sequentially in first-appearance order, continuing after the
|
|
23
|
+
* highest bibliography number so the two ranges never collide.
|
|
24
|
+
*
|
|
25
|
+
* Footnotes are numbered sequentially in first-appearance order (identical
|
|
26
|
+
* footnote text shares a number).
|
|
27
|
+
*/
|
|
28
|
+
type ReferenceKind = "ref" | "footnote";
|
|
29
|
+
interface ReferenceCounts {
|
|
30
|
+
ref: number;
|
|
31
|
+
footnote: number;
|
|
32
|
+
}
|
|
33
|
+
/** Document-wide numbering: normalised token content → marker number. */
|
|
34
|
+
interface ReferenceNumbering {
|
|
35
|
+
ref: Map<string, number>;
|
|
36
|
+
footnote: Map<string, number>;
|
|
37
|
+
}
|
|
38
|
+
/** Collapse whitespace and case so a token and its bibliography entry compare equal. */
|
|
39
|
+
declare function normalizeReferenceContent(content: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Map every `[n] entry` paragraph in the document to its number. The first
|
|
42
|
+
* paragraph carrying a given entry text wins.
|
|
43
|
+
*/
|
|
44
|
+
declare function collectBibliography(blocks: readonly Block[]): Map<string, number>;
|
|
45
|
+
/**
|
|
46
|
+
* Compute the document-wide numbering (see the module comment for the rules).
|
|
47
|
+
*/
|
|
48
|
+
declare function computeReferenceNumbering(blocks: readonly Block[]): ReferenceNumbering;
|
|
49
|
+
/**
|
|
50
|
+
* Per-block count of inline references, as the *previous* numbering scheme
|
|
51
|
+
* exposed it. Kept for API compatibility; the marker numbers no longer derive
|
|
52
|
+
* from these offsets.
|
|
53
|
+
*/
|
|
54
|
+
declare function computeReferenceBases(blocks: readonly Block[]): Map<string, ReferenceCounts>;
|
|
55
|
+
interface BlockReferenceScopeValue {
|
|
56
|
+
/**
|
|
57
|
+
* The marker number for a token with this `kind` and `content`. Pure with
|
|
58
|
+
* respect to the document: the same content always gets the same number.
|
|
59
|
+
*/
|
|
60
|
+
numberFor(kind: ReferenceKind, content: string): number;
|
|
61
|
+
/**
|
|
62
|
+
* Allocate the next number for `kind` in render order. Legacy API — prefer
|
|
63
|
+
* `numberFor`, which is stable under re-renders.
|
|
64
|
+
*/
|
|
65
|
+
next(kind: ReferenceKind): number;
|
|
66
|
+
}
|
|
67
|
+
interface NcmReferencesProviderProps {
|
|
68
|
+
blocks: readonly Block[];
|
|
69
|
+
children: ReactNode;
|
|
70
|
+
}
|
|
71
|
+
/** Document-root provider — runs the numbering pre-pass over `blocks`. */
|
|
72
|
+
declare function NcmReferencesProvider({ blocks, children }: NcmReferencesProviderProps): react.JSX.Element;
|
|
73
|
+
interface BlockReferenceScopeProps {
|
|
74
|
+
/** Block id. Accepted for API compatibility; numbering is document-wide. */
|
|
75
|
+
blockId?: string;
|
|
76
|
+
children: ReactNode;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Reference scope for one block (or one standalone `InlineContent` fragment).
|
|
80
|
+
*
|
|
81
|
+
* Inside an `NcmDocument` it resolves numbers from the document pre-pass.
|
|
82
|
+
* Standalone — no `NcmReferencesProvider` above it — it numbers the fragment's
|
|
83
|
+
* own tokens by content in first-request order, which is still idempotent
|
|
84
|
+
* under StrictMode double rendering because a repeated request for the same
|
|
85
|
+
* content returns the same number.
|
|
86
|
+
*/
|
|
87
|
+
declare function BlockReferenceScope({ children }: BlockReferenceScopeProps): react.JSX.Element;
|
|
88
|
+
/** Read the active per-block reference scope, if any. */
|
|
89
|
+
declare function useBlockReferenceScope(): BlockReferenceScopeValue | null;
|
|
90
|
+
/**
|
|
91
|
+
* Wrap a subtree so any inline references inside it do NOT take document
|
|
92
|
+
* numbers — used for a reference's own popover content, which the numbering
|
|
93
|
+
* pre-pass deliberately does not descend into.
|
|
94
|
+
*/
|
|
95
|
+
declare function InertReferenceScope({ children }: {
|
|
96
|
+
children: ReactNode;
|
|
97
|
+
}): react.JSX.Element;
|
|
98
|
+
|
|
99
|
+
export { BlockReferenceScope as B, InertReferenceScope as I, NcmReferencesProvider as N, type ReferenceCounts as R, type BlockReferenceScopeProps as a, type BlockReferenceScopeValue as b, type NcmReferencesProviderProps as c, type ReferenceKind as d, type ReferenceNumbering as e, collectBibliography as f, computeReferenceBases as g, computeReferenceNumbering as h, normalizeReferenceContent as n, useBlockReferenceScope as u };
|
package/dist/styles/nuu.css
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* 1rem body at 1.65, headings 1.75 / 1.56 / 1.39 / 1.24 / 1.1em. Switching
|
|
16
16
|
* view must not resize a single glyph. Since the flow-block rhythm pass, the
|
|
17
17
|
* MARGINS are part of the same contract: the editor states this file's block
|
|
18
|
-
* gaps (1rem between siblings, per-level rem heading margins, the 1.
|
|
18
|
+
* gaps (1rem between siblings, per-level rem heading margins, the 1.5rem /
|
|
19
19
|
* 0.125rem list geometry) per element on its side. If one side of that pair
|
|
20
20
|
* moves, move the other in the same change.
|
|
21
21
|
*
|
|
@@ -105,13 +105,16 @@
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/*
|
|
108
|
-
* Callout (admonition) —
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
108
|
+
* Callout (admonition) — a quiet card: rounded `md` corners (the NUU chrome
|
|
109
|
+
* step, stated as radius × 0.8 so a host's `--radius` carries through), 1px
|
|
110
|
+
* hairline border, a 2px colored left edge (the blockquote's own weight),
|
|
111
|
+
* tight padding. Rounded since (Task) 581, superseding the sharp-corner line
|
|
112
|
+
* of the minimalist pass — everything else from that pass stands. The type
|
|
113
|
+
* supplies only colors, through the `--ncm-callout-*` hooks; a host assigns
|
|
114
|
+
* them per `data-ncm-admonition-type` (Onyx does, from its palette
|
|
112
115
|
* families). Unset, every hook falls back to the neutral hairline card, so
|
|
113
116
|
* a host with no callout stylesheet — and any type a host does not cover —
|
|
114
|
-
* renders the same
|
|
117
|
+
* renders the same quiet shell with no color.
|
|
115
118
|
*
|
|
116
119
|
* These rules override the component's own rounded-card utilities
|
|
117
120
|
* (`rounded-lg bg-card p-4`): this file is unlayered and Tailwind utilities
|
|
@@ -122,9 +125,18 @@
|
|
|
122
125
|
[data-ncm-document].ncm-theme-nuu [data-ncm-admonition] {
|
|
123
126
|
border: 1px solid var(--ncm-callout-border, var(--border));
|
|
124
127
|
border-left: 2px solid var(--ncm-callout-edge, var(--border));
|
|
125
|
-
border-radius: 0;
|
|
128
|
+
border-radius: calc(var(--radius, 0.625rem) * 0.8);
|
|
126
129
|
padding: 0.625rem 0.875rem;
|
|
127
130
|
background-color: var(--ncm-callout-tint, transparent);
|
|
131
|
+
/*
|
|
132
|
+
* An unbroken word must stay inside the card. Hosts lay the title out as a
|
|
133
|
+
* flex row (glyph + text), and a flex item's min-content size is the whole
|
|
134
|
+
* unbreakable word — the text ran past the card edge. `anywhere`, not
|
|
135
|
+
* `break-word`: only `anywhere` lets the break point count toward the
|
|
136
|
+
* min-content size, which is what the flex layout measures. Inherited, so
|
|
137
|
+
* the title and every content paragraph get it. ((Task) 581)
|
|
138
|
+
*/
|
|
139
|
+
overflow-wrap: anywhere;
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
/*
|
|
@@ -157,9 +169,14 @@
|
|
|
157
169
|
}
|
|
158
170
|
|
|
159
171
|
/* Lists */
|
|
172
|
+
/*
|
|
173
|
+
* 1.5rem is the ONE marker-slot width all three list kinds share — disc,
|
|
174
|
+
* decimal, and the task checkbox (1em box + 0.5rem gap) — so the text column
|
|
175
|
+
* is identical across them at every depth.
|
|
176
|
+
*/
|
|
160
177
|
[data-ncm-document].ncm-theme-nuu [data-ncm-type="list_ordered"],
|
|
161
178
|
[data-ncm-document].ncm-theme-nuu [data-ncm-type="list_unordered"] {
|
|
162
|
-
padding-left: 1.
|
|
179
|
+
padding-left: 1.5rem;
|
|
163
180
|
color: var(--foreground);
|
|
164
181
|
line-height: 1.65;
|
|
165
182
|
}
|
|
@@ -182,7 +199,7 @@
|
|
|
182
199
|
[data-ncm-document].ncm-theme-nuu [data-ncm-type="list_unordered"] ol,
|
|
183
200
|
[data-ncm-document].ncm-theme-nuu [data-ncm-type="list_unordered"] ul {
|
|
184
201
|
margin-top: 0.125rem;
|
|
185
|
-
padding-left: 1.
|
|
202
|
+
padding-left: 1.5rem;
|
|
186
203
|
}
|
|
187
204
|
|
|
188
205
|
[data-ncm-document].ncm-theme-nuu [data-ncm-type="list_ordered"] li::marker,
|
|
@@ -206,11 +223,14 @@
|
|
|
206
223
|
/*
|
|
207
224
|
* Task list — one spec with the editor's `ul[data-type="taskList"]` block in
|
|
208
225
|
* `@nuucognition/nuu-editor` (`src/nuu-editor/nuu-editor.scss`): flush-left
|
|
209
|
-
* rows 0.125rem apart, a 1em
|
|
210
|
-
* (border-token box, foreground fill when
|
|
211
|
-
* 0.5rem to the text
|
|
212
|
-
*
|
|
213
|
-
*
|
|
226
|
+
* rows 0.125rem apart, a 1em checkbox rounded 0.25rem (the nuu-ui Checkbox
|
|
227
|
+
* radius) drawn from theme tokens (border-token box, foreground fill when
|
|
228
|
+
* checked, background-coloured check), 0.5rem to the text — 1em + 0.5rem =
|
|
229
|
+
* the shared 1.5rem marker slot that lines task text up with disc and
|
|
230
|
+
* decimal text. Checked text dims to the muted tone with NO strike-through.
|
|
231
|
+
* A nested task list carries NO indent of its own: the checkbox slot IS the
|
|
232
|
+
* indent, the same 1.5rem step the other list kinds get from padding. If one
|
|
233
|
+
* side of that pair moves, move the other in the same change.
|
|
214
234
|
*
|
|
215
235
|
* The checkbox is drawn with `appearance: none` because the native control
|
|
216
236
|
* neither themes nor matches the editor's; the input stays a real (disabled)
|
|
@@ -233,7 +253,9 @@
|
|
|
233
253
|
}
|
|
234
254
|
|
|
235
255
|
[data-ncm-document].ncm-theme-nuu [data-ncm-task-list] [data-ncm-list-nested] {
|
|
236
|
-
margin
|
|
256
|
+
/* No margin: the nested row's own checkbox slot (1em + 0.5rem) is the
|
|
257
|
+
1.5rem indent, the same step disc and decimal get from padding. */
|
|
258
|
+
margin-left: 0;
|
|
237
259
|
margin-top: 0.125rem;
|
|
238
260
|
}
|
|
239
261
|
|
|
@@ -252,7 +274,8 @@
|
|
|
252
274
|
height: 1em;
|
|
253
275
|
margin: 0.375rem 0 0;
|
|
254
276
|
border: 1px solid var(--border);
|
|
255
|
-
|
|
277
|
+
/* nuu-ui's Checkbox radius (rounded-[4px]). */
|
|
278
|
+
border-radius: 0.25rem;
|
|
256
279
|
background-color: transparent;
|
|
257
280
|
position: relative;
|
|
258
281
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuucognition/ncm-ui",
|
|
3
|
-
"version": "0.1.1-beta.
|
|
3
|
+
"version": "0.1.1-beta.2",
|
|
4
4
|
"description": "React renderers for NUU Cognition Markdown (NCM) blocks — a component library that renders parsed NCM Blocks to accessible, themeable markup.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
"*.css"
|
|
19
19
|
],
|
|
20
20
|
"publishConfig": {
|
|
21
|
-
"access": "public"
|
|
22
|
-
"tag": "beta"
|
|
21
|
+
"access": "public"
|
|
23
22
|
},
|
|
24
23
|
"main": "./dist/index.js",
|
|
25
24
|
"module": "./dist/index.js",
|
|
@@ -30,7 +29,7 @@
|
|
|
30
29
|
"LICENSE"
|
|
31
30
|
],
|
|
32
31
|
"dependencies": {
|
|
33
|
-
"@nuucognition/mesh-core": "1.0.1-beta.
|
|
32
|
+
"@nuucognition/mesh-core": "1.0.1-beta.2",
|
|
34
33
|
"clsx": "^2.1.1",
|
|
35
34
|
"katex": "^0.16.21",
|
|
36
35
|
"shiki": "^1.29.2",
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import * as react from 'react';
|
|
2
|
-
import { ReactNode } from 'react';
|
|
3
|
-
import { Block } from '@nuucognition/ncm';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Document-order numbering for inline references (`^[ref: ...]` /
|
|
7
|
-
* `^[footnote: ...]`).
|
|
8
|
-
*
|
|
9
|
-
* The two kinds are counted **independently**: refs produce `[1] [2] …` and
|
|
10
|
-
* footnotes produce `¹ ² …`, each with its own running counter across the
|
|
11
|
-
* whole document.
|
|
12
|
-
*
|
|
13
|
-
* Numbering is computed from the `blocks` array — a pure pre-pass that does not
|
|
14
|
-
* depend on React render order — so markers stay stable even if a host
|
|
15
|
-
* virtualises blocks or renders them out of order. The pre-pass yields, per
|
|
16
|
-
* block, the count of each kind in all *preceding* blocks (the "base"); within
|
|
17
|
-
* a block, a `BlockReferenceScope` hands out sequential numbers in render
|
|
18
|
-
* order. Only the within-block step relies on the block's inline content
|
|
19
|
-
* rendering as a synchronous subtree (it always does).
|
|
20
|
-
*/
|
|
21
|
-
type ReferenceKind = "ref" | "footnote";
|
|
22
|
-
interface ReferenceCounts {
|
|
23
|
-
ref: number;
|
|
24
|
-
footnote: number;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Map each block id to the number of refs/footnotes that precede it in
|
|
28
|
-
* document order — the starting offset for that block's own markers.
|
|
29
|
-
*/
|
|
30
|
-
declare function computeReferenceBases(blocks: readonly Block[]): Map<string, ReferenceCounts>;
|
|
31
|
-
interface BlockReferenceScopeValue {
|
|
32
|
-
/** Allocate the next document-order number for `kind` within this block. */
|
|
33
|
-
next(kind: ReferenceKind): number;
|
|
34
|
-
}
|
|
35
|
-
interface NcmReferencesProviderProps {
|
|
36
|
-
blocks: readonly Block[];
|
|
37
|
-
children: ReactNode;
|
|
38
|
-
}
|
|
39
|
-
/** Document-root provider — runs the numbering pre-pass over `blocks`. */
|
|
40
|
-
declare function NcmReferencesProvider({ blocks, children }: NcmReferencesProviderProps): react.JSX.Element;
|
|
41
|
-
interface BlockReferenceScopeProps {
|
|
42
|
-
/** Block id; resolves the base offset from the document pre-pass. */
|
|
43
|
-
blockId?: string;
|
|
44
|
-
children: ReactNode;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Per-block numbering scope. Seeds a fresh counter from the block's base offset
|
|
48
|
-
* on every render and hands out sequential numbers as markers render. Resetting
|
|
49
|
-
* each render keeps numbering idempotent under React re-renders / StrictMode.
|
|
50
|
-
*/
|
|
51
|
-
declare function BlockReferenceScope({ blockId, children }: BlockReferenceScopeProps): react.JSX.Element;
|
|
52
|
-
/** Read the active per-block reference scope, if any. */
|
|
53
|
-
declare function useBlockReferenceScope(): BlockReferenceScopeValue | null;
|
|
54
|
-
/**
|
|
55
|
-
* Wrap a subtree so any inline references inside it do NOT allocate
|
|
56
|
-
* document-order numbers — used for a reference's own popover content, which
|
|
57
|
-
* the numbering pre-pass deliberately does not descend into.
|
|
58
|
-
*/
|
|
59
|
-
declare function InertReferenceScope({ children }: {
|
|
60
|
-
children: ReactNode;
|
|
61
|
-
}): react.JSX.Element;
|
|
62
|
-
|
|
63
|
-
export { BlockReferenceScope as B, InertReferenceScope as I, NcmReferencesProvider as N, type ReferenceCounts as R, type BlockReferenceScopeProps as a, type BlockReferenceScopeValue as b, type NcmReferencesProviderProps as c, type ReferenceKind as d, computeReferenceBases as e, useBlockReferenceScope as u };
|