@nuucognition/ncm-ui 0.1.1-beta.1 → 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 +102 -35
- package/dist/blocks/aside/index.js +102 -35
- package/dist/blocks/blockquote/index.d.ts +7 -5
- package/dist/blocks/blockquote/index.js +1218 -36
- package/dist/blocks/container/index.js +72 -31
- package/dist/blocks/definition/index.js +101 -34
- package/dist/blocks/embedding/index.js +72 -31
- package/dist/blocks/figure/index.js +72 -31
- package/dist/blocks/footnote/index.js +102 -35
- package/dist/blocks/header/index.js +72 -31
- package/dist/blocks/index.js +102 -35
- package/dist/blocks/list/index.js +72 -31
- package/dist/blocks/paragraph/index.js +72 -31
- package/dist/blocks/spoiler/index.js +102 -35
- package/dist/blocks/table/index.js +72 -31
- package/dist/blocks/task-list/index.js +72 -31
- package/dist/components/index.js +141 -54
- package/dist/components/ncm-block.js +102 -35
- package/dist/components/ncm-document.js +141 -54
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +119 -44
- package/dist/hooks/index.js +102 -35
- package/dist/hooks/use-block-renderer.js +102 -35
- package/dist/index.d.ts +1 -1
- package/dist/index.js +148 -47
- package/dist/inline/index.d.ts +2 -3
- package/dist/inline/index.js +72 -31
- package/dist/lib/defaults.js +102 -35
- package/dist/references-BM-lvGrq.d.ts +99 -0
- package/package.json +3 -3
- package/dist/references-BYW5pnj_.d.ts +0 -63
|
@@ -51,6 +51,52 @@ function tryParseInlineRef(input) {
|
|
|
51
51
|
}
|
|
52
52
|
return { token: { type: "inline_ref", kind: "footnote", content: inner.trim() }, length };
|
|
53
53
|
}
|
|
54
|
+
function runLength(input, index, char) {
|
|
55
|
+
let end = index;
|
|
56
|
+
while (end < input.length && input[end] === char) end++;
|
|
57
|
+
return end - index;
|
|
58
|
+
}
|
|
59
|
+
function tryParseEmphasis(input) {
|
|
60
|
+
const char = input[0];
|
|
61
|
+
if (char !== "*" && char !== "_") return null;
|
|
62
|
+
const open = Math.min(3, runLength(input, 0, char));
|
|
63
|
+
const need = open;
|
|
64
|
+
let i = open;
|
|
65
|
+
while (i < input.length) {
|
|
66
|
+
const ch = input[i];
|
|
67
|
+
if (ch === "`") {
|
|
68
|
+
const close = input.indexOf("`", i + 1);
|
|
69
|
+
if (close === -1) break;
|
|
70
|
+
i = close + 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (ch !== char) {
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const run = runLength(input, i, char);
|
|
78
|
+
const closes = need === 1 ? run % 2 === 1 : run >= need;
|
|
79
|
+
if (!closes) {
|
|
80
|
+
i += run;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const extra = run - need;
|
|
84
|
+
const inner = input.slice(open, i + extra);
|
|
85
|
+
if (inner.length === 0) return null;
|
|
86
|
+
const length = i + run;
|
|
87
|
+
const children = parseInline(inner);
|
|
88
|
+
let token;
|
|
89
|
+
if (need === 3) {
|
|
90
|
+
token = { type: "bold", children: [{ type: "italic", children }] };
|
|
91
|
+
} else if (need === 2) {
|
|
92
|
+
token = { type: "bold", children };
|
|
93
|
+
} else {
|
|
94
|
+
token = { type: "italic", children };
|
|
95
|
+
}
|
|
96
|
+
return { token, length };
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
54
100
|
function parseInline(content) {
|
|
55
101
|
if (!content) return [];
|
|
56
102
|
const tokens = [];
|
|
@@ -122,17 +168,11 @@ function parseInline(content) {
|
|
|
122
168
|
remaining = remaining.slice(linkMatch[0].length);
|
|
123
169
|
continue;
|
|
124
170
|
}
|
|
125
|
-
const
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
type: "bold",
|
|
131
|
-
children: parseInline(innerContent)
|
|
132
|
-
});
|
|
133
|
-
remaining = remaining.slice(boldMatch[0].length);
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
171
|
+
const emphasis = tryParseEmphasis(remaining);
|
|
172
|
+
if (emphasis) {
|
|
173
|
+
tokens.push(emphasis.token);
|
|
174
|
+
remaining = remaining.slice(emphasis.length);
|
|
175
|
+
continue;
|
|
136
176
|
}
|
|
137
177
|
const strikeMatch = remaining.match(/^~~(.+?)~~/);
|
|
138
178
|
if (strikeMatch && strikeMatch[1] !== void 0) {
|
|
@@ -143,18 +183,6 @@ function parseInline(content) {
|
|
|
143
183
|
remaining = remaining.slice(strikeMatch[0].length);
|
|
144
184
|
continue;
|
|
145
185
|
}
|
|
146
|
-
const italicMatch = remaining.match(/^\*([^*]+)\*|^_([^_]+)_/);
|
|
147
|
-
if (italicMatch) {
|
|
148
|
-
const innerContent = italicMatch[1] ?? italicMatch[2];
|
|
149
|
-
if (innerContent !== void 0) {
|
|
150
|
-
tokens.push({
|
|
151
|
-
type: "italic",
|
|
152
|
-
children: parseInline(innerContent)
|
|
153
|
-
});
|
|
154
|
-
remaining = remaining.slice(italicMatch[0].length);
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
186
|
const nextSpecial = findNextSpecialChar(remaining);
|
|
159
187
|
if (nextSpecial > 0) {
|
|
160
188
|
tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
|
|
@@ -265,17 +293,30 @@ function ReferenceMarker({ kind, number, children }) {
|
|
|
265
293
|
}
|
|
266
294
|
);
|
|
267
295
|
}
|
|
268
|
-
|
|
296
|
+
function normalizeReferenceContent(content) {
|
|
297
|
+
return content.replace(/\s+/g, " ").trim().toLowerCase();
|
|
298
|
+
}
|
|
299
|
+
var ReferenceNumberingContext = createContext(null);
|
|
269
300
|
var BlockReferenceScopeContext = createContext(null);
|
|
270
|
-
function BlockReferenceScope({
|
|
271
|
-
const
|
|
272
|
-
const
|
|
301
|
+
function BlockReferenceScope({ children }) {
|
|
302
|
+
const numbering = useContext(ReferenceNumberingContext);
|
|
303
|
+
const local = useRef({ ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() });
|
|
273
304
|
const counter = useRef({ ref: 0, footnote: 0 });
|
|
274
|
-
counter.current = { ref: 0, footnote: 0 };
|
|
275
305
|
const value = {
|
|
306
|
+
numberFor(kind, content) {
|
|
307
|
+
const key = normalizeReferenceContent(content);
|
|
308
|
+
const fromDocument = numbering?.[kind].get(key);
|
|
309
|
+
if (fromDocument !== void 0) return fromDocument;
|
|
310
|
+
const map = local.current[kind];
|
|
311
|
+
const existing = map.get(key);
|
|
312
|
+
if (existing !== void 0) return existing;
|
|
313
|
+
counter.current[kind] += 1;
|
|
314
|
+
map.set(key, counter.current[kind]);
|
|
315
|
+
return counter.current[kind];
|
|
316
|
+
},
|
|
276
317
|
next(kind) {
|
|
277
318
|
counter.current[kind] += 1;
|
|
278
|
-
return
|
|
319
|
+
return counter.current[kind];
|
|
279
320
|
}
|
|
280
321
|
};
|
|
281
322
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value, children });
|
|
@@ -283,7 +324,7 @@ function BlockReferenceScope({ blockId, children }) {
|
|
|
283
324
|
function useBlockReferenceScope() {
|
|
284
325
|
return useContext(BlockReferenceScopeContext);
|
|
285
326
|
}
|
|
286
|
-
var INERT_SCOPE = { next: () => 0 };
|
|
327
|
+
var INERT_SCOPE = { numberFor: () => 0, next: () => 0 };
|
|
287
328
|
function InertReferenceScope({ children }) {
|
|
288
329
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value: INERT_SCOPE, children });
|
|
289
330
|
}
|
|
@@ -574,7 +615,7 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
|
|
|
574
615
|
);
|
|
575
616
|
}
|
|
576
617
|
case "inline_ref": {
|
|
577
|
-
const number = refScope?.
|
|
618
|
+
const number = refScope?.numberFor(token.kind, token.content) ?? 0;
|
|
578
619
|
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 });
|
|
579
620
|
}
|
|
580
621
|
default:
|
package/dist/components/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { createContext, createElement, useMemo, useContext, useRef, Component, u
|
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
|
-
import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
|
|
7
6
|
import { parseNcm, serializeInlineContent, isTypedNestedList } from '@nuucognition/ncm';
|
|
7
|
+
import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
|
|
8
8
|
|
|
9
9
|
// src/components/block-shell.tsx
|
|
10
10
|
function cn(...inputs) {
|
|
@@ -121,6 +121,52 @@ function tryParseInlineRef(input) {
|
|
|
121
121
|
}
|
|
122
122
|
return { token: { type: "inline_ref", kind: "footnote", content: inner.trim() }, length };
|
|
123
123
|
}
|
|
124
|
+
function runLength(input, index, char) {
|
|
125
|
+
let end = index;
|
|
126
|
+
while (end < input.length && input[end] === char) end++;
|
|
127
|
+
return end - index;
|
|
128
|
+
}
|
|
129
|
+
function tryParseEmphasis(input) {
|
|
130
|
+
const char = input[0];
|
|
131
|
+
if (char !== "*" && char !== "_") return null;
|
|
132
|
+
const open = Math.min(3, runLength(input, 0, char));
|
|
133
|
+
const need = open;
|
|
134
|
+
let i = open;
|
|
135
|
+
while (i < input.length) {
|
|
136
|
+
const ch = input[i];
|
|
137
|
+
if (ch === "`") {
|
|
138
|
+
const close = input.indexOf("`", i + 1);
|
|
139
|
+
if (close === -1) break;
|
|
140
|
+
i = close + 1;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (ch !== char) {
|
|
144
|
+
i++;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const run = runLength(input, i, char);
|
|
148
|
+
const closes = need === 1 ? run % 2 === 1 : run >= need;
|
|
149
|
+
if (!closes) {
|
|
150
|
+
i += run;
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const extra = run - need;
|
|
154
|
+
const inner = input.slice(open, i + extra);
|
|
155
|
+
if (inner.length === 0) return null;
|
|
156
|
+
const length = i + run;
|
|
157
|
+
const children = parseInline(inner);
|
|
158
|
+
let token;
|
|
159
|
+
if (need === 3) {
|
|
160
|
+
token = { type: "bold", children: [{ type: "italic", children }] };
|
|
161
|
+
} else if (need === 2) {
|
|
162
|
+
token = { type: "bold", children };
|
|
163
|
+
} else {
|
|
164
|
+
token = { type: "italic", children };
|
|
165
|
+
}
|
|
166
|
+
return { token, length };
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
124
170
|
function parseInline(content) {
|
|
125
171
|
if (!content) return [];
|
|
126
172
|
const tokens = [];
|
|
@@ -192,17 +238,11 @@ function parseInline(content) {
|
|
|
192
238
|
remaining = remaining.slice(linkMatch[0].length);
|
|
193
239
|
continue;
|
|
194
240
|
}
|
|
195
|
-
const
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
type: "bold",
|
|
201
|
-
children: parseInline(innerContent)
|
|
202
|
-
});
|
|
203
|
-
remaining = remaining.slice(boldMatch[0].length);
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
241
|
+
const emphasis = tryParseEmphasis(remaining);
|
|
242
|
+
if (emphasis) {
|
|
243
|
+
tokens.push(emphasis.token);
|
|
244
|
+
remaining = remaining.slice(emphasis.length);
|
|
245
|
+
continue;
|
|
206
246
|
}
|
|
207
247
|
const strikeMatch = remaining.match(/^~~(.+?)~~/);
|
|
208
248
|
if (strikeMatch && strikeMatch[1] !== void 0) {
|
|
@@ -213,18 +253,6 @@ function parseInline(content) {
|
|
|
213
253
|
remaining = remaining.slice(strikeMatch[0].length);
|
|
214
254
|
continue;
|
|
215
255
|
}
|
|
216
|
-
const italicMatch = remaining.match(/^\*([^*]+)\*|^_([^_]+)_/);
|
|
217
|
-
if (italicMatch) {
|
|
218
|
-
const innerContent = italicMatch[1] ?? italicMatch[2];
|
|
219
|
-
if (innerContent !== void 0) {
|
|
220
|
-
tokens.push({
|
|
221
|
-
type: "italic",
|
|
222
|
-
children: parseInline(innerContent)
|
|
223
|
-
});
|
|
224
|
-
remaining = remaining.slice(italicMatch[0].length);
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
256
|
const nextSpecial = findNextSpecialChar(remaining);
|
|
229
257
|
if (nextSpecial > 0) {
|
|
230
258
|
tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
|
|
@@ -375,48 +403,81 @@ function collectListStrings(items) {
|
|
|
375
403
|
}
|
|
376
404
|
return out;
|
|
377
405
|
}
|
|
378
|
-
function
|
|
406
|
+
function normalizeReferenceContent(content) {
|
|
407
|
+
return content.replace(/\s+/g, " ").trim().toLowerCase();
|
|
408
|
+
}
|
|
409
|
+
var BIBLIOGRAPHY_ENTRY_RE = /^\s*\[(\d+)\]\s+([\s\S]+?)\s*$/;
|
|
410
|
+
function collectBibliography(blocks) {
|
|
411
|
+
const entries = /* @__PURE__ */ new Map();
|
|
412
|
+
for (const block of blocks) {
|
|
413
|
+
if (block.type !== "paragraph") continue;
|
|
414
|
+
const content = block.content ?? "";
|
|
415
|
+
const match = BIBLIOGRAPHY_ENTRY_RE.exec(content);
|
|
416
|
+
if (!match || !match[1] || !match[2]) continue;
|
|
417
|
+
const key = normalizeReferenceContent(match[2]);
|
|
418
|
+
if (key && !entries.has(key)) entries.set(key, Number(match[1]));
|
|
419
|
+
}
|
|
420
|
+
return entries;
|
|
421
|
+
}
|
|
422
|
+
function walkInlineRefs(tokens, visit) {
|
|
379
423
|
for (const token of tokens) {
|
|
380
424
|
if (token.type === "inline_ref") {
|
|
381
|
-
|
|
425
|
+
visit(token);
|
|
382
426
|
} else if ("children" in token) {
|
|
383
|
-
|
|
427
|
+
walkInlineRefs(token.children, visit);
|
|
384
428
|
}
|
|
385
429
|
}
|
|
386
430
|
}
|
|
387
|
-
function
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
function computeReferenceBases(blocks) {
|
|
395
|
-
const bases = /* @__PURE__ */ new Map();
|
|
396
|
-
const acc = { ref: 0, footnote: 0 };
|
|
431
|
+
function computeReferenceNumbering(blocks) {
|
|
432
|
+
const bibliography = collectBibliography(blocks);
|
|
433
|
+
let maxBibliography = 0;
|
|
434
|
+
for (const n of bibliography.values()) maxBibliography = Math.max(maxBibliography, n);
|
|
435
|
+
const numbering = { ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() };
|
|
436
|
+
let nextRef = maxBibliography;
|
|
437
|
+
let nextFootnote = 0;
|
|
397
438
|
for (const block of blocks) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
439
|
+
for (const str of collectInlineStrings(block)) {
|
|
440
|
+
if (!str) continue;
|
|
441
|
+
walkInlineRefs(parseInline(str), (token) => {
|
|
442
|
+
const key = normalizeReferenceContent(token.content);
|
|
443
|
+
const map = numbering[token.kind];
|
|
444
|
+
if (map.has(key)) return;
|
|
445
|
+
if (token.kind === "ref") {
|
|
446
|
+
const fromBibliography = bibliography.get(key);
|
|
447
|
+
map.set(key, fromBibliography ?? ++nextRef);
|
|
448
|
+
} else {
|
|
449
|
+
map.set(key, ++nextFootnote);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
402
453
|
}
|
|
403
|
-
return
|
|
454
|
+
return numbering;
|
|
404
455
|
}
|
|
405
|
-
var
|
|
456
|
+
var ReferenceNumberingContext = createContext(null);
|
|
406
457
|
var BlockReferenceScopeContext = createContext(null);
|
|
407
458
|
function NcmReferencesProvider({ blocks, children }) {
|
|
408
|
-
const
|
|
409
|
-
return /* @__PURE__ */ jsx(
|
|
459
|
+
const numbering = useMemo(() => computeReferenceNumbering(blocks), [blocks]);
|
|
460
|
+
return /* @__PURE__ */ jsx(ReferenceNumberingContext.Provider, { value: numbering, children });
|
|
410
461
|
}
|
|
411
|
-
function BlockReferenceScope({
|
|
412
|
-
const
|
|
413
|
-
const
|
|
462
|
+
function BlockReferenceScope({ children }) {
|
|
463
|
+
const numbering = useContext(ReferenceNumberingContext);
|
|
464
|
+
const local = useRef({ ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() });
|
|
414
465
|
const counter = useRef({ ref: 0, footnote: 0 });
|
|
415
|
-
counter.current = { ref: 0, footnote: 0 };
|
|
416
466
|
const value = {
|
|
467
|
+
numberFor(kind, content) {
|
|
468
|
+
const key = normalizeReferenceContent(content);
|
|
469
|
+
const fromDocument = numbering?.[kind].get(key);
|
|
470
|
+
if (fromDocument !== void 0) return fromDocument;
|
|
471
|
+
const map = local.current[kind];
|
|
472
|
+
const existing = map.get(key);
|
|
473
|
+
if (existing !== void 0) return existing;
|
|
474
|
+
counter.current[kind] += 1;
|
|
475
|
+
map.set(key, counter.current[kind]);
|
|
476
|
+
return counter.current[kind];
|
|
477
|
+
},
|
|
417
478
|
next(kind) {
|
|
418
479
|
counter.current[kind] += 1;
|
|
419
|
-
return
|
|
480
|
+
return counter.current[kind];
|
|
420
481
|
}
|
|
421
482
|
};
|
|
422
483
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value, children });
|
|
@@ -424,7 +485,7 @@ function BlockReferenceScope({ blockId, children }) {
|
|
|
424
485
|
function useBlockReferenceScope() {
|
|
425
486
|
return useContext(BlockReferenceScopeContext);
|
|
426
487
|
}
|
|
427
|
-
var INERT_SCOPE = { next: () => 0 };
|
|
488
|
+
var INERT_SCOPE = { numberFor: () => 0, next: () => 0 };
|
|
428
489
|
function InertReferenceScope({ children }) {
|
|
429
490
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value: INERT_SCOPE, children });
|
|
430
491
|
}
|
|
@@ -715,7 +776,7 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
|
|
|
715
776
|
);
|
|
716
777
|
}
|
|
717
778
|
case "inline_ref": {
|
|
718
|
-
const number = refScope?.
|
|
779
|
+
const number = refScope?.numberFor(token.kind, token.content) ?? 0;
|
|
719
780
|
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 });
|
|
720
781
|
}
|
|
721
782
|
default:
|
|
@@ -781,8 +842,32 @@ function renderReadingText(content, opts) {
|
|
|
781
842
|
if (cursor < content.length) pieces.push(content.slice(cursor));
|
|
782
843
|
return /* @__PURE__ */ jsx(Fragment, { children: pieces });
|
|
783
844
|
}
|
|
845
|
+
function quoteBlocks(block) {
|
|
846
|
+
try {
|
|
847
|
+
const doc = parseNcm(block.content, {
|
|
848
|
+
preset: "ncm-full",
|
|
849
|
+
allowMissingFrontmatter: true,
|
|
850
|
+
// Attribution off, as the NUU Editor's bridge keeps it: the promoter's
|
|
851
|
+
// trigger is any last quote line starting with `-`, so a nested quote
|
|
852
|
+
// ending in a list item would lose that item to a `— Author` line.
|
|
853
|
+
blockOptions: { extensions: { attribution: false } }
|
|
854
|
+
});
|
|
855
|
+
const blocks = doc.blocks ?? [];
|
|
856
|
+
if (blocks.length === 0 || blocks.some((child) => child.type === "frontmatter")) {
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
return blocks.map((child, index) => ({ ...child, id: `${block.id}.${index + 1}`, stableId: void 0 }));
|
|
860
|
+
} catch {
|
|
861
|
+
return null;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function QuotedLines({ content }) {
|
|
865
|
+
const lines = content.split("\n");
|
|
866
|
+
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)) });
|
|
867
|
+
}
|
|
784
868
|
function BlockquoteBlock({ block, className }) {
|
|
785
|
-
const
|
|
869
|
+
const multiline = block.content.includes("\n");
|
|
870
|
+
const blocks = useMemo(() => multiline ? quoteBlocks(block) : null, [block, multiline]);
|
|
786
871
|
return /* @__PURE__ */ jsx(
|
|
787
872
|
"blockquote",
|
|
788
873
|
{
|
|
@@ -792,7 +877,9 @@ function BlockquoteBlock({ block, className }) {
|
|
|
792
877
|
"data-block-id": block.id,
|
|
793
878
|
"data-ncm-blockquote": "",
|
|
794
879
|
className,
|
|
795
|
-
children:
|
|
880
|
+
children: !multiline ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : blocks === null ? /* @__PURE__ */ jsx(QuotedLines, { content: block.content }) : blocks.map(
|
|
881
|
+
(child) => child.type === "paragraph" ? /* @__PURE__ */ jsx(QuotedLines, { content: child.content ?? "" }, blockKey(child)) : /* @__PURE__ */ jsx(NcmBlock, { block: child }, blockKey(child))
|
|
882
|
+
)
|
|
796
883
|
}
|
|
797
884
|
);
|
|
798
885
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { createContext, useContext, createElement, useRef, Component, useState, useEffect,
|
|
2
|
+
import { createContext, useContext, createElement, useMemo, useRef, Component, useState, useEffect, useCallback, useId } from 'react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
5
5
|
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
import { serializeInlineContent, isTypedNestedList, parseNcm } from '@nuucognition/ncm';
|
|
6
7
|
import { extractExtension, embedTypeFromExtension } from '@nuucognition/mesh-core';
|
|
7
|
-
import { serializeInlineContent, isTypedNestedList } from '@nuucognition/ncm';
|
|
8
8
|
|
|
9
9
|
function blockKey(block) {
|
|
10
10
|
return block.stableId ? `${block.id}:${block.stableId}` : block.id;
|
|
@@ -153,6 +153,52 @@ function tryParseInlineRef(input) {
|
|
|
153
153
|
}
|
|
154
154
|
return { token: { type: "inline_ref", kind: "footnote", content: inner.trim() }, length };
|
|
155
155
|
}
|
|
156
|
+
function runLength(input, index, char) {
|
|
157
|
+
let end = index;
|
|
158
|
+
while (end < input.length && input[end] === char) end++;
|
|
159
|
+
return end - index;
|
|
160
|
+
}
|
|
161
|
+
function tryParseEmphasis(input) {
|
|
162
|
+
const char = input[0];
|
|
163
|
+
if (char !== "*" && char !== "_") return null;
|
|
164
|
+
const open = Math.min(3, runLength(input, 0, char));
|
|
165
|
+
const need = open;
|
|
166
|
+
let i = open;
|
|
167
|
+
while (i < input.length) {
|
|
168
|
+
const ch = input[i];
|
|
169
|
+
if (ch === "`") {
|
|
170
|
+
const close = input.indexOf("`", i + 1);
|
|
171
|
+
if (close === -1) break;
|
|
172
|
+
i = close + 1;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (ch !== char) {
|
|
176
|
+
i++;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const run = runLength(input, i, char);
|
|
180
|
+
const closes = need === 1 ? run % 2 === 1 : run >= need;
|
|
181
|
+
if (!closes) {
|
|
182
|
+
i += run;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const extra = run - need;
|
|
186
|
+
const inner = input.slice(open, i + extra);
|
|
187
|
+
if (inner.length === 0) return null;
|
|
188
|
+
const length = i + run;
|
|
189
|
+
const children = parseInline(inner);
|
|
190
|
+
let token;
|
|
191
|
+
if (need === 3) {
|
|
192
|
+
token = { type: "bold", children: [{ type: "italic", children }] };
|
|
193
|
+
} else if (need === 2) {
|
|
194
|
+
token = { type: "bold", children };
|
|
195
|
+
} else {
|
|
196
|
+
token = { type: "italic", children };
|
|
197
|
+
}
|
|
198
|
+
return { token, length };
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
156
202
|
function parseInline(content) {
|
|
157
203
|
if (!content) return [];
|
|
158
204
|
const tokens = [];
|
|
@@ -224,17 +270,11 @@ function parseInline(content) {
|
|
|
224
270
|
remaining = remaining.slice(linkMatch[0].length);
|
|
225
271
|
continue;
|
|
226
272
|
}
|
|
227
|
-
const
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
type: "bold",
|
|
233
|
-
children: parseInline(innerContent)
|
|
234
|
-
});
|
|
235
|
-
remaining = remaining.slice(boldMatch[0].length);
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
273
|
+
const emphasis = tryParseEmphasis(remaining);
|
|
274
|
+
if (emphasis) {
|
|
275
|
+
tokens.push(emphasis.token);
|
|
276
|
+
remaining = remaining.slice(emphasis.length);
|
|
277
|
+
continue;
|
|
238
278
|
}
|
|
239
279
|
const strikeMatch = remaining.match(/^~~(.+?)~~/);
|
|
240
280
|
if (strikeMatch && strikeMatch[1] !== void 0) {
|
|
@@ -245,18 +285,6 @@ function parseInline(content) {
|
|
|
245
285
|
remaining = remaining.slice(strikeMatch[0].length);
|
|
246
286
|
continue;
|
|
247
287
|
}
|
|
248
|
-
const italicMatch = remaining.match(/^\*([^*]+)\*|^_([^_]+)_/);
|
|
249
|
-
if (italicMatch) {
|
|
250
|
-
const innerContent = italicMatch[1] ?? italicMatch[2];
|
|
251
|
-
if (innerContent !== void 0) {
|
|
252
|
-
tokens.push({
|
|
253
|
-
type: "italic",
|
|
254
|
-
children: parseInline(innerContent)
|
|
255
|
-
});
|
|
256
|
-
remaining = remaining.slice(italicMatch[0].length);
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
288
|
const nextSpecial = findNextSpecialChar(remaining);
|
|
261
289
|
if (nextSpecial > 0) {
|
|
262
290
|
tokens.push({ type: "text", content: remaining.slice(0, nextSpecial) });
|
|
@@ -367,17 +395,30 @@ function ReferenceMarker({ kind, number, children }) {
|
|
|
367
395
|
}
|
|
368
396
|
);
|
|
369
397
|
}
|
|
370
|
-
|
|
398
|
+
function normalizeReferenceContent(content) {
|
|
399
|
+
return content.replace(/\s+/g, " ").trim().toLowerCase();
|
|
400
|
+
}
|
|
401
|
+
var ReferenceNumberingContext = createContext(null);
|
|
371
402
|
var BlockReferenceScopeContext = createContext(null);
|
|
372
|
-
function BlockReferenceScope({
|
|
373
|
-
const
|
|
374
|
-
const
|
|
403
|
+
function BlockReferenceScope({ children }) {
|
|
404
|
+
const numbering = useContext(ReferenceNumberingContext);
|
|
405
|
+
const local = useRef({ ref: /* @__PURE__ */ new Map(), footnote: /* @__PURE__ */ new Map() });
|
|
375
406
|
const counter = useRef({ ref: 0, footnote: 0 });
|
|
376
|
-
counter.current = { ref: 0, footnote: 0 };
|
|
377
407
|
const value = {
|
|
408
|
+
numberFor(kind, content) {
|
|
409
|
+
const key = normalizeReferenceContent(content);
|
|
410
|
+
const fromDocument = numbering?.[kind].get(key);
|
|
411
|
+
if (fromDocument !== void 0) return fromDocument;
|
|
412
|
+
const map = local.current[kind];
|
|
413
|
+
const existing = map.get(key);
|
|
414
|
+
if (existing !== void 0) return existing;
|
|
415
|
+
counter.current[kind] += 1;
|
|
416
|
+
map.set(key, counter.current[kind]);
|
|
417
|
+
return counter.current[kind];
|
|
418
|
+
},
|
|
378
419
|
next(kind) {
|
|
379
420
|
counter.current[kind] += 1;
|
|
380
|
-
return
|
|
421
|
+
return counter.current[kind];
|
|
381
422
|
}
|
|
382
423
|
};
|
|
383
424
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value, children });
|
|
@@ -385,7 +426,7 @@ function BlockReferenceScope({ blockId, children }) {
|
|
|
385
426
|
function useBlockReferenceScope() {
|
|
386
427
|
return useContext(BlockReferenceScopeContext);
|
|
387
428
|
}
|
|
388
|
-
var INERT_SCOPE = { next: () => 0 };
|
|
429
|
+
var INERT_SCOPE = { numberFor: () => 0, next: () => 0 };
|
|
389
430
|
function InertReferenceScope({ children }) {
|
|
390
431
|
return /* @__PURE__ */ jsx(BlockReferenceScopeContext.Provider, { value: INERT_SCOPE, children });
|
|
391
432
|
}
|
|
@@ -676,7 +717,7 @@ function TokenRenderer({ token, disableBionic, disableBeeline }) {
|
|
|
676
717
|
);
|
|
677
718
|
}
|
|
678
719
|
case "inline_ref": {
|
|
679
|
-
const number = refScope?.
|
|
720
|
+
const number = refScope?.numberFor(token.kind, token.content) ?? 0;
|
|
680
721
|
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 });
|
|
681
722
|
}
|
|
682
723
|
default:
|
|
@@ -742,8 +783,32 @@ function renderReadingText(content, opts) {
|
|
|
742
783
|
if (cursor < content.length) pieces.push(content.slice(cursor));
|
|
743
784
|
return /* @__PURE__ */ jsx(Fragment, { children: pieces });
|
|
744
785
|
}
|
|
786
|
+
function quoteBlocks(block) {
|
|
787
|
+
try {
|
|
788
|
+
const doc = parseNcm(block.content, {
|
|
789
|
+
preset: "ncm-full",
|
|
790
|
+
allowMissingFrontmatter: true,
|
|
791
|
+
// Attribution off, as the NUU Editor's bridge keeps it: the promoter's
|
|
792
|
+
// trigger is any last quote line starting with `-`, so a nested quote
|
|
793
|
+
// ending in a list item would lose that item to a `— Author` line.
|
|
794
|
+
blockOptions: { extensions: { attribution: false } }
|
|
795
|
+
});
|
|
796
|
+
const blocks = doc.blocks ?? [];
|
|
797
|
+
if (blocks.length === 0 || blocks.some((child) => child.type === "frontmatter")) {
|
|
798
|
+
return null;
|
|
799
|
+
}
|
|
800
|
+
return blocks.map((child, index) => ({ ...child, id: `${block.id}.${index + 1}`, stableId: void 0 }));
|
|
801
|
+
} catch {
|
|
802
|
+
return null;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
function QuotedLines({ content }) {
|
|
806
|
+
const lines = content.split("\n");
|
|
807
|
+
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)) });
|
|
808
|
+
}
|
|
745
809
|
function BlockquoteBlock({ block, className }) {
|
|
746
|
-
const
|
|
810
|
+
const multiline = block.content.includes("\n");
|
|
811
|
+
const blocks = useMemo(() => multiline ? quoteBlocks(block) : null, [block, multiline]);
|
|
747
812
|
return /* @__PURE__ */ jsx(
|
|
748
813
|
"blockquote",
|
|
749
814
|
{
|
|
@@ -753,7 +818,9 @@ function BlockquoteBlock({ block, className }) {
|
|
|
753
818
|
"data-block-id": block.id,
|
|
754
819
|
"data-ncm-blockquote": "",
|
|
755
820
|
className,
|
|
756
|
-
children:
|
|
821
|
+
children: !multiline ? /* @__PURE__ */ jsx(InlineContent, { content: block.content }) : blocks === null ? /* @__PURE__ */ jsx(QuotedLines, { content: block.content }) : blocks.map(
|
|
822
|
+
(child) => child.type === "paragraph" ? /* @__PURE__ */ jsx(QuotedLines, { content: child.content ?? "" }, blockKey(child)) : /* @__PURE__ */ jsx(NcmBlock, { block: child }, blockKey(child))
|
|
823
|
+
)
|
|
757
824
|
}
|
|
758
825
|
);
|
|
759
826
|
}
|