@bendyline/squisq-react 1.4.0 → 1.4.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.
- package/README.md +57 -23
- package/dist/index.d.ts +70 -21
- package/dist/index.js +379 -164
- package/dist/index.js.map +1 -1
- package/dist/squisq-player.css +1 -1
- package/dist/squisq-player.css.map +1 -1
- package/dist/squisq-player.global.js +49 -17
- package/dist/squisq-player.global.js.map +1 -1
- package/dist/standalone-source.js +1 -1
- package/dist/styles/index.css +2263 -0
- package/package.json +8 -5
- package/src/DocPlayer.tsx +160 -46
- package/src/DocPlayerWithSidebar.tsx +21 -9
- package/src/LinearDocView.tsx +59 -10
- package/src/MarkdownRenderer.tsx +52 -35
- package/src/__tests__/DocPlayer.test.tsx +34 -4
- package/src/__tests__/DocPlayerStylesSentinel.test.tsx +41 -0
- package/src/__tests__/LinearDocView.test.tsx +53 -1
- package/src/__tests__/MarkdownRenderer.test.tsx +18 -0
- package/src/__tests__/useJsonViewTokens.test.ts +41 -0
- package/src/__tests__/useSlideSwipe.test.ts +81 -0
- package/src/hooks/{AudioProvider.ts → AudioController.ts} +3 -3
- package/src/hooks/index.ts +7 -2
- package/src/hooks/useAudioSync.ts +5 -4
- package/src/hooks/useSlideSwipe.ts +265 -0
- package/src/index.ts +1 -1
- package/src/jsonView/useJsonViewTokens.ts +6 -31
- package/src/standalone-entry.tsx +1 -1
- package/src/styles/doc-animations.css +46 -0
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/DocPlayer.tsx
|
|
2
|
-
import { Fragment as Fragment3, useRef as
|
|
2
|
+
import { Fragment as Fragment3, useRef as useRef7, useState as useState7, useEffect as useEffect8, useCallback as useCallback6, useMemo as useMemo9 } from "react";
|
|
3
3
|
import {
|
|
4
4
|
isTemplateBlock as isTemplateBlock2,
|
|
5
5
|
getCaptionAtTime as getCaptionAtTime2,
|
|
@@ -2245,16 +2245,164 @@ function useViewportOrientation() {
|
|
|
2245
2245
|
};
|
|
2246
2246
|
}
|
|
2247
2247
|
|
|
2248
|
+
// src/hooks/useSlideSwipe.ts
|
|
2249
|
+
import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef5, useState as useState5 } from "react";
|
|
2250
|
+
var DISTANCE_RATIO = 0.3;
|
|
2251
|
+
var FLICK_VELOCITY = 0.5;
|
|
2252
|
+
var MIN_FLICK_DISTANCE = 12;
|
|
2253
|
+
var RUBBER_BAND = 0.35;
|
|
2254
|
+
var DEFAULT_SETTLE_MS = 260;
|
|
2255
|
+
function decideSwipe({
|
|
2256
|
+
dx,
|
|
2257
|
+
width,
|
|
2258
|
+
elapsedMs,
|
|
2259
|
+
canNext,
|
|
2260
|
+
canPrev
|
|
2261
|
+
}) {
|
|
2262
|
+
const distanceThreshold = width > 0 ? width * DISTANCE_RATIO : Infinity;
|
|
2263
|
+
const velocity = elapsedMs > 0 ? Math.abs(dx) / elapsedMs : 0;
|
|
2264
|
+
const passesDistance = Math.abs(dx) >= distanceThreshold;
|
|
2265
|
+
const passesFlick = velocity >= FLICK_VELOCITY && Math.abs(dx) >= MIN_FLICK_DISTANCE;
|
|
2266
|
+
if (!passesDistance && !passesFlick) return "snap";
|
|
2267
|
+
if (dx < 0) return canNext ? "next" : "snap";
|
|
2268
|
+
if (dx > 0) return canPrev ? "prev" : "snap";
|
|
2269
|
+
return "snap";
|
|
2270
|
+
}
|
|
2271
|
+
function useSlideSwipe(opts) {
|
|
2272
|
+
const settleMs = opts.settleMs ?? DEFAULT_SETTLE_MS;
|
|
2273
|
+
const [offsetPx, setOffsetPx] = useState5(0);
|
|
2274
|
+
const [phase, setPhase] = useState5("idle");
|
|
2275
|
+
const optsRef = useRef5(opts);
|
|
2276
|
+
optsRef.current = opts;
|
|
2277
|
+
const dragRef = useRef5(null);
|
|
2278
|
+
const phaseRef = useRef5("idle");
|
|
2279
|
+
phaseRef.current = phase;
|
|
2280
|
+
const settleTimer = useRef5(null);
|
|
2281
|
+
const settleRaf = useRef5(null);
|
|
2282
|
+
const clearPending = useCallback4(() => {
|
|
2283
|
+
if (settleTimer.current != null) {
|
|
2284
|
+
clearTimeout(settleTimer.current);
|
|
2285
|
+
settleTimer.current = null;
|
|
2286
|
+
}
|
|
2287
|
+
if (settleRaf.current != null) {
|
|
2288
|
+
cancelAnimationFrame(settleRaf.current);
|
|
2289
|
+
settleRaf.current = null;
|
|
2290
|
+
}
|
|
2291
|
+
}, []);
|
|
2292
|
+
const onPointerDown = useCallback4((e) => {
|
|
2293
|
+
const o = optsRef.current;
|
|
2294
|
+
if (!o.enabled) return;
|
|
2295
|
+
if (phaseRef.current === "settling") return;
|
|
2296
|
+
if (e.pointerType === "mouse" && e.button !== 0) return;
|
|
2297
|
+
const target = e.target;
|
|
2298
|
+
if (target.closest?.("button, a, input, textarea, select, [data-no-swipe]")) return;
|
|
2299
|
+
dragRef.current = {
|
|
2300
|
+
pointerId: e.pointerId,
|
|
2301
|
+
startX: e.clientX,
|
|
2302
|
+
startTime: performance.now(),
|
|
2303
|
+
target
|
|
2304
|
+
};
|
|
2305
|
+
try {
|
|
2306
|
+
target.setPointerCapture?.(e.pointerId);
|
|
2307
|
+
} catch {
|
|
2308
|
+
}
|
|
2309
|
+
setPhase("dragging");
|
|
2310
|
+
setOffsetPx(0);
|
|
2311
|
+
}, []);
|
|
2312
|
+
useEffect7(() => {
|
|
2313
|
+
function currentWidth() {
|
|
2314
|
+
return optsRef.current.containerRef.current?.getBoundingClientRect().width ?? 0;
|
|
2315
|
+
}
|
|
2316
|
+
function endDrag(drag) {
|
|
2317
|
+
dragRef.current = null;
|
|
2318
|
+
try {
|
|
2319
|
+
drag.target.releasePointerCapture?.(drag.pointerId);
|
|
2320
|
+
} catch {
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
function settleTo(target, onArrive) {
|
|
2324
|
+
setPhase("settling");
|
|
2325
|
+
settleRaf.current = requestAnimationFrame(() => {
|
|
2326
|
+
settleRaf.current = null;
|
|
2327
|
+
setOffsetPx(target);
|
|
2328
|
+
settleTimer.current = setTimeout(() => {
|
|
2329
|
+
settleTimer.current = null;
|
|
2330
|
+
onArrive?.();
|
|
2331
|
+
setOffsetPx(0);
|
|
2332
|
+
setPhase("idle");
|
|
2333
|
+
}, settleMs);
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
function onMove(e) {
|
|
2337
|
+
const drag = dragRef.current;
|
|
2338
|
+
if (!drag || e.pointerId !== drag.pointerId) return;
|
|
2339
|
+
const o = optsRef.current;
|
|
2340
|
+
const raw = e.clientX - drag.startX;
|
|
2341
|
+
const blocked = raw > 0 && !o.canGoPrev || raw < 0 && !o.canGoNext;
|
|
2342
|
+
setOffsetPx(blocked ? raw * RUBBER_BAND : raw);
|
|
2343
|
+
}
|
|
2344
|
+
function onUp(e) {
|
|
2345
|
+
const drag = dragRef.current;
|
|
2346
|
+
if (!drag || e.pointerId !== drag.pointerId) return;
|
|
2347
|
+
endDrag(drag);
|
|
2348
|
+
const o = optsRef.current;
|
|
2349
|
+
const rawDx = e.clientX - drag.startX;
|
|
2350
|
+
const width = currentWidth();
|
|
2351
|
+
const elapsedMs = performance.now() - drag.startTime;
|
|
2352
|
+
const decision = decideSwipe({
|
|
2353
|
+
dx: rawDx,
|
|
2354
|
+
width,
|
|
2355
|
+
elapsedMs,
|
|
2356
|
+
canNext: o.canGoNext,
|
|
2357
|
+
canPrev: o.canGoPrev
|
|
2358
|
+
});
|
|
2359
|
+
if (decision === "snap") {
|
|
2360
|
+
settleTo(0);
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
const distance = Math.max(width, Math.abs(rawDx));
|
|
2364
|
+
const target = decision === "next" ? -distance : distance;
|
|
2365
|
+
settleTo(target, decision === "next" ? o.onNext : o.onPrev);
|
|
2366
|
+
}
|
|
2367
|
+
function onCancel(e) {
|
|
2368
|
+
const drag = dragRef.current;
|
|
2369
|
+
if (!drag || e.pointerId !== drag.pointerId) return;
|
|
2370
|
+
endDrag(drag);
|
|
2371
|
+
settleTo(0);
|
|
2372
|
+
}
|
|
2373
|
+
window.addEventListener("pointermove", onMove);
|
|
2374
|
+
window.addEventListener("pointerup", onUp);
|
|
2375
|
+
window.addEventListener("pointercancel", onCancel);
|
|
2376
|
+
return () => {
|
|
2377
|
+
window.removeEventListener("pointermove", onMove);
|
|
2378
|
+
window.removeEventListener("pointerup", onUp);
|
|
2379
|
+
window.removeEventListener("pointercancel", onCancel);
|
|
2380
|
+
};
|
|
2381
|
+
}, [settleMs]);
|
|
2382
|
+
useEffect7(() => {
|
|
2383
|
+
if (!opts.enabled) {
|
|
2384
|
+
dragRef.current = null;
|
|
2385
|
+
clearPending();
|
|
2386
|
+
setPhase("idle");
|
|
2387
|
+
setOffsetPx(0);
|
|
2388
|
+
}
|
|
2389
|
+
}, [opts.enabled, clearPending]);
|
|
2390
|
+
useEffect7(() => clearPending, [clearPending]);
|
|
2391
|
+
return { offsetPx, phase, onPointerDown };
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2248
2394
|
// src/DocPlayer.tsx
|
|
2249
2395
|
import {
|
|
2250
2396
|
expandCoverBlock,
|
|
2251
2397
|
createTemplateContext,
|
|
2398
|
+
markdownToDoc as markdownToDoc2,
|
|
2252
2399
|
DEFAULT_THEME as DEFAULT_THEME3,
|
|
2253
2400
|
VIEWPORT_PRESETS as VIEWPORT_PRESETS4
|
|
2254
2401
|
} from "@bendyline/squisq/doc";
|
|
2402
|
+
import { parseMarkdown as parseMarkdown2 } from "@bendyline/squisq/markdown";
|
|
2255
2403
|
|
|
2256
2404
|
// src/DocProgressBar.tsx
|
|
2257
|
-
import { useRef as
|
|
2405
|
+
import { useRef as useRef6, useState as useState6, useCallback as useCallback5 } from "react";
|
|
2258
2406
|
|
|
2259
2407
|
// src/types.ts
|
|
2260
2408
|
function formatTime(seconds) {
|
|
@@ -2272,10 +2420,10 @@ function DocProgressBar({
|
|
|
2272
2420
|
expandedBlocks,
|
|
2273
2421
|
getBlockTitle
|
|
2274
2422
|
}) {
|
|
2275
|
-
const progressBarRef =
|
|
2276
|
-
const [hoverPosition, setHoverPosition] =
|
|
2423
|
+
const progressBarRef = useRef6(null);
|
|
2424
|
+
const [hoverPosition, setHoverPosition] = useState6(null);
|
|
2277
2425
|
const playProgress = state.totalDuration > 0 ? Math.max(0, Math.min(1, state.currentTime / state.totalDuration)) : 0;
|
|
2278
|
-
const handleProgressHover =
|
|
2426
|
+
const handleProgressHover = useCallback5((e) => {
|
|
2279
2427
|
const bar = progressBarRef.current;
|
|
2280
2428
|
if (!bar) return;
|
|
2281
2429
|
const rect = bar.getBoundingClientRect();
|
|
@@ -2283,10 +2431,10 @@ function DocProgressBar({
|
|
|
2283
2431
|
const progress = Math.max(0, Math.min(1, x / rect.width));
|
|
2284
2432
|
setHoverPosition(progress);
|
|
2285
2433
|
}, []);
|
|
2286
|
-
const handleProgressLeave =
|
|
2434
|
+
const handleProgressLeave = useCallback5(() => {
|
|
2287
2435
|
setHoverPosition(null);
|
|
2288
2436
|
}, []);
|
|
2289
|
-
const getBlockAtTimeLocal =
|
|
2437
|
+
const getBlockAtTimeLocal = useCallback5(
|
|
2290
2438
|
(time) => {
|
|
2291
2439
|
for (let i = expandedBlocks.length - 1; i >= 0; i--) {
|
|
2292
2440
|
const blk = expandedBlocks[i];
|
|
@@ -2681,8 +2829,14 @@ import {
|
|
|
2681
2829
|
resolveFontFamily as resolveFontFamily2
|
|
2682
2830
|
} from "@bendyline/squisq/schemas";
|
|
2683
2831
|
import { VIEWPORT_PRESETS as VIEWPORT_PRESETS3 } from "@bendyline/squisq/schemas";
|
|
2684
|
-
import {
|
|
2685
|
-
|
|
2832
|
+
import {
|
|
2833
|
+
getLayers,
|
|
2834
|
+
hasTemplate,
|
|
2835
|
+
markdownToDoc,
|
|
2836
|
+
DEFAULT_THEME as DEFAULT_THEME2,
|
|
2837
|
+
deriveTemplateInputs
|
|
2838
|
+
} from "@bendyline/squisq/doc";
|
|
2839
|
+
import { extractPlainText, parseMarkdown } from "@bendyline/squisq/markdown";
|
|
2686
2840
|
|
|
2687
2841
|
// src/MarkdownRenderer.tsx
|
|
2688
2842
|
import { Fragment as Fragment2 } from "react";
|
|
@@ -2737,7 +2891,8 @@ function InlineAudioPlayer({
|
|
|
2737
2891
|
|
|
2738
2892
|
// src/MarkdownRenderer.tsx
|
|
2739
2893
|
import { jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2740
|
-
|
|
2894
|
+
var DEFAULT_CTX = { htmlPolicy: "sanitize" };
|
|
2895
|
+
function renderInline(nodes, keyPrefix = "", ctx = DEFAULT_CTX) {
|
|
2741
2896
|
return nodes.map((node, i) => {
|
|
2742
2897
|
const key = `${keyPrefix}i${i}`;
|
|
2743
2898
|
switch (node.type) {
|
|
@@ -2752,17 +2907,17 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2752
2907
|
] }, j)) }, key);
|
|
2753
2908
|
}
|
|
2754
2909
|
case "emphasis":
|
|
2755
|
-
return /* @__PURE__ */ jsx18("em", { className: "squisq-md-em", children: renderInline(node.children, key,
|
|
2910
|
+
return /* @__PURE__ */ jsx18("em", { className: "squisq-md-em", children: renderInline(node.children, key, ctx) }, key);
|
|
2756
2911
|
case "strong":
|
|
2757
|
-
return /* @__PURE__ */ jsx18("strong", { className: "squisq-md-strong", children: renderInline(node.children, key,
|
|
2912
|
+
return /* @__PURE__ */ jsx18("strong", { className: "squisq-md-strong", children: renderInline(node.children, key, ctx) }, key);
|
|
2758
2913
|
case "delete":
|
|
2759
|
-
return /* @__PURE__ */ jsx18("del", { className: "squisq-md-del", children: renderInline(node.children, key,
|
|
2914
|
+
return /* @__PURE__ */ jsx18("del", { className: "squisq-md-del", children: renderInline(node.children, key, ctx) }, key);
|
|
2760
2915
|
case "inlineCode":
|
|
2761
2916
|
return /* @__PURE__ */ jsx18("code", { className: "squisq-md-inline-code", children: node.value }, key);
|
|
2762
2917
|
case "link": {
|
|
2763
|
-
const href = sanitizeUrl(node.url, "link");
|
|
2918
|
+
const href = sanitizeUrl(node.url, "link", { extraLinkSchemes: ctx.linkSchemes });
|
|
2764
2919
|
if (!href) {
|
|
2765
|
-
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-link squisq-md-link--blocked", children: renderInline(node.children, key,
|
|
2920
|
+
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-link squisq-md-link--blocked", children: renderInline(node.children, key, ctx) }, key);
|
|
2766
2921
|
}
|
|
2767
2922
|
return /* @__PURE__ */ jsx18(
|
|
2768
2923
|
"a",
|
|
@@ -2772,7 +2927,7 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2772
2927
|
title: node.title ?? void 0,
|
|
2773
2928
|
target: "_blank",
|
|
2774
2929
|
rel: "noopener noreferrer",
|
|
2775
|
-
children: renderInline(node.children, key,
|
|
2930
|
+
children: renderInline(node.children, key, ctx)
|
|
2776
2931
|
},
|
|
2777
2932
|
key
|
|
2778
2933
|
);
|
|
@@ -2784,8 +2939,8 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2784
2939
|
case "inlineMath":
|
|
2785
2940
|
return /* @__PURE__ */ jsx18("code", { className: "squisq-md-inline-math", children: node.value }, key);
|
|
2786
2941
|
case "htmlInline":
|
|
2787
|
-
if (htmlPolicy === "strip") return null;
|
|
2788
|
-
if (htmlPolicy === "trusted" && !containsMediaTag(node.htmlChildren) && !containsDangerousTag(node.htmlChildren) && !hasDangerousRawHtml(node.rawHtml)) {
|
|
2942
|
+
if (ctx.htmlPolicy === "strip") return null;
|
|
2943
|
+
if (ctx.htmlPolicy === "trusted" && !containsMediaTag(node.htmlChildren) && !containsDangerousTag(node.htmlChildren) && !hasDangerousRawHtml(node.rawHtml)) {
|
|
2789
2944
|
return /* @__PURE__ */ jsx18(
|
|
2790
2945
|
"span",
|
|
2791
2946
|
{
|
|
@@ -2795,7 +2950,7 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2795
2950
|
key
|
|
2796
2951
|
);
|
|
2797
2952
|
}
|
|
2798
|
-
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-html-inline", children: renderHtmlNodes(resolveHtmlNodes(node.htmlChildren, htmlPolicy), `${key}h`) }, key);
|
|
2953
|
+
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-html-inline", children: renderHtmlNodes(resolveHtmlNodes(node.htmlChildren, ctx.htmlPolicy), `${key}h`) }, key);
|
|
2799
2954
|
case "footnoteReference":
|
|
2800
2955
|
return /* @__PURE__ */ jsx18("sup", { className: "squisq-md-footnote-ref", children: /* @__PURE__ */ jsxs11("a", { href: `#fn-${node.identifier}`, children: [
|
|
2801
2956
|
"[",
|
|
@@ -2803,7 +2958,7 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2803
2958
|
"]"
|
|
2804
2959
|
] }) }, key);
|
|
2805
2960
|
case "linkReference":
|
|
2806
|
-
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-link-ref", children: renderInline(node.children, key,
|
|
2961
|
+
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-link-ref", children: renderInline(node.children, key, ctx) }, key);
|
|
2807
2962
|
case "imageReference":
|
|
2808
2963
|
return /* @__PURE__ */ jsxs11("span", { className: "squisq-md-image-ref", children: [
|
|
2809
2964
|
"[",
|
|
@@ -2811,7 +2966,7 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2811
2966
|
"]"
|
|
2812
2967
|
] }, key);
|
|
2813
2968
|
case "textDirective":
|
|
2814
|
-
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-text-directive", "data-directive": node.name, children: renderInline(node.children, key,
|
|
2969
|
+
return /* @__PURE__ */ jsx18("span", { className: "squisq-md-text-directive", "data-directive": node.name, children: renderInline(node.children, key, ctx) }, key);
|
|
2815
2970
|
case "mention":
|
|
2816
2971
|
return /* @__PURE__ */ jsxs11(
|
|
2817
2972
|
"span",
|
|
@@ -2833,30 +2988,30 @@ function renderInline(nodes, keyPrefix = "", htmlPolicy = "sanitize") {
|
|
|
2833
2988
|
}
|
|
2834
2989
|
});
|
|
2835
2990
|
}
|
|
2836
|
-
function renderBlock(node, key,
|
|
2991
|
+
function renderBlock(node, key, ctx = DEFAULT_CTX) {
|
|
2837
2992
|
switch (node.type) {
|
|
2838
2993
|
case "paragraph":
|
|
2839
|
-
return /* @__PURE__ */ jsx18("p", { className: "squisq-md-p", children: renderInline(node.children, key,
|
|
2994
|
+
return /* @__PURE__ */ jsx18("p", { className: "squisq-md-p", children: renderInline(node.children, key, ctx) }, key);
|
|
2840
2995
|
case "heading": {
|
|
2841
2996
|
const Tag = `h${node.depth}`;
|
|
2842
|
-
return /* @__PURE__ */ jsx18(Tag, { className: `squisq-md-heading squisq-md-h${node.depth}`, children: renderInline(node.children, key,
|
|
2997
|
+
return /* @__PURE__ */ jsx18(Tag, { className: `squisq-md-heading squisq-md-h${node.depth}`, children: renderInline(node.children, key, ctx) }, key);
|
|
2843
2998
|
}
|
|
2844
2999
|
case "blockquote":
|
|
2845
|
-
return /* @__PURE__ */ jsx18("blockquote", { className: "squisq-md-blockquote", children: renderBlocks(node.children, key,
|
|
3000
|
+
return /* @__PURE__ */ jsx18("blockquote", { className: "squisq-md-blockquote", children: renderBlocks(node.children, key, ctx) }, key);
|
|
2846
3001
|
case "list":
|
|
2847
3002
|
if (node.ordered) {
|
|
2848
|
-
return /* @__PURE__ */ jsx18("ol", { className: "squisq-md-list squisq-md-ol", start: node.start ?? void 0, children: node.children.map((item, i) => renderListItem(item, `${key}li${i}`,
|
|
3003
|
+
return /* @__PURE__ */ jsx18("ol", { className: "squisq-md-list squisq-md-ol", start: node.start ?? void 0, children: node.children.map((item, i) => renderListItem(item, `${key}li${i}`, ctx)) }, key);
|
|
2849
3004
|
}
|
|
2850
|
-
return /* @__PURE__ */ jsx18("ul", { className: "squisq-md-list squisq-md-ul", children: node.children.map((item, i) => renderListItem(item, `${key}li${i}`,
|
|
3005
|
+
return /* @__PURE__ */ jsx18("ul", { className: "squisq-md-list squisq-md-ul", children: node.children.map((item, i) => renderListItem(item, `${key}li${i}`, ctx)) }, key);
|
|
2851
3006
|
case "code":
|
|
2852
3007
|
return /* @__PURE__ */ jsx18("pre", { className: "squisq-md-code-block", children: /* @__PURE__ */ jsx18("code", { className: node.lang ? `language-${node.lang}` : void 0, children: node.value }) }, key);
|
|
2853
3008
|
case "thematicBreak":
|
|
2854
3009
|
return /* @__PURE__ */ jsx18("hr", { className: "squisq-md-hr" }, key);
|
|
2855
3010
|
case "table":
|
|
2856
|
-
return renderTable(node.children, node.align, key,
|
|
3011
|
+
return renderTable(node.children, node.align, key, ctx);
|
|
2857
3012
|
case "htmlBlock":
|
|
2858
|
-
if (htmlPolicy === "strip") return null;
|
|
2859
|
-
if (htmlPolicy === "trusted" && !containsMediaTag(node.htmlChildren) && !containsDangerousTag(node.htmlChildren) && !hasDangerousRawHtml(node.rawHtml)) {
|
|
3013
|
+
if (ctx.htmlPolicy === "strip") return null;
|
|
3014
|
+
if (ctx.htmlPolicy === "trusted" && !containsMediaTag(node.htmlChildren) && !containsDangerousTag(node.htmlChildren) && !hasDangerousRawHtml(node.rawHtml)) {
|
|
2860
3015
|
return /* @__PURE__ */ jsx18(
|
|
2861
3016
|
"div",
|
|
2862
3017
|
{
|
|
@@ -2866,7 +3021,7 @@ function renderBlock(node, key, htmlPolicy = "sanitize") {
|
|
|
2866
3021
|
key
|
|
2867
3022
|
);
|
|
2868
3023
|
}
|
|
2869
|
-
return /* @__PURE__ */ jsx18("div", { className: "squisq-md-html-block", children: renderHtmlNodes(resolveHtmlNodes(node.htmlChildren, htmlPolicy), `${key}h`) }, key);
|
|
3024
|
+
return /* @__PURE__ */ jsx18("div", { className: "squisq-md-html-block", children: renderHtmlNodes(resolveHtmlNodes(node.htmlChildren, ctx.htmlPolicy), `${key}h`) }, key);
|
|
2870
3025
|
case "math":
|
|
2871
3026
|
return /* @__PURE__ */ jsx18("pre", { className: "squisq-md-math-block", children: /* @__PURE__ */ jsx18("code", { children: node.value }) }, key);
|
|
2872
3027
|
case "definition":
|
|
@@ -2874,7 +3029,7 @@ function renderBlock(node, key, htmlPolicy = "sanitize") {
|
|
|
2874
3029
|
case "footnoteDefinition":
|
|
2875
3030
|
return /* @__PURE__ */ jsxs11("div", { className: "squisq-md-footnote-def", id: `fn-${node.identifier}`, children: [
|
|
2876
3031
|
/* @__PURE__ */ jsx18("sup", { children: node.label ?? node.identifier }),
|
|
2877
|
-
renderBlocks(node.children, key,
|
|
3032
|
+
renderBlocks(node.children, key, ctx)
|
|
2878
3033
|
] }, key);
|
|
2879
3034
|
case "containerDirective":
|
|
2880
3035
|
return /* @__PURE__ */ jsxs11(
|
|
@@ -2884,7 +3039,7 @@ function renderBlock(node, key, htmlPolicy = "sanitize") {
|
|
|
2884
3039
|
"data-directive": node.name,
|
|
2885
3040
|
children: [
|
|
2886
3041
|
node.label && /* @__PURE__ */ jsx18("div", { className: "squisq-md-directive-label", children: node.label }),
|
|
2887
|
-
renderBlocks(node.children, key,
|
|
3042
|
+
renderBlocks(node.children, key, ctx)
|
|
2888
3043
|
]
|
|
2889
3044
|
},
|
|
2890
3045
|
key
|
|
@@ -2895,29 +3050,29 @@ function renderBlock(node, key, htmlPolicy = "sanitize") {
|
|
|
2895
3050
|
{
|
|
2896
3051
|
className: `squisq-md-directive squisq-md-directive-${node.name}`,
|
|
2897
3052
|
"data-directive": node.name,
|
|
2898
|
-
children: renderInline(node.children, key,
|
|
3053
|
+
children: renderInline(node.children, key, ctx)
|
|
2899
3054
|
},
|
|
2900
3055
|
key
|
|
2901
3056
|
);
|
|
2902
3057
|
case "definitionList":
|
|
2903
3058
|
return /* @__PURE__ */ jsx18("dl", { className: "squisq-md-dl", children: node.children.map((child, i) => {
|
|
2904
3059
|
if (child.type === "definitionTerm") {
|
|
2905
|
-
return /* @__PURE__ */ jsx18("dt", { className: "squisq-md-dt", children: renderInline(child.children, `${key}dt${i}`,
|
|
3060
|
+
return /* @__PURE__ */ jsx18("dt", { className: "squisq-md-dt", children: renderInline(child.children, `${key}dt${i}`, ctx) }, `${key}dt${i}`);
|
|
2906
3061
|
}
|
|
2907
|
-
return /* @__PURE__ */ jsx18("dd", { className: "squisq-md-dd", children: renderBlocks(child.children, `${key}dd${i}`,
|
|
3062
|
+
return /* @__PURE__ */ jsx18("dd", { className: "squisq-md-dd", children: renderBlocks(child.children, `${key}dd${i}`, ctx) }, `${key}dd${i}`);
|
|
2908
3063
|
}) }, key);
|
|
2909
3064
|
default:
|
|
2910
3065
|
return null;
|
|
2911
3066
|
}
|
|
2912
3067
|
}
|
|
2913
|
-
function renderListItem(item, key,
|
|
3068
|
+
function renderListItem(item, key, ctx = DEFAULT_CTX) {
|
|
2914
3069
|
const isTask = item.checked !== null && item.checked !== void 0;
|
|
2915
3070
|
return /* @__PURE__ */ jsxs11("li", { className: `squisq-md-li${isTask ? " squisq-md-task" : ""}`, children: [
|
|
2916
3071
|
isTask && /* @__PURE__ */ jsx18("input", { type: "checkbox", checked: !!item.checked, readOnly: true, className: "squisq-md-checkbox" }),
|
|
2917
|
-
renderBlocks(item.children, key,
|
|
3072
|
+
renderBlocks(item.children, key, ctx)
|
|
2918
3073
|
] }, key);
|
|
2919
3074
|
}
|
|
2920
|
-
function renderTable(rows, align, key,
|
|
3075
|
+
function renderTable(rows, align, key, ctx = DEFAULT_CTX) {
|
|
2921
3076
|
const [headerRow, ...bodyRows] = rows;
|
|
2922
3077
|
return /* @__PURE__ */ jsxs11("table", { className: "squisq-md-table", children: [
|
|
2923
3078
|
headerRow && /* @__PURE__ */ jsx18("thead", { children: /* @__PURE__ */ jsx18("tr", { children: headerRow.children.map((cell, ci) => /* @__PURE__ */ jsx18(
|
|
@@ -2925,7 +3080,7 @@ function renderTable(rows, align, key, htmlPolicy = "sanitize") {
|
|
|
2925
3080
|
{
|
|
2926
3081
|
className: "squisq-md-th",
|
|
2927
3082
|
style: align?.[ci] ? { textAlign: align[ci] } : void 0,
|
|
2928
|
-
children: renderInline(cell.children, `${key}th${ci}`,
|
|
3083
|
+
children: renderInline(cell.children, `${key}th${ci}`, ctx)
|
|
2929
3084
|
},
|
|
2930
3085
|
`${key}th${ci}`
|
|
2931
3086
|
)) }) }),
|
|
@@ -2934,14 +3089,14 @@ function renderTable(rows, align, key, htmlPolicy = "sanitize") {
|
|
|
2934
3089
|
{
|
|
2935
3090
|
className: "squisq-md-td",
|
|
2936
3091
|
style: align?.[ci] ? { textAlign: align[ci] } : void 0,
|
|
2937
|
-
children: renderInline(cell.children, `${key}td${ri}-${ci}`,
|
|
3092
|
+
children: renderInline(cell.children, `${key}td${ri}-${ci}`, ctx)
|
|
2938
3093
|
},
|
|
2939
3094
|
`${key}td${ri}-${ci}`
|
|
2940
3095
|
)) }, `${key}tr${ri}`)) })
|
|
2941
3096
|
] }, key);
|
|
2942
3097
|
}
|
|
2943
|
-
function renderBlocks(nodes, keyPrefix = "",
|
|
2944
|
-
return nodes.map((node, i) => renderBlock(node, `${keyPrefix}b${i}`,
|
|
3098
|
+
function renderBlocks(nodes, keyPrefix = "", ctx = DEFAULT_CTX) {
|
|
3099
|
+
return nodes.map((node, i) => renderBlock(node, `${keyPrefix}b${i}`, ctx));
|
|
2945
3100
|
}
|
|
2946
3101
|
function MdImage({ src, alt, title }) {
|
|
2947
3102
|
const safeSrc = sanitizeUrl(src, "media");
|
|
@@ -3070,18 +3225,29 @@ function renderHtmlNodes(nodes, keyPrefix) {
|
|
|
3070
3225
|
function MarkdownRenderer({
|
|
3071
3226
|
nodes,
|
|
3072
3227
|
className,
|
|
3073
|
-
htmlPolicy = "sanitize"
|
|
3228
|
+
htmlPolicy = "sanitize",
|
|
3229
|
+
linkSchemes
|
|
3074
3230
|
}) {
|
|
3075
3231
|
if (!nodes || nodes.length === 0) return null;
|
|
3076
|
-
return /* @__PURE__ */ jsx18("div", { className: `squisq-md ${className || ""}`, children: renderBlocks(nodes, "", htmlPolicy) });
|
|
3232
|
+
return /* @__PURE__ */ jsx18("div", { className: `squisq-md ${className || ""}`, children: renderBlocks(nodes, "", { htmlPolicy, linkSchemes }) });
|
|
3077
3233
|
}
|
|
3078
3234
|
|
|
3079
3235
|
// src/LinearDocView.tsx
|
|
3080
3236
|
import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3237
|
+
var warnedUnknownTemplates = /* @__PURE__ */ new Set();
|
|
3081
3238
|
function isAnnotatedBlock(block) {
|
|
3082
3239
|
const annotation = block.sourceHeading?.templateAnnotation;
|
|
3083
|
-
if (!annotation) return false;
|
|
3084
|
-
|
|
3240
|
+
if (!annotation?.template) return false;
|
|
3241
|
+
if (!hasTemplate(annotation.template)) {
|
|
3242
|
+
if (!warnedUnknownTemplates.has(annotation.template)) {
|
|
3243
|
+
warnedUnknownTemplates.add(annotation.template);
|
|
3244
|
+
console.warn(
|
|
3245
|
+
`[squisq] Unknown template "${annotation.template}" \u2014 rendering the block as plain markdown.`
|
|
3246
|
+
);
|
|
3247
|
+
}
|
|
3248
|
+
return false;
|
|
3249
|
+
}
|
|
3250
|
+
return true;
|
|
3085
3251
|
}
|
|
3086
3252
|
function countAll(blocks) {
|
|
3087
3253
|
let count = 0;
|
|
@@ -3173,6 +3339,7 @@ function BlockSection({ block, basePath, viewport, renderContext, blockIndex })
|
|
|
3173
3339
|
}
|
|
3174
3340
|
function LinearDocView({
|
|
3175
3341
|
doc,
|
|
3342
|
+
markdown,
|
|
3176
3343
|
basePath = "/",
|
|
3177
3344
|
viewport,
|
|
3178
3345
|
className,
|
|
@@ -3182,7 +3349,15 @@ function LinearDocView({
|
|
|
3182
3349
|
imageDisplayMode = "inline"
|
|
3183
3350
|
}) {
|
|
3184
3351
|
const activeViewport = viewport ?? VIEWPORT_PRESETS3.landscape;
|
|
3185
|
-
const
|
|
3352
|
+
const markdownDoc = useMemo8(
|
|
3353
|
+
() => !doc && markdown !== void 0 ? markdownToDoc(parseMarkdown(markdown)) : void 0,
|
|
3354
|
+
[doc, markdown]
|
|
3355
|
+
);
|
|
3356
|
+
const resolvedDoc = doc ?? markdownDoc;
|
|
3357
|
+
const totalBlocks = useMemo8(
|
|
3358
|
+
() => resolvedDoc ? countAll(resolvedDoc.blocks) : 0,
|
|
3359
|
+
[resolvedDoc]
|
|
3360
|
+
);
|
|
3186
3361
|
const autoSurface = useAutoSurface(surface === "auto");
|
|
3187
3362
|
const resolvedSurface = surface === "auto" ? autoSurface : surface;
|
|
3188
3363
|
const renderContext = useMemo8(() => {
|
|
@@ -3198,6 +3373,9 @@ function LinearDocView({
|
|
|
3198
3373
|
};
|
|
3199
3374
|
}, [activeViewport, totalBlocks, theme, resolvedSurface]);
|
|
3200
3375
|
const activeTheme = renderContext.theme;
|
|
3376
|
+
if (!resolvedDoc) {
|
|
3377
|
+
return /* @__PURE__ */ jsx19("div", { className: `squisq-linear squisq-linear--empty ${className || ""}` });
|
|
3378
|
+
}
|
|
3201
3379
|
const bgColor = activeTheme.colors.background;
|
|
3202
3380
|
const textColor = activeTheme.colors.text;
|
|
3203
3381
|
const mutedColor = activeTheme.colors.textMuted;
|
|
@@ -3358,7 +3536,7 @@ function LinearDocView({
|
|
|
3358
3536
|
background: color-mix(in srgb, var(--squisq-linear-primary) 8%, transparent);
|
|
3359
3537
|
}
|
|
3360
3538
|
` }),
|
|
3361
|
-
|
|
3539
|
+
resolvedDoc.blocks.map((block, i) => /* @__PURE__ */ jsx19(
|
|
3362
3540
|
BlockSection,
|
|
3363
3541
|
{
|
|
3364
3542
|
block,
|
|
@@ -3395,9 +3573,9 @@ var SMALL_WORDS = /* @__PURE__ */ new Set([
|
|
|
3395
3573
|
"by",
|
|
3396
3574
|
"is"
|
|
3397
3575
|
]);
|
|
3398
|
-
function buildSegmentTitleMap(
|
|
3576
|
+
function buildSegmentTitleMap(doc) {
|
|
3399
3577
|
const map = /* @__PURE__ */ new Map();
|
|
3400
|
-
for (const block of
|
|
3578
|
+
for (const block of doc.blocks) {
|
|
3401
3579
|
if (isTemplateBlock2(block) && block.template === "sectionHeader" && "title" in block) {
|
|
3402
3580
|
const segIdx = block.audioSegment;
|
|
3403
3581
|
if (!map.has(segIdx)) {
|
|
@@ -3405,9 +3583,9 @@ function buildSegmentTitleMap(script) {
|
|
|
3405
3583
|
}
|
|
3406
3584
|
}
|
|
3407
3585
|
}
|
|
3408
|
-
for (let i = 0; i <
|
|
3586
|
+
for (let i = 0; i < doc.audio.segments.length; i++) {
|
|
3409
3587
|
if (!map.has(i)) {
|
|
3410
|
-
const name =
|
|
3588
|
+
const name = doc.audio.segments[i].name;
|
|
3411
3589
|
if (name === "intro" || name.includes("intro")) {
|
|
3412
3590
|
map.set(i, "Introduction");
|
|
3413
3591
|
} else if (name === "flight-context" || name.includes("flight-context")) {
|
|
@@ -3423,14 +3601,34 @@ function buildSegmentTitleMap(script) {
|
|
|
3423
3601
|
}
|
|
3424
3602
|
return map;
|
|
3425
3603
|
}
|
|
3426
|
-
function
|
|
3427
|
-
|
|
3428
|
-
|
|
3604
|
+
function isDevEnvironment() {
|
|
3605
|
+
try {
|
|
3606
|
+
return typeof process !== "undefined" && process.env.NODE_ENV !== "production";
|
|
3607
|
+
} catch {
|
|
3608
|
+
return false;
|
|
3609
|
+
}
|
|
3610
|
+
}
|
|
3611
|
+
var warnedMissingStyles = false;
|
|
3612
|
+
function DocPlayer(props) {
|
|
3613
|
+
const { doc, markdown } = props;
|
|
3614
|
+
const markdownDoc = useMemo9(
|
|
3615
|
+
() => !doc && markdown !== void 0 ? markdownToDoc2(parseMarkdown2(markdown)) : void 0,
|
|
3616
|
+
[doc, markdown]
|
|
3617
|
+
);
|
|
3618
|
+
const resolvedDoc = doc ?? markdownDoc;
|
|
3619
|
+
if (!resolvedDoc) {
|
|
3620
|
+
return /* @__PURE__ */ jsx20("div", { className: "doc-player doc-player--empty" });
|
|
3621
|
+
}
|
|
3622
|
+
return /* @__PURE__ */ jsx20(DocPlayerContent, { ...props, doc: resolvedDoc });
|
|
3623
|
+
}
|
|
3624
|
+
function DocPlayerContent({
|
|
3625
|
+
doc,
|
|
3626
|
+
basePath = ".",
|
|
3429
3627
|
renderMode = false,
|
|
3430
3628
|
autoPlay = false,
|
|
3431
3629
|
onEnded,
|
|
3432
3630
|
onTimeUpdate,
|
|
3433
|
-
|
|
3631
|
+
audioController: externalAudioController,
|
|
3434
3632
|
showControls = true,
|
|
3435
3633
|
showScrubber = false,
|
|
3436
3634
|
muted = false,
|
|
@@ -3445,14 +3643,15 @@ function DocPlayer({
|
|
|
3445
3643
|
displayMode = "video",
|
|
3446
3644
|
theme,
|
|
3447
3645
|
surface,
|
|
3448
|
-
captionStyle = "standard"
|
|
3646
|
+
captionStyle = "standard",
|
|
3647
|
+
enableSwipe = true
|
|
3449
3648
|
}) {
|
|
3450
3649
|
const isSlideshowMode = displayMode === "slideshow";
|
|
3451
3650
|
const isLinearMode = displayMode === "linear";
|
|
3452
|
-
const audioRef =
|
|
3453
|
-
const containerRef =
|
|
3454
|
-
const [tapFeedback, setTapFeedback] =
|
|
3455
|
-
const tapFeedbackTimer =
|
|
3651
|
+
const audioRef = useRef7(null);
|
|
3652
|
+
const containerRef = useRef7(null);
|
|
3653
|
+
const [tapFeedback, setTapFeedback] = useState7(null);
|
|
3654
|
+
const tapFeedbackTimer = useRef7();
|
|
3456
3655
|
const { viewport, orientation } = useViewportOrientation();
|
|
3457
3656
|
const activeViewport = forceViewport || (renderMode ? VIEWPORT_PRESETS4.landscape : viewport);
|
|
3458
3657
|
const isDebugMode = useMemo9(() => {
|
|
@@ -3460,8 +3659,20 @@ function DocPlayer({
|
|
|
3460
3659
|
const params = new URLSearchParams(window.location.search);
|
|
3461
3660
|
return params.get("debug") === "true";
|
|
3462
3661
|
}, []);
|
|
3463
|
-
const internalAudio = useAudioSync(audioRef,
|
|
3464
|
-
const audio =
|
|
3662
|
+
const internalAudio = useAudioSync(audioRef, doc.audio, basePath);
|
|
3663
|
+
const audio = externalAudioController || internalAudio;
|
|
3664
|
+
useEffect8(() => {
|
|
3665
|
+
if (warnedMissingStyles || !isDevEnvironment()) return;
|
|
3666
|
+
const el = containerRef.current;
|
|
3667
|
+
if (!el || typeof getComputedStyle !== "function") return;
|
|
3668
|
+
const value = getComputedStyle(el).getPropertyValue("--squisq-styles-loaded");
|
|
3669
|
+
if (!value.trim()) {
|
|
3670
|
+
warnedMissingStyles = true;
|
|
3671
|
+
console.warn(
|
|
3672
|
+
'[squisq] @bendyline/squisq-react/styles is not loaded \u2014 import "@bendyline/squisq-react/styles"'
|
|
3673
|
+
);
|
|
3674
|
+
}
|
|
3675
|
+
}, []);
|
|
3465
3676
|
const {
|
|
3466
3677
|
currentTime,
|
|
3467
3678
|
isPlaying,
|
|
@@ -3478,13 +3689,13 @@ function DocPlayer({
|
|
|
3478
3689
|
skipToSegment: _skipToSegment,
|
|
3479
3690
|
restart
|
|
3480
3691
|
} = audio;
|
|
3481
|
-
const mediaSchedule = useMemo9(() => resolveMediaSchedule(
|
|
3482
|
-
const currentTimeRef =
|
|
3692
|
+
const mediaSchedule = useMemo9(() => resolveMediaSchedule(doc), [doc]);
|
|
3693
|
+
const currentTimeRef = useRef7(currentTime);
|
|
3483
3694
|
currentTimeRef.current = currentTime;
|
|
3484
|
-
const totalDurationRef =
|
|
3695
|
+
const totalDurationRef = useRef7(totalDuration);
|
|
3485
3696
|
totalDurationRef.current = totalDuration;
|
|
3486
|
-
const expandedBlocksLenRef =
|
|
3487
|
-
const handleContainerClick =
|
|
3697
|
+
const expandedBlocksLenRef = useRef7(0);
|
|
3698
|
+
const handleContainerClick = useCallback6(
|
|
3488
3699
|
(e) => {
|
|
3489
3700
|
if (renderMode || isSlideshowMode || isLinearMode) return;
|
|
3490
3701
|
const target = e.target;
|
|
@@ -3518,9 +3729,9 @@ function DocPlayer({
|
|
|
3518
3729
|
nextBlock: _nextBlock,
|
|
3519
3730
|
prevBlock: _prevBlock,
|
|
3520
3731
|
blocks: expandedBlocks
|
|
3521
|
-
} = useDocPlayback(
|
|
3732
|
+
} = useDocPlayback(doc, currentTime, activeViewport, renderMode, effectiveTheme);
|
|
3522
3733
|
const coverBlock = useMemo9(() => {
|
|
3523
|
-
const startBlockConfig =
|
|
3734
|
+
const startBlockConfig = doc.startBlock;
|
|
3524
3735
|
if (!startBlockConfig) return null;
|
|
3525
3736
|
const context = createTemplateContext(effectiveTheme, 0, 1, activeViewport);
|
|
3526
3737
|
const layers = expandCoverBlock(startBlockConfig, context);
|
|
@@ -3533,15 +3744,15 @@ function DocPlayer({
|
|
|
3533
3744
|
audioSegment: -1,
|
|
3534
3745
|
layers
|
|
3535
3746
|
};
|
|
3536
|
-
}, [
|
|
3537
|
-
const [coverForced, setCoverForced] =
|
|
3538
|
-
const [coverGraceActive, setCoverGraceActive] =
|
|
3539
|
-
const coverGraceTimer =
|
|
3540
|
-
const coverWasShowing =
|
|
3541
|
-
const hasPlayedOnce =
|
|
3747
|
+
}, [doc.startBlock, activeViewport, effectiveTheme]);
|
|
3748
|
+
const [coverForced, setCoverForced] = useState7(false);
|
|
3749
|
+
const [coverGraceActive, setCoverGraceActive] = useState7(false);
|
|
3750
|
+
const coverGraceTimer = useRef7();
|
|
3751
|
+
const coverWasShowing = useRef7(false);
|
|
3752
|
+
const hasPlayedOnce = useRef7(false);
|
|
3542
3753
|
const atRest = !!(coverBlock && !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
|
|
3543
3754
|
if (atRest) coverWasShowing.current = true;
|
|
3544
|
-
|
|
3755
|
+
useEffect8(() => {
|
|
3545
3756
|
if (isPlaying && coverWasShowing.current && coverBlock && !renderMode) {
|
|
3546
3757
|
coverWasShowing.current = false;
|
|
3547
3758
|
hasPlayedOnce.current = true;
|
|
@@ -3549,24 +3760,24 @@ function DocPlayer({
|
|
|
3549
3760
|
coverGraceTimer.current = setTimeout(() => setCoverGraceActive(false), 3e3);
|
|
3550
3761
|
}
|
|
3551
3762
|
}, [isPlaying, coverBlock, renderMode]);
|
|
3552
|
-
|
|
3763
|
+
useEffect8(() => () => clearTimeout(coverGraceTimer.current), []);
|
|
3553
3764
|
const showCoverBlock = !isSlideshowMode && !isLinearMode && coverBlock && (coverForced || coverGraceActive || !isPlaying && currentTime === 0 && !hasPlayedOnce.current && !renderMode && !autoPlay);
|
|
3554
|
-
const hasAutoPlayed =
|
|
3555
|
-
|
|
3765
|
+
const hasAutoPlayed = useRef7(false);
|
|
3766
|
+
useEffect8(() => {
|
|
3556
3767
|
if (isAudioReady && autoPlay && !hasAutoPlayed.current) {
|
|
3557
3768
|
hasAutoPlayed.current = true;
|
|
3558
3769
|
play();
|
|
3559
3770
|
}
|
|
3560
3771
|
}, [isAudioReady, autoPlay, play]);
|
|
3561
|
-
|
|
3772
|
+
useEffect8(() => {
|
|
3562
3773
|
onTimeUpdate?.(currentTime);
|
|
3563
3774
|
}, [currentTime, onTimeUpdate]);
|
|
3564
|
-
|
|
3775
|
+
useEffect8(() => {
|
|
3565
3776
|
if (isEnded) {
|
|
3566
3777
|
onEnded?.();
|
|
3567
3778
|
}
|
|
3568
3779
|
}, [isEnded, onEnded]);
|
|
3569
|
-
|
|
3780
|
+
useEffect8(() => {
|
|
3570
3781
|
if ((renderMode || isDebugMode) && typeof window !== "undefined") {
|
|
3571
3782
|
const w = window;
|
|
3572
3783
|
w.seekTo = (time) => {
|
|
@@ -3645,7 +3856,7 @@ function DocPlayer({
|
|
|
3645
3856
|
});
|
|
3646
3857
|
};
|
|
3647
3858
|
w.getDuration = () => {
|
|
3648
|
-
const mediaDuration = getDocPlaybackDuration(
|
|
3859
|
+
const mediaDuration = getDocPlaybackDuration(doc);
|
|
3649
3860
|
if (totalDuration > 0) return Math.max(totalDuration, mediaDuration);
|
|
3650
3861
|
return mediaDuration;
|
|
3651
3862
|
};
|
|
@@ -3655,20 +3866,20 @@ function DocPlayer({
|
|
|
3655
3866
|
startTime: s.startTime,
|
|
3656
3867
|
duration: s.duration
|
|
3657
3868
|
}));
|
|
3658
|
-
w.getAudioSegments = () =>
|
|
3869
|
+
w.getAudioSegments = () => doc.audio.segments.map((seg) => ({
|
|
3659
3870
|
src: seg.src,
|
|
3660
3871
|
name: seg.name,
|
|
3661
3872
|
duration: seg.duration,
|
|
3662
3873
|
startTime: seg.startTime
|
|
3663
3874
|
}));
|
|
3664
|
-
w.getCaptions = () =>
|
|
3875
|
+
w.getCaptions = () => doc.captions?.phrases?.map((p) => ({
|
|
3665
3876
|
text: p.text,
|
|
3666
3877
|
startTime: p.startTime,
|
|
3667
3878
|
endTime: p.endTime
|
|
3668
3879
|
})) || [];
|
|
3669
3880
|
w.getChapters = () => {
|
|
3670
|
-
const titleMap = buildSegmentTitleMap(
|
|
3671
|
-
return
|
|
3881
|
+
const titleMap = buildSegmentTitleMap(doc);
|
|
3882
|
+
return doc.audio.segments.map((seg, i) => ({
|
|
3672
3883
|
title: titleMap.get(i) || seg.name,
|
|
3673
3884
|
startTime: seg.startTime,
|
|
3674
3885
|
duration: seg.duration
|
|
@@ -3700,25 +3911,28 @@ function DocPlayer({
|
|
|
3700
3911
|
};
|
|
3701
3912
|
}, [renderMode, isDebugMode, seekTo, totalDuration, expandedBlocks, coverBlock]);
|
|
3702
3913
|
const defaultMode = captionsEnabledProp === false ? "off" : captionStyle || "standard";
|
|
3703
|
-
const [captionMode, setCaptionMode] =
|
|
3914
|
+
const [captionMode, setCaptionMode] = useState7(defaultMode);
|
|
3915
|
+
useEffect8(() => {
|
|
3916
|
+
setCaptionMode(defaultMode);
|
|
3917
|
+
}, [defaultMode]);
|
|
3704
3918
|
const captionsEnabled = captionMode !== "off";
|
|
3705
3919
|
const activeCaptionStyle = captionMode === "social" ? "social" : "standard";
|
|
3706
|
-
const setCaptionsEnabled =
|
|
3920
|
+
const setCaptionsEnabled = useCallback6(
|
|
3707
3921
|
(enabled) => {
|
|
3708
3922
|
setCaptionMode(enabled ? captionStyle || "standard" : "off");
|
|
3709
3923
|
onCaptionsToggle?.(enabled);
|
|
3710
3924
|
},
|
|
3711
3925
|
[onCaptionsToggle, captionStyle]
|
|
3712
3926
|
);
|
|
3713
|
-
const cycleCaptionMode =
|
|
3927
|
+
const cycleCaptionMode = useCallback6(() => {
|
|
3714
3928
|
setCaptionMode((prev) => {
|
|
3715
3929
|
const next = prev === "off" ? "standard" : prev === "standard" ? "social" : "off";
|
|
3716
3930
|
onCaptionsToggle?.(next !== "off");
|
|
3717
3931
|
return next;
|
|
3718
3932
|
});
|
|
3719
3933
|
}, [onCaptionsToggle]);
|
|
3720
|
-
const hasCaptions =
|
|
3721
|
-
const segmentTitleMap = useMemo9(() => buildSegmentTitleMap(
|
|
3934
|
+
const hasCaptions = doc.captions && doc.captions.phrases.length > 0;
|
|
3935
|
+
const segmentTitleMap = useMemo9(() => buildSegmentTitleMap(doc), [doc]);
|
|
3722
3936
|
const playbackState = useMemo9(
|
|
3723
3937
|
() => ({
|
|
3724
3938
|
isPlaying,
|
|
@@ -3732,10 +3946,10 @@ function DocPlayer({
|
|
|
3732
3946
|
captionMode,
|
|
3733
3947
|
isFullscreen,
|
|
3734
3948
|
currentSegmentIndex: currentSegment,
|
|
3735
|
-
currentSegmentName: segmentTitleMap.get(currentSegment) ??
|
|
3949
|
+
currentSegmentName: segmentTitleMap.get(currentSegment) ?? doc.audio.segments[currentSegment]?.name ?? null,
|
|
3736
3950
|
currentBlock: currentBlock ?? null
|
|
3737
3951
|
}),
|
|
3738
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps --
|
|
3952
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- doc.audio.segments is stable within a given doc
|
|
3739
3953
|
[
|
|
3740
3954
|
isPlaying,
|
|
3741
3955
|
currentTime,
|
|
@@ -3795,13 +4009,22 @@ function DocPlayer({
|
|
|
3795
4009
|
}),
|
|
3796
4010
|
[currentBlockIndex, expandedBlocks, seekTo, pause]
|
|
3797
4011
|
);
|
|
3798
|
-
|
|
4012
|
+
const swipeEnabled = isSlideshowMode && !isLinearMode && !renderMode && enableSwipe;
|
|
4013
|
+
const swipe = useSlideSwipe({
|
|
4014
|
+
enabled: swipeEnabled,
|
|
4015
|
+
containerRef,
|
|
4016
|
+
canGoNext: currentBlockIndex < expandedBlocks.length - 1,
|
|
4017
|
+
canGoPrev: currentBlockIndex > 0,
|
|
4018
|
+
onNext: slideNavActions.nextSlide,
|
|
4019
|
+
onPrev: slideNavActions.prevSlide
|
|
4020
|
+
});
|
|
4021
|
+
useEffect8(() => {
|
|
3799
4022
|
onPlaybackStateChange?.(playbackState);
|
|
3800
4023
|
}, [playbackState, onPlaybackStateChange]);
|
|
3801
|
-
|
|
4024
|
+
useEffect8(() => {
|
|
3802
4025
|
onControlsReady?.({ play, pause, ...playbackActions });
|
|
3803
4026
|
}, [play, pause, playbackActions, onControlsReady]);
|
|
3804
|
-
const getBlockTitle =
|
|
4027
|
+
const getBlockTitle = useCallback6((block) => {
|
|
3805
4028
|
const docBlock = block;
|
|
3806
4029
|
if (isTemplateBlock2(docBlock)) {
|
|
3807
4030
|
const props = docBlock;
|
|
@@ -3840,13 +4063,13 @@ function DocPlayer({
|
|
|
3840
4063
|
};
|
|
3841
4064
|
});
|
|
3842
4065
|
}, [expandedBlocks, totalDuration, getBlockTitle]);
|
|
3843
|
-
|
|
4066
|
+
useEffect8(() => {
|
|
3844
4067
|
if (blockMarkers.length > 0) {
|
|
3845
4068
|
onBlockMarkers?.(blockMarkers);
|
|
3846
4069
|
}
|
|
3847
4070
|
}, [blockMarkers, onBlockMarkers]);
|
|
3848
4071
|
expandedBlocksLenRef.current = expandedBlocks.length;
|
|
3849
|
-
const handleKeyDown =
|
|
4072
|
+
const handleKeyDown = useCallback6(
|
|
3850
4073
|
(e) => {
|
|
3851
4074
|
const activeEl = document.activeElement;
|
|
3852
4075
|
if (activeEl && (activeEl.tagName === "INPUT" || activeEl.tagName === "TEXTAREA" || activeEl.tagName === "SELECT")) {
|
|
@@ -3892,7 +4115,7 @@ function DocPlayer({
|
|
|
3892
4115
|
},
|
|
3893
4116
|
[isSlideshowMode, isLinearMode, toggle, seekTo, slideNavActions]
|
|
3894
4117
|
);
|
|
3895
|
-
|
|
4118
|
+
useEffect8(() => {
|
|
3896
4119
|
if (renderMode) return;
|
|
3897
4120
|
window.addEventListener("keydown", handleKeyDown);
|
|
3898
4121
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
@@ -3912,7 +4135,7 @@ function DocPlayer({
|
|
|
3912
4135
|
children: /* @__PURE__ */ jsx20(
|
|
3913
4136
|
LinearDocView,
|
|
3914
4137
|
{
|
|
3915
|
-
doc
|
|
4138
|
+
doc,
|
|
3916
4139
|
basePath,
|
|
3917
4140
|
viewport: activeViewport,
|
|
3918
4141
|
theme,
|
|
@@ -3926,15 +4149,19 @@ function DocPlayer({
|
|
|
3926
4149
|
"div",
|
|
3927
4150
|
{
|
|
3928
4151
|
ref: containerRef,
|
|
3929
|
-
className: "doc-player"
|
|
4152
|
+
className: `doc-player${swipeEnabled ? " doc-player--swipe" : ""}${swipe.phase === "dragging" ? " doc-player--grabbing" : ""}`,
|
|
3930
4153
|
onClick: handleContainerClick,
|
|
4154
|
+
onPointerDown: swipe.onPointerDown,
|
|
3931
4155
|
style: {
|
|
3932
4156
|
position: "relative",
|
|
3933
4157
|
width: "100%",
|
|
3934
4158
|
aspectRatio: `${activeViewport.width} / ${activeViewport.height}`,
|
|
3935
4159
|
margin: "0 auto",
|
|
3936
4160
|
overflow: "hidden",
|
|
3937
|
-
cursor
|
|
4161
|
+
// Swipe uses the grab/grabbing cursor via CSS classes; let vertical page
|
|
4162
|
+
// scroll through on touch while we own horizontal drags.
|
|
4163
|
+
cursor: renderMode || swipeEnabled ? void 0 : "pointer",
|
|
4164
|
+
touchAction: swipeEnabled ? "pan-y" : void 0
|
|
3938
4165
|
},
|
|
3939
4166
|
children: [
|
|
3940
4167
|
/* @__PURE__ */ jsx20("audio", { ref: audioRef, preload: "auto", muted }),
|
|
@@ -3974,21 +4201,29 @@ function DocPlayer({
|
|
|
3974
4201
|
viewport: activeViewport
|
|
3975
4202
|
}
|
|
3976
4203
|
) }, previousBlock.id),
|
|
3977
|
-
!showCoverBlock && currentBlock && /* @__PURE__ */ jsx20(
|
|
3978
|
-
|
|
4204
|
+
!showCoverBlock && currentBlock && /* @__PURE__ */ jsx20(
|
|
4205
|
+
"div",
|
|
3979
4206
|
{
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
4207
|
+
className: `doc-player__block doc-player__block--active${swipe.phase !== "idle" ? ` doc-player__block--${swipe.phase}` : ""}`,
|
|
4208
|
+
style: swipe.phase !== "idle" ? { transform: `translateX(${swipe.offsetPx}px)` } : void 0,
|
|
4209
|
+
children: /* @__PURE__ */ jsx20(
|
|
4210
|
+
BlockRenderer,
|
|
4211
|
+
{
|
|
4212
|
+
block: currentBlock,
|
|
4213
|
+
blockTime,
|
|
4214
|
+
basePath,
|
|
4215
|
+
isEntering,
|
|
4216
|
+
viewport: activeViewport,
|
|
4217
|
+
isPlaying
|
|
4218
|
+
}
|
|
4219
|
+
)
|
|
4220
|
+
},
|
|
4221
|
+
currentBlock.id
|
|
4222
|
+
),
|
|
3988
4223
|
hasCaptions && (renderMode ? captionsEnabled : true) && /* @__PURE__ */ jsx20(
|
|
3989
4224
|
CaptionOverlay,
|
|
3990
4225
|
{
|
|
3991
|
-
captions:
|
|
4226
|
+
captions: doc.captions,
|
|
3992
4227
|
currentTime,
|
|
3993
4228
|
enabled: captionsEnabled && (renderMode || isPlaying || currentTime > 0),
|
|
3994
4229
|
fontSize: 16,
|
|
@@ -4049,9 +4284,8 @@ function DocPlayer({
|
|
|
4049
4284
|
/* @__PURE__ */ jsxs13("span", { style: { color: "#666" }, children: [
|
|
4050
4285
|
"(progress: ",
|
|
4051
4286
|
(docProgress * 100).toFixed(1),
|
|
4052
|
-
"%, scriptDur:",
|
|
4053
|
-
|
|
4054
|
-
script.duration.toFixed(1),
|
|
4287
|
+
"%, scriptDur: ",
|
|
4288
|
+
doc.duration.toFixed(1),
|
|
4055
4289
|
")"
|
|
4056
4290
|
] })
|
|
4057
4291
|
] }),
|
|
@@ -4069,11 +4303,11 @@ function DocPlayer({
|
|
|
4069
4303
|
" ",
|
|
4070
4304
|
currentSegment,
|
|
4071
4305
|
"/",
|
|
4072
|
-
|
|
4306
|
+
doc.audio.segments.length - 1,
|
|
4073
4307
|
" ",
|
|
4074
4308
|
/* @__PURE__ */ jsxs13("span", { style: { color: "#666" }, children: [
|
|
4075
4309
|
"(",
|
|
4076
|
-
|
|
4310
|
+
doc.audio.segments[currentSegment]?.name || "none",
|
|
4077
4311
|
")"
|
|
4078
4312
|
] })
|
|
4079
4313
|
] }),
|
|
@@ -4095,13 +4329,13 @@ function DocPlayer({
|
|
|
4095
4329
|
showCoverBlock && /* @__PURE__ */ jsx20("span", { style: { color: "#60a5fa" }, children: " (cover)" })
|
|
4096
4330
|
] }),
|
|
4097
4331
|
hasCaptions && (() => {
|
|
4098
|
-
const debugPhrase = getCaptionAtTime2(
|
|
4332
|
+
const debugPhrase = getCaptionAtTime2(doc.captions, currentTime);
|
|
4099
4333
|
const debugEnabled = captionsEnabled && (isPlaying || currentTime > 0);
|
|
4100
4334
|
return /* @__PURE__ */ jsxs13(Fragment3, { children: [
|
|
4101
4335
|
/* @__PURE__ */ jsxs13("div", { children: [
|
|
4102
4336
|
/* @__PURE__ */ jsx20("span", { style: { color: "#888" }, children: "captions:" }),
|
|
4103
4337
|
" ",
|
|
4104
|
-
|
|
4338
|
+
doc.captions?.phrases.length || 0,
|
|
4105
4339
|
" phrases",
|
|
4106
4340
|
" ",
|
|
4107
4341
|
/* @__PURE__ */ jsxs13("span", { style: { color: captionsEnabled ? "#4ade80" : "#666" }, children: [
|
|
@@ -4331,7 +4565,7 @@ function DocControlsSidebar({ state, actions }) {
|
|
|
4331
4565
|
}
|
|
4332
4566
|
|
|
4333
4567
|
// src/DocPlayerWithSidebar.tsx
|
|
4334
|
-
import { useRef as
|
|
4568
|
+
import { useRef as useRef8, useState as useState8, useCallback as useCallback7, useEffect as useEffect9 } from "react";
|
|
4335
4569
|
import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4336
4570
|
var DEFAULT_STATE = {
|
|
4337
4571
|
isPlaying: false,
|
|
@@ -4348,24 +4582,25 @@ var DEFAULT_STATE = {
|
|
|
4348
4582
|
currentBlock: null
|
|
4349
4583
|
};
|
|
4350
4584
|
function DocPlayerWithSidebar({
|
|
4351
|
-
|
|
4585
|
+
doc,
|
|
4352
4586
|
basePath,
|
|
4353
4587
|
autoPlay = false,
|
|
4354
4588
|
onEnded,
|
|
4355
4589
|
onTimeUpdate,
|
|
4356
|
-
|
|
4590
|
+
audioController,
|
|
4357
4591
|
muted,
|
|
4358
4592
|
captionsEnabled,
|
|
4359
4593
|
isFullscreen,
|
|
4360
4594
|
onFullscreenToggle,
|
|
4361
4595
|
forceViewport,
|
|
4362
|
-
onPlayingChange
|
|
4596
|
+
onPlayingChange,
|
|
4597
|
+
theme
|
|
4363
4598
|
}) {
|
|
4364
|
-
const stateRef =
|
|
4365
|
-
const actionsRef =
|
|
4366
|
-
const wasPlayingRef =
|
|
4367
|
-
const [, setTick] =
|
|
4368
|
-
const handleStateChange =
|
|
4599
|
+
const stateRef = useRef8(DEFAULT_STATE);
|
|
4600
|
+
const actionsRef = useRef8(null);
|
|
4601
|
+
const wasPlayingRef = useRef8(false);
|
|
4602
|
+
const [, setTick] = useState8(0);
|
|
4603
|
+
const handleStateChange = useCallback7(
|
|
4369
4604
|
(state) => {
|
|
4370
4605
|
stateRef.current = state;
|
|
4371
4606
|
if (onPlayingChange && state.isPlaying !== wasPlayingRef.current) {
|
|
@@ -4375,7 +4610,7 @@ function DocPlayerWithSidebar({
|
|
|
4375
4610
|
},
|
|
4376
4611
|
[onPlayingChange]
|
|
4377
4612
|
);
|
|
4378
|
-
const handleControlsReady =
|
|
4613
|
+
const handleControlsReady = useCallback7(
|
|
4379
4614
|
(controls) => {
|
|
4380
4615
|
const isFirst = !actionsRef.current;
|
|
4381
4616
|
actionsRef.current = controls;
|
|
@@ -4383,7 +4618,7 @@ function DocPlayerWithSidebar({
|
|
|
4383
4618
|
},
|
|
4384
4619
|
[]
|
|
4385
4620
|
);
|
|
4386
|
-
|
|
4621
|
+
useEffect9(() => {
|
|
4387
4622
|
const interval = setInterval(() => {
|
|
4388
4623
|
setTick((t) => t + 1);
|
|
4389
4624
|
}, 250);
|
|
@@ -4393,12 +4628,13 @@ function DocPlayerWithSidebar({
|
|
|
4393
4628
|
/* @__PURE__ */ jsx23("div", { className: "doc-player-sidebar-layout__video", children: /* @__PURE__ */ jsx23(
|
|
4394
4629
|
DocPlayer,
|
|
4395
4630
|
{
|
|
4396
|
-
|
|
4631
|
+
doc,
|
|
4632
|
+
theme,
|
|
4397
4633
|
basePath,
|
|
4398
4634
|
autoPlay,
|
|
4399
4635
|
onEnded,
|
|
4400
4636
|
onTimeUpdate,
|
|
4401
|
-
|
|
4637
|
+
audioController,
|
|
4402
4638
|
muted,
|
|
4403
4639
|
captionsEnabled,
|
|
4404
4640
|
showControls: isFullscreen,
|
|
@@ -4416,36 +4652,15 @@ function DocPlayerWithSidebar({
|
|
|
4416
4652
|
|
|
4417
4653
|
// src/jsonView/useJsonViewTokens.ts
|
|
4418
4654
|
import { useMemo as useMemo10 } from "react";
|
|
4419
|
-
import {
|
|
4420
|
-
applySurface as applySurface3,
|
|
4421
|
-
resolveFontFamily as resolveFontFamily3
|
|
4422
|
-
} from "@bendyline/squisq/schemas";
|
|
4423
|
-
import { DEFAULT_THEME as DEFAULT_THEME4 } from "@bendyline/squisq/doc";
|
|
4655
|
+
import { buildJsonFormTokens, resolveJsonFormTheme } from "@bendyline/squisq/jsonForm";
|
|
4424
4656
|
function useJsonViewTokens(theme, surface) {
|
|
4425
4657
|
const auto = useAutoSurface(surface === "auto");
|
|
4426
4658
|
const effectiveSurface = surface === "auto" ? auto : surface ?? void 0;
|
|
4427
4659
|
return useMemo10(() => {
|
|
4428
|
-
const
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
const monoFont = resolveFontFamily3(
|
|
4433
|
-
finalTheme.typography.monoFont,
|
|
4434
|
-
"ui-monospace, Consolas, monospace"
|
|
4435
|
-
);
|
|
4436
|
-
const style = {
|
|
4437
|
-
["--squisq-json-bg"]: finalTheme.colors.background,
|
|
4438
|
-
["--squisq-json-text"]: finalTheme.colors.text,
|
|
4439
|
-
["--squisq-json-muted"]: finalTheme.colors.textMuted,
|
|
4440
|
-
["--squisq-json-primary"]: finalTheme.colors.primary,
|
|
4441
|
-
["--squisq-json-accent"]: finalTheme.colors.secondary,
|
|
4442
|
-
["--squisq-json-border"]: `color-mix(in srgb, ${finalTheme.colors.textMuted} 35%, transparent)`,
|
|
4443
|
-
["--squisq-json-title-font"]: titleFont,
|
|
4444
|
-
["--squisq-json-body-font"]: bodyFont,
|
|
4445
|
-
["--squisq-json-mono-font"]: monoFont,
|
|
4446
|
-
["--squisq-json-radius"]: `${finalTheme.style.borderRadius ?? 8}px`
|
|
4447
|
-
};
|
|
4448
|
-
return { style, theme: finalTheme };
|
|
4660
|
+
const style = buildJsonFormTokens(theme, effectiveSurface, {
|
|
4661
|
+
prefix: "--squisq-json"
|
|
4662
|
+
});
|
|
4663
|
+
return { style, theme: resolveJsonFormTheme(theme, effectiveSurface) };
|
|
4449
4664
|
}, [theme, effectiveSurface]);
|
|
4450
4665
|
}
|
|
4451
4666
|
|
|
@@ -4461,7 +4676,7 @@ import { Fragment as Fragment4, useMemo as useMemo11 } from "react";
|
|
|
4461
4676
|
import {
|
|
4462
4677
|
arrayItemKind
|
|
4463
4678
|
} from "@bendyline/squisq/jsonForm";
|
|
4464
|
-
import { parseMarkdown } from "@bendyline/squisq/markdown";
|
|
4679
|
+
import { parseMarkdown as parseMarkdown3 } from "@bendyline/squisq/markdown";
|
|
4465
4680
|
import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4466
4681
|
function TextViewer({ value }) {
|
|
4467
4682
|
if (value === void 0 || value === null || value === "") {
|
|
@@ -4479,7 +4694,7 @@ function RichTextViewer({ value }) {
|
|
|
4479
4694
|
const nodes = useMemo11(() => {
|
|
4480
4695
|
if (typeof value !== "string" || value === "") return null;
|
|
4481
4696
|
try {
|
|
4482
|
-
const doc =
|
|
4697
|
+
const doc = parseMarkdown3(value);
|
|
4483
4698
|
return doc.children;
|
|
4484
4699
|
} catch {
|
|
4485
4700
|
return null;
|