@owomark/view 0.1.4 → 0.1.6
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 +16 -281
- package/dist/{chunk-Y72HQJQI.js → chunk-KHKPOH74.js} +2 -3
- package/dist/{chunk-F3LG7AML.js → chunk-WA6XHBZS.js} +34 -13
- package/dist/index.d.ts +21 -77
- package/dist/index.js +268 -46
- package/dist/internal/virtual/height-estimator.d.ts +2 -9
- package/dist/internal/virtual/height-estimator.js +1 -1
- package/dist/internal/virtual/viewport-manager.js +1 -1
- package/dist/types-DsL_4tUb.d.ts +93 -0
- package/package.json +2 -38
- package/src/style.css +0 -3
- package/src/theme/dark.css +6 -0
- package/src/theme/light.css +6 -0
- package/src/theme/owomark.css +22 -2
- package/dist/chunk-DHRAXGIK.js +0 -1710
- package/dist/static.d.ts +0 -220
- package/dist/static.js +0 -40
- package/src/mdx-components/mdx-components.css +0 -336
package/dist/index.js
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Callout,
|
|
3
|
-
CodeDemo,
|
|
4
|
-
DEFAULT_MDX_COMPONENTS,
|
|
5
|
-
FileTree,
|
|
6
|
-
Kbd,
|
|
7
|
-
Step,
|
|
8
|
-
Steps,
|
|
9
|
-
THEME_DARK_CLASS,
|
|
10
|
-
THEME_LIGHT_CLASS,
|
|
11
|
-
Tab,
|
|
12
|
-
Tabs,
|
|
13
|
-
createOwoMarkProcessor,
|
|
14
|
-
getOwoMarkPlugins,
|
|
15
|
-
getThemeClassName,
|
|
16
|
-
rehypeMathDisplayFix,
|
|
17
|
-
rehypeSideAnnotation,
|
|
18
|
-
remarkConvertSoftBreaksToHardBreaks,
|
|
19
|
-
remarkSideAnnotation
|
|
20
|
-
} from "./chunk-DHRAXGIK.js";
|
|
21
1
|
import {
|
|
22
2
|
BlockLayoutMap
|
|
23
3
|
} from "./chunk-3CKPBCIP.js";
|
|
@@ -27,10 +7,12 @@ import {
|
|
|
27
7
|
import {
|
|
28
8
|
FALLBACK_BLOCK_HEIGHT,
|
|
29
9
|
estimateBlockHeight
|
|
30
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-KHKPOH74.js";
|
|
31
11
|
import {
|
|
32
|
-
VirtualViewportManager
|
|
33
|
-
|
|
12
|
+
VirtualViewportManager,
|
|
13
|
+
createSkeletonHtml,
|
|
14
|
+
ensureSkeletonStyles
|
|
15
|
+
} from "./chunk-WA6XHBZS.js";
|
|
34
16
|
|
|
35
17
|
// src/editor.ts
|
|
36
18
|
import { createDomAdapter } from "@owomark/core/internal/dom-adapter";
|
|
@@ -829,17 +811,60 @@ var PreviewDomPatcher = class {
|
|
|
829
811
|
};
|
|
830
812
|
|
|
831
813
|
// src/renderer/registry.ts
|
|
814
|
+
var DEFAULT_HEAVY_KINDS = [
|
|
815
|
+
{ kind: "mermaid", meta: { mode: "html-worker-safe", priority: "deferred", heavy: true } },
|
|
816
|
+
{ kind: "katex", meta: { mode: "html-worker-safe", priority: "deferred", heavy: true } },
|
|
817
|
+
{ kind: "math-block", meta: { mode: "html-worker-safe", priority: "deferred", heavy: true } },
|
|
818
|
+
{ kind: "chart", meta: { mode: "html-worker-safe", priority: "deferred", heavy: true } },
|
|
819
|
+
{ kind: "embed", meta: { mode: "html-worker-safe", priority: "deferred", heavy: true } }
|
|
820
|
+
];
|
|
832
821
|
function createRendererRegistry() {
|
|
833
822
|
const renderers = /* @__PURE__ */ new Map();
|
|
823
|
+
const metadata = /* @__PURE__ */ new Map();
|
|
824
|
+
for (const { kind, meta } of DEFAULT_HEAVY_KINDS) {
|
|
825
|
+
metadata.set(kind, meta);
|
|
826
|
+
}
|
|
834
827
|
return {
|
|
835
828
|
get(kind) {
|
|
836
829
|
return renderers.get(kind) ?? null;
|
|
837
830
|
},
|
|
838
831
|
register(kind, renderer) {
|
|
839
832
|
renderers.set(kind, renderer);
|
|
833
|
+
if (!metadata.has(kind)) {
|
|
834
|
+
metadata.set(kind, {
|
|
835
|
+
mode: renderer.mode,
|
|
836
|
+
priority: renderer.priority
|
|
837
|
+
});
|
|
838
|
+
}
|
|
840
839
|
},
|
|
841
840
|
unregister(kind) {
|
|
842
841
|
renderers.delete(kind);
|
|
842
|
+
},
|
|
843
|
+
registerMetadata(kind, meta) {
|
|
844
|
+
metadata.set(kind, meta);
|
|
845
|
+
},
|
|
846
|
+
isHeavy(kind) {
|
|
847
|
+
const meta = metadata.get(kind);
|
|
848
|
+
if (meta?.heavy) return true;
|
|
849
|
+
const def = renderers.get(kind);
|
|
850
|
+
return def?.priority === "deferred" || false;
|
|
851
|
+
},
|
|
852
|
+
getMode(kind) {
|
|
853
|
+
const def = renderers.get(kind);
|
|
854
|
+
if (def) return def.mode;
|
|
855
|
+
return metadata.get(kind)?.mode ?? null;
|
|
856
|
+
},
|
|
857
|
+
getPriority(kind) {
|
|
858
|
+
const def = renderers.get(kind);
|
|
859
|
+
if (def) return def.priority;
|
|
860
|
+
return metadata.get(kind)?.priority ?? null;
|
|
861
|
+
},
|
|
862
|
+
listRegistered() {
|
|
863
|
+
const kinds = /* @__PURE__ */ new Set([
|
|
864
|
+
...renderers.keys(),
|
|
865
|
+
...metadata.keys()
|
|
866
|
+
]);
|
|
867
|
+
return Array.from(kinds);
|
|
843
868
|
}
|
|
844
869
|
};
|
|
845
870
|
}
|
|
@@ -948,7 +973,7 @@ function isDeferred(block, registry) {
|
|
|
948
973
|
const def = registry.get(block.kind);
|
|
949
974
|
return def?.priority === "deferred";
|
|
950
975
|
}
|
|
951
|
-
function createRenderBlockFull(registry, renderCache, externalRenderBlock) {
|
|
976
|
+
function createRenderBlockFull(registry, renderCache, externalRenderBlock, scheduler) {
|
|
952
977
|
return async function renderBlockFull(block, baseContext) {
|
|
953
978
|
const context = {
|
|
954
979
|
...baseContext,
|
|
@@ -956,6 +981,14 @@ function createRenderBlockFull(registry, renderCache, externalRenderBlock) {
|
|
|
956
981
|
};
|
|
957
982
|
const customRenderer = registry.get(block.kind);
|
|
958
983
|
if (customRenderer) {
|
|
984
|
+
if (customRenderer.mode === "html-worker-safe" && customRenderer.workerModuleUrl && scheduler) {
|
|
985
|
+
try {
|
|
986
|
+
const html2 = await scheduler.submitWorkerTask(block, customRenderer, context);
|
|
987
|
+
renderCache.set(block.renderKey, html2);
|
|
988
|
+
return { kind: "html", html: html2 };
|
|
989
|
+
} catch {
|
|
990
|
+
}
|
|
991
|
+
}
|
|
959
992
|
const result = await customRenderer.render(block, context);
|
|
960
993
|
if (result.kind === "html") {
|
|
961
994
|
renderCache.set(block.renderKey, result.html);
|
|
@@ -982,6 +1015,7 @@ function createIncrementalEngine(options) {
|
|
|
982
1015
|
const themeKey = options?.themeKey ?? "";
|
|
983
1016
|
const viewportFirst = options?.viewportFirst ?? false;
|
|
984
1017
|
const registry = options?.registry ?? createRendererRegistry();
|
|
1018
|
+
const scheduler = options?.scheduler;
|
|
985
1019
|
const externalRenderBlock = options?.renderBlock;
|
|
986
1020
|
const onContentUpdate = options?.onContentUpdate;
|
|
987
1021
|
const patcher = new PreviewDomPatcher();
|
|
@@ -992,7 +1026,7 @@ function createIncrementalEngine(options) {
|
|
|
992
1026
|
let pendingAbort = null;
|
|
993
1027
|
let pendingIdleIds = [];
|
|
994
1028
|
let pendingBackfill = /* @__PURE__ */ new Set();
|
|
995
|
-
const renderBlockFull = createRenderBlockFull(registry, renderCache, externalRenderBlock);
|
|
1029
|
+
const renderBlockFull = createRenderBlockFull(registry, renderCache, externalRenderBlock, scheduler);
|
|
996
1030
|
function applyResult(blockId, result) {
|
|
997
1031
|
if (result.kind === "html") {
|
|
998
1032
|
patcher.patchBlockHtml(blockId, result.html);
|
|
@@ -1038,12 +1072,14 @@ function createIncrementalEngine(options) {
|
|
|
1038
1072
|
return {
|
|
1039
1073
|
mount(root) {
|
|
1040
1074
|
patcher.mount(root);
|
|
1075
|
+
ensureSkeletonStyles(root.ownerDocument);
|
|
1041
1076
|
mounted = true;
|
|
1042
1077
|
},
|
|
1043
1078
|
destroy() {
|
|
1044
1079
|
pendingAbort?.abort();
|
|
1045
1080
|
pendingAbort = null;
|
|
1046
1081
|
cancelAllIdle(pendingIdleIds);
|
|
1082
|
+
scheduler?.release();
|
|
1047
1083
|
patcher.destroy();
|
|
1048
1084
|
renderCache.clear();
|
|
1049
1085
|
pendingBackfill.clear();
|
|
@@ -1121,18 +1157,26 @@ function createIncrementalEngine(options) {
|
|
|
1121
1157
|
}
|
|
1122
1158
|
}
|
|
1123
1159
|
if (signal.aborted) return;
|
|
1160
|
+
pendingBackfill = /* @__PURE__ */ new Set();
|
|
1161
|
+
for (const block of realtimeOffscreen) {
|
|
1162
|
+
const height = estimateBlockHeight(block, registry);
|
|
1163
|
+
htmlMap.set(block.blockId, createSkeletonHtml({ height }));
|
|
1164
|
+
pendingBackfill.add(block.blockId);
|
|
1165
|
+
}
|
|
1166
|
+
for (const block of deferredAll) {
|
|
1167
|
+
const height = estimateBlockHeight(block, registry);
|
|
1168
|
+
htmlMap.set(block.blockId, createSkeletonHtml({ height }));
|
|
1169
|
+
pendingBackfill.add(block.blockId);
|
|
1170
|
+
}
|
|
1124
1171
|
patcher.fullRender(blocks, htmlMap);
|
|
1125
1172
|
for (const { blockId, result } of domMounts) {
|
|
1126
1173
|
if (signal.aborted) return;
|
|
1127
1174
|
applyResult(blockId, result);
|
|
1128
1175
|
}
|
|
1129
|
-
pendingBackfill = /* @__PURE__ */ new Set();
|
|
1130
1176
|
for (const block of realtimeOffscreen) {
|
|
1131
|
-
pendingBackfill.add(block.blockId);
|
|
1132
1177
|
scheduleBlockRender(block, baseContext, signal, state.version);
|
|
1133
1178
|
}
|
|
1134
1179
|
for (const block of deferredAll) {
|
|
1135
|
-
pendingBackfill.add(block.blockId);
|
|
1136
1180
|
scheduleBlockRender(block, baseContext, signal, state.version);
|
|
1137
1181
|
}
|
|
1138
1182
|
}
|
|
@@ -1249,6 +1293,7 @@ var OffscreenMeasurer = class {
|
|
|
1249
1293
|
function createVirtualEngine(options) {
|
|
1250
1294
|
const themeKey = options?.themeKey ?? "";
|
|
1251
1295
|
const registry = options?.registry ?? createRendererRegistry();
|
|
1296
|
+
const scheduler = options?.scheduler;
|
|
1252
1297
|
const externalRenderBlock = options?.renderBlock;
|
|
1253
1298
|
const onContentUpdate = options?.onContentUpdate;
|
|
1254
1299
|
const layoutMap = new BlockLayoutMap();
|
|
@@ -1256,7 +1301,7 @@ function createVirtualEngine(options) {
|
|
|
1256
1301
|
const measurer = new OffscreenMeasurer();
|
|
1257
1302
|
const viewport = new VirtualViewportManager();
|
|
1258
1303
|
const renderCache = /* @__PURE__ */ new Map();
|
|
1259
|
-
const renderBlockFull = createRenderBlockFull(registry, renderCache, externalRenderBlock);
|
|
1304
|
+
const renderBlockFull = createRenderBlockFull(registry, renderCache, externalRenderBlock, scheduler);
|
|
1260
1305
|
let renderedVersion = 0;
|
|
1261
1306
|
let lastBlocks = [];
|
|
1262
1307
|
let blockMap = /* @__PURE__ */ new Map();
|
|
@@ -1273,7 +1318,7 @@ function createVirtualEngine(options) {
|
|
|
1273
1318
|
function getInitialHeight(block) {
|
|
1274
1319
|
const cached = heightCache.get(block.renderKey);
|
|
1275
1320
|
if (cached !== void 0) return cached;
|
|
1276
|
-
return estimateBlockHeight(block);
|
|
1321
|
+
return estimateBlockHeight(block, registry);
|
|
1277
1322
|
}
|
|
1278
1323
|
async function renderAndMountBlock(block, baseContext, signal) {
|
|
1279
1324
|
if (signal.aborted) return;
|
|
@@ -1385,7 +1430,7 @@ function createVirtualEngine(options) {
|
|
|
1385
1430
|
heightCache.clear();
|
|
1386
1431
|
layoutMap.invalidateAll((blockId) => {
|
|
1387
1432
|
const block = blockMap.get(blockId);
|
|
1388
|
-
return block ? estimateBlockHeight(block) : FALLBACK_BLOCK_HEIGHT;
|
|
1433
|
+
return block ? estimateBlockHeight(block, registry) : FALLBACK_BLOCK_HEIGHT;
|
|
1389
1434
|
});
|
|
1390
1435
|
return true;
|
|
1391
1436
|
}
|
|
@@ -1420,6 +1465,7 @@ function createVirtualEngine(options) {
|
|
|
1420
1465
|
blockResizeObserver?.disconnect();
|
|
1421
1466
|
blockResizeObserver = null;
|
|
1422
1467
|
observedWrappers.clear();
|
|
1468
|
+
scheduler?.release();
|
|
1423
1469
|
viewport.destroy();
|
|
1424
1470
|
measurer.destroy();
|
|
1425
1471
|
renderCache.clear();
|
|
@@ -1545,11 +1591,185 @@ function createOwoMarkPreviewEngine(options) {
|
|
|
1545
1591
|
return createIncrementalEngine(options);
|
|
1546
1592
|
case "virtual":
|
|
1547
1593
|
return createVirtualEngine(options);
|
|
1594
|
+
case "mdx":
|
|
1595
|
+
throw new Error(
|
|
1596
|
+
'The "mdx" strategy is implemented by @owomark/react OwoMarkPreview, not by @owomark/view createOwoMarkPreviewEngine().'
|
|
1597
|
+
);
|
|
1548
1598
|
default:
|
|
1549
1599
|
throw new Error(`Unknown preview strategy: ${strategy}`);
|
|
1550
1600
|
}
|
|
1551
1601
|
}
|
|
1552
1602
|
|
|
1603
|
+
// src/worker/preview-task-scheduler.ts
|
|
1604
|
+
var MAX_CONSECUTIVE_CRASHES = 3;
|
|
1605
|
+
var CRASH_WINDOW_MS = 3e4;
|
|
1606
|
+
function serializeBlock(block) {
|
|
1607
|
+
return {
|
|
1608
|
+
kind: block.kind,
|
|
1609
|
+
raw: block.raw,
|
|
1610
|
+
blockId: block.blockId,
|
|
1611
|
+
renderKey: block.renderKey,
|
|
1612
|
+
startLine: block.startLine,
|
|
1613
|
+
endLine: block.endLine
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
function createPreviewTaskScheduler(options) {
|
|
1617
|
+
const poolSize = options?.poolSize ?? Math.max(1, (typeof navigator !== "undefined" ? navigator.hardwareConcurrency ?? 4 : 4) - 1);
|
|
1618
|
+
let refCount = 1;
|
|
1619
|
+
let taskCounter = 0;
|
|
1620
|
+
let permanentlyFailed = false;
|
|
1621
|
+
const crashTimestamps = [];
|
|
1622
|
+
const pendingTasks = /* @__PURE__ */ new Map();
|
|
1623
|
+
const workers = [];
|
|
1624
|
+
let nextWorkerIndex = 0;
|
|
1625
|
+
function createWorkerSlot() {
|
|
1626
|
+
try {
|
|
1627
|
+
if (typeof Worker === "undefined") return null;
|
|
1628
|
+
const worker = new Worker(
|
|
1629
|
+
new URL("./preview-render.worker.js", import.meta.url),
|
|
1630
|
+
{ type: "module" }
|
|
1631
|
+
);
|
|
1632
|
+
const slot = { worker, pendingCount: 0, dead: false };
|
|
1633
|
+
worker.onmessage = (e) => {
|
|
1634
|
+
const resp = e.data;
|
|
1635
|
+
slot.pendingCount--;
|
|
1636
|
+
const pending = pendingTasks.get(resp.taskId);
|
|
1637
|
+
if (!pending) return;
|
|
1638
|
+
pendingTasks.delete(resp.taskId);
|
|
1639
|
+
if (resp.ok) {
|
|
1640
|
+
pending.resolve(resp.html);
|
|
1641
|
+
} else {
|
|
1642
|
+
pending.reject(new Error(resp.error));
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
worker.onerror = () => {
|
|
1646
|
+
slot.dead = true;
|
|
1647
|
+
slot.pendingCount = 0;
|
|
1648
|
+
worker.terminate();
|
|
1649
|
+
recordCrash();
|
|
1650
|
+
options?.onCrash?.();
|
|
1651
|
+
};
|
|
1652
|
+
return slot;
|
|
1653
|
+
} catch {
|
|
1654
|
+
return null;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
function recordCrash() {
|
|
1658
|
+
const now = Date.now();
|
|
1659
|
+
crashTimestamps.push(now);
|
|
1660
|
+
while (crashTimestamps.length > 0 && now - crashTimestamps[0] > CRASH_WINDOW_MS) {
|
|
1661
|
+
crashTimestamps.shift();
|
|
1662
|
+
}
|
|
1663
|
+
if (crashTimestamps.length >= MAX_CONSECUTIVE_CRASHES) {
|
|
1664
|
+
permanentlyFailed = true;
|
|
1665
|
+
terminateAll();
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
function getLeastBusySlot() {
|
|
1669
|
+
if (permanentlyFailed) return null;
|
|
1670
|
+
let best = null;
|
|
1671
|
+
for (const slot of workers) {
|
|
1672
|
+
if (slot.dead) continue;
|
|
1673
|
+
if (!best || slot.pendingCount < best.pendingCount) {
|
|
1674
|
+
best = slot;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
if (best) return best;
|
|
1678
|
+
if (workers.length < poolSize) {
|
|
1679
|
+
const slot = createWorkerSlot();
|
|
1680
|
+
if (slot) {
|
|
1681
|
+
workers.push(slot);
|
|
1682
|
+
return slot;
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
for (let i = 0; i < workers.length; i++) {
|
|
1686
|
+
if (workers[i].dead) {
|
|
1687
|
+
const slot = createWorkerSlot();
|
|
1688
|
+
if (slot) {
|
|
1689
|
+
workers[i] = slot;
|
|
1690
|
+
return slot;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
return null;
|
|
1695
|
+
}
|
|
1696
|
+
function terminateAll() {
|
|
1697
|
+
for (const slot of workers) {
|
|
1698
|
+
if (!slot.dead) {
|
|
1699
|
+
slot.dead = true;
|
|
1700
|
+
slot.worker.terminate();
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
workers.length = 0;
|
|
1704
|
+
for (const [, pending] of pendingTasks) {
|
|
1705
|
+
pending.reject(new Error("Scheduler terminated"));
|
|
1706
|
+
}
|
|
1707
|
+
pendingTasks.clear();
|
|
1708
|
+
}
|
|
1709
|
+
const scheduler = {
|
|
1710
|
+
submitWorkerTask(block, rendererDef, context) {
|
|
1711
|
+
if (permanentlyFailed || !rendererDef.workerModuleUrl) {
|
|
1712
|
+
return Promise.reject(new Error("Worker unavailable"));
|
|
1713
|
+
}
|
|
1714
|
+
const slot = getLeastBusySlot();
|
|
1715
|
+
if (!slot) {
|
|
1716
|
+
return Promise.reject(new Error("No worker available"));
|
|
1717
|
+
}
|
|
1718
|
+
const taskId = ++taskCounter;
|
|
1719
|
+
return new Promise((resolve, reject) => {
|
|
1720
|
+
pendingTasks.set(taskId, { resolve, reject });
|
|
1721
|
+
slot.pendingCount++;
|
|
1722
|
+
slot.worker.postMessage({
|
|
1723
|
+
type: "render",
|
|
1724
|
+
taskId,
|
|
1725
|
+
block: serializeBlock(block),
|
|
1726
|
+
rendererModuleUrl: rendererDef.workerModuleUrl,
|
|
1727
|
+
context: {
|
|
1728
|
+
version: context.version,
|
|
1729
|
+
themeKey: context.themeKey,
|
|
1730
|
+
sourceLineOffset: context.sourceLineOffset
|
|
1731
|
+
}
|
|
1732
|
+
});
|
|
1733
|
+
});
|
|
1734
|
+
},
|
|
1735
|
+
cancel(taskId) {
|
|
1736
|
+
const pending = pendingTasks.get(taskId);
|
|
1737
|
+
if (pending) {
|
|
1738
|
+
pendingTasks.delete(taskId);
|
|
1739
|
+
pending.reject(new Error("Task cancelled"));
|
|
1740
|
+
}
|
|
1741
|
+
const msg = { type: "cancel", taskId };
|
|
1742
|
+
for (const slot of workers) {
|
|
1743
|
+
if (!slot.dead) slot.worker.postMessage(msg);
|
|
1744
|
+
}
|
|
1745
|
+
},
|
|
1746
|
+
cancelAll() {
|
|
1747
|
+
for (const [, pending] of pendingTasks) {
|
|
1748
|
+
pending.reject(new Error("All tasks cancelled"));
|
|
1749
|
+
}
|
|
1750
|
+
pendingTasks.clear();
|
|
1751
|
+
const msg = { type: "cancel-all" };
|
|
1752
|
+
for (const slot of workers) {
|
|
1753
|
+
if (!slot.dead) {
|
|
1754
|
+
slot.pendingCount = 0;
|
|
1755
|
+
slot.worker.postMessage(msg);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
},
|
|
1759
|
+
acquire() {
|
|
1760
|
+
refCount++;
|
|
1761
|
+
return scheduler;
|
|
1762
|
+
},
|
|
1763
|
+
release() {
|
|
1764
|
+
if (--refCount <= 0) {
|
|
1765
|
+
refCount = 0;
|
|
1766
|
+
terminateAll();
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
return scheduler;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1553
1773
|
// src/dom/side-annotation-positioner.ts
|
|
1554
1774
|
var SideAnnotationPositioner = class {
|
|
1555
1775
|
container;
|
|
@@ -1639,31 +1859,33 @@ var SideAnnotationPositioner = class {
|
|
|
1639
1859
|
}
|
|
1640
1860
|
}
|
|
1641
1861
|
};
|
|
1862
|
+
|
|
1863
|
+
// src/theme.ts
|
|
1864
|
+
var THEME_LIGHT_CLASS = "owo-theme-light";
|
|
1865
|
+
var THEME_DARK_CLASS = "owo-theme-dark";
|
|
1866
|
+
function getThemeClassName(theme) {
|
|
1867
|
+
switch (theme) {
|
|
1868
|
+
case "light":
|
|
1869
|
+
return THEME_LIGHT_CLASS;
|
|
1870
|
+
case "dark":
|
|
1871
|
+
return THEME_DARK_CLASS;
|
|
1872
|
+
default:
|
|
1873
|
+
return theme;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1642
1876
|
export {
|
|
1643
|
-
Callout,
|
|
1644
|
-
CodeDemo,
|
|
1645
|
-
DEFAULT_MDX_COMPONENTS,
|
|
1646
|
-
FileTree,
|
|
1647
|
-
Kbd,
|
|
1648
1877
|
PreviewDomPatcher,
|
|
1649
1878
|
SideAnnotationPositioner,
|
|
1650
|
-
Step,
|
|
1651
|
-
Steps,
|
|
1652
1879
|
THEME_DARK_CLASS,
|
|
1653
1880
|
THEME_LIGHT_CLASS,
|
|
1654
|
-
Tab,
|
|
1655
|
-
Tabs,
|
|
1656
1881
|
createOwoMarkPreviewEngine,
|
|
1657
|
-
createOwoMarkProcessor,
|
|
1658
1882
|
createOwoMarkVanillaEditor,
|
|
1659
1883
|
createOwoMarkView,
|
|
1884
|
+
createPreviewTaskScheduler,
|
|
1660
1885
|
createRendererRegistry,
|
|
1886
|
+
createSkeletonHtml,
|
|
1661
1887
|
createViewEngine,
|
|
1662
|
-
|
|
1888
|
+
ensureSkeletonStyles,
|
|
1663
1889
|
getThemeClassName,
|
|
1664
|
-
rehypeMathDisplayFix,
|
|
1665
|
-
rehypeSideAnnotation,
|
|
1666
|
-
remarkConvertSoftBreaksToHardBreaks,
|
|
1667
|
-
remarkSideAnnotation,
|
|
1668
1890
|
renderBlockDefault
|
|
1669
1891
|
};
|
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { PreviewBlock } from '@owomark/core';
|
|
2
|
+
import { P as PreviewRendererRegistry } from '../../types-DsL_4tUb.js';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
* Heuristic height estimation for blocks before measurement.
|
|
5
|
-
*
|
|
6
|
-
* Uses block kind and source line count to produce a rough height estimate.
|
|
7
|
-
* These estimates are used as initial placeholder heights in the coordinate
|
|
8
|
-
* table until real measurement completes.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
declare function estimateBlockHeight(block: PreviewBlock): number;
|
|
4
|
+
declare function estimateBlockHeight(block: PreviewBlock, registry?: PreviewRendererRegistry): number;
|
|
12
5
|
|
|
13
6
|
export { estimateBlockHeight };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { OwoMarkSharedState, PreviewBlockKind, PreviewBlock } from '@owomark/core';
|
|
2
|
+
|
|
3
|
+
type PreviewRenderPhase = 'idle' | 'rendering' | 'highlighting' | 'ready' | 'error';
|
|
4
|
+
type PreviewCacheEntry = {
|
|
5
|
+
blockId: string;
|
|
6
|
+
renderKey: string;
|
|
7
|
+
html: string;
|
|
8
|
+
highlighted: boolean;
|
|
9
|
+
themeKey: string;
|
|
10
|
+
updatedAt: number;
|
|
11
|
+
};
|
|
12
|
+
type PreviewRenderContext = {
|
|
13
|
+
version: number;
|
|
14
|
+
themeKey: string;
|
|
15
|
+
abortSignal?: AbortSignal;
|
|
16
|
+
/**
|
|
17
|
+
* Line offset to add to source-line attributes in the rendered HTML.
|
|
18
|
+
* When a block starts at line N in the document, the renderer processes
|
|
19
|
+
* its raw content starting from line 1; this offset (N - 1) must be
|
|
20
|
+
* added to `data-source-line-start/end` so scroll sync anchors map
|
|
21
|
+
* to the correct document lines.
|
|
22
|
+
*/
|
|
23
|
+
sourceLineOffset: number;
|
|
24
|
+
};
|
|
25
|
+
type PreviewRenderResult = {
|
|
26
|
+
kind: 'html';
|
|
27
|
+
html: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'dom';
|
|
30
|
+
mount: (container: HTMLElement) => void;
|
|
31
|
+
unmount?: () => void;
|
|
32
|
+
};
|
|
33
|
+
type PreviewRendererMode = 'html-worker-safe' | 'dom-main-thread';
|
|
34
|
+
type PreviewTaskPriority = 'realtime' | 'deferred';
|
|
35
|
+
type PreviewRendererDefinition = {
|
|
36
|
+
mode: PreviewRendererMode;
|
|
37
|
+
priority: PreviewTaskPriority;
|
|
38
|
+
render: PreviewBlockRenderer;
|
|
39
|
+
version: string;
|
|
40
|
+
workerModuleUrl?: string;
|
|
41
|
+
};
|
|
42
|
+
type PreviewBlockRenderer = (block: PreviewBlock, context: PreviewRenderContext) => Promise<PreviewRenderResult> | PreviewRenderResult;
|
|
43
|
+
type PreviewBlockMetadata = {
|
|
44
|
+
mode: PreviewRendererMode;
|
|
45
|
+
priority: PreviewTaskPriority;
|
|
46
|
+
heavy?: boolean;
|
|
47
|
+
};
|
|
48
|
+
type PreviewRendererRegistry = {
|
|
49
|
+
get(kind: PreviewBlockKind): PreviewRendererDefinition | null;
|
|
50
|
+
register(kind: PreviewBlockKind, renderer: PreviewRendererDefinition): void;
|
|
51
|
+
unregister(kind: PreviewBlockKind): void;
|
|
52
|
+
registerMetadata(kind: PreviewBlockKind, meta: PreviewBlockMetadata): void;
|
|
53
|
+
isHeavy(kind: PreviewBlockKind): boolean;
|
|
54
|
+
getMode(kind: PreviewBlockKind): PreviewRendererMode | null;
|
|
55
|
+
getPriority(kind: PreviewBlockKind): PreviewTaskPriority | null;
|
|
56
|
+
listRegistered(): PreviewBlockKind[];
|
|
57
|
+
};
|
|
58
|
+
type PreviewTaskScheduler = {
|
|
59
|
+
submitWorkerTask(block: PreviewBlock, rendererDef: PreviewRendererDefinition, context: PreviewRenderContext): Promise<string>;
|
|
60
|
+
cancel(taskId: number): void;
|
|
61
|
+
cancelAll(): void;
|
|
62
|
+
acquire(): PreviewTaskScheduler;
|
|
63
|
+
release(): void;
|
|
64
|
+
};
|
|
65
|
+
type PreviewStrategy = 'incremental' | 'virtual' | 'mdx';
|
|
66
|
+
type OwoMarkPreviewEngineOptions = {
|
|
67
|
+
strategy?: PreviewStrategy;
|
|
68
|
+
themeKey?: string;
|
|
69
|
+
registry?: PreviewRendererRegistry;
|
|
70
|
+
scheduler?: PreviewTaskScheduler;
|
|
71
|
+
viewportFirst?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* External block renderer function. When provided, the engine uses this
|
|
74
|
+
* instead of the built-in default renderer. This allows the host to supply
|
|
75
|
+
* its own Markdown pipeline (unified, remark, rehype, Shiki, etc.) without
|
|
76
|
+
* the preview package bundling those heavy dependencies.
|
|
77
|
+
*/
|
|
78
|
+
renderBlock?: (block: PreviewBlock, context: PreviewRenderContext) => Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Called after every DOM mutation — including idle-backfilled and deferred
|
|
81
|
+
* block renders — not just after the synchronous update() return.
|
|
82
|
+
* Use for scroll sync or other post-DOM-update side effects.
|
|
83
|
+
*/
|
|
84
|
+
onContentUpdate?: () => void;
|
|
85
|
+
};
|
|
86
|
+
type OwoMarkPreviewEngine = {
|
|
87
|
+
mount(root: HTMLElement): void;
|
|
88
|
+
destroy(): void;
|
|
89
|
+
update(state: OwoMarkSharedState): void;
|
|
90
|
+
getRenderedVersion(): number;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type { OwoMarkPreviewEngineOptions as O, PreviewRendererRegistry as P, OwoMarkPreviewEngine as a, PreviewTaskScheduler as b, PreviewBlockMetadata as c, PreviewBlockRenderer as d, PreviewCacheEntry as e, PreviewRenderContext as f, PreviewRenderPhase as g, PreviewRenderResult as h, PreviewRendererDefinition as i, PreviewRendererMode as j, PreviewStrategy as k, PreviewTaskPriority as l };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owomark/view",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Rendering engine, preview engine, DOM view layer, and official base theme for OwoMark.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,10 +21,6 @@
|
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"import": "./dist/index.js"
|
|
23
23
|
},
|
|
24
|
-
"./static": {
|
|
25
|
-
"types": "./dist/static.d.ts",
|
|
26
|
-
"import": "./dist/static.js"
|
|
27
|
-
},
|
|
28
24
|
"./internal/virtual/block-layout-map": {
|
|
29
25
|
"types": "./dist/internal/virtual/block-layout-map.d.ts",
|
|
30
26
|
"import": "./dist/internal/virtual/block-layout-map.js"
|
|
@@ -42,7 +38,6 @@
|
|
|
42
38
|
"import": "./dist/internal/virtual/viewport-manager.js"
|
|
43
39
|
},
|
|
44
40
|
"./style.css": "./src/style.css",
|
|
45
|
-
"./mdx-components.css": "./src/mdx-components/mdx-components.css",
|
|
46
41
|
"./owomark.css": "./src/theme/owomark.css",
|
|
47
42
|
"./preview.css": "./src/theme/preview.css",
|
|
48
43
|
"./light.css": "./src/theme/light.css",
|
|
@@ -53,12 +48,10 @@
|
|
|
53
48
|
"files": [
|
|
54
49
|
"dist",
|
|
55
50
|
"src/style.css",
|
|
56
|
-
"src/mdx-components/mdx-components.css",
|
|
57
51
|
"src/theme"
|
|
58
52
|
],
|
|
59
53
|
"sideEffects": [
|
|
60
54
|
"./src/style.css",
|
|
61
|
-
"./src/mdx-components/mdx-components.css",
|
|
62
55
|
"./src/theme/*.css"
|
|
63
56
|
],
|
|
64
57
|
"scripts": {
|
|
@@ -69,38 +62,9 @@
|
|
|
69
62
|
"access": "public"
|
|
70
63
|
},
|
|
71
64
|
"dependencies": {
|
|
72
|
-
"@owomark/core": "^0.1.
|
|
73
|
-
"rehype-katex": "^6.0.3",
|
|
74
|
-
"rehype-pretty-code": "^0.14.1",
|
|
75
|
-
"rehype-slug": "^6.0.0",
|
|
76
|
-
"rehype-stringify": "^10.0.1",
|
|
77
|
-
"remark-directive": "^4.0.0",
|
|
78
|
-
"remark-gfm": "^4.0.1",
|
|
79
|
-
"remark-math": "^6.0.0",
|
|
80
|
-
"remark-mdx": "^3.1.0",
|
|
81
|
-
"remark-parse": "^11.0.0",
|
|
82
|
-
"remark-rehype": "^11.1.2",
|
|
83
|
-
"shiki": "^3.23.0",
|
|
84
|
-
"unified": "^11.0.5"
|
|
85
|
-
},
|
|
86
|
-
"peerDependencies": {
|
|
87
|
-
"@mdx-js/mdx": "^3.0.0",
|
|
88
|
-
"react": "^18.0.0 || ^19.0.0",
|
|
89
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
90
|
-
},
|
|
91
|
-
"peerDependenciesMeta": {
|
|
92
|
-
"@mdx-js/mdx": {
|
|
93
|
-
"optional": true
|
|
94
|
-
},
|
|
95
|
-
"react": {
|
|
96
|
-
"optional": true
|
|
97
|
-
},
|
|
98
|
-
"react-dom": {
|
|
99
|
-
"optional": true
|
|
100
|
-
}
|
|
65
|
+
"@owomark/core": "^0.1.6"
|
|
101
66
|
},
|
|
102
67
|
"devDependencies": {
|
|
103
|
-
"@types/react": "^19.0.0",
|
|
104
68
|
"tsup": "^8.5.1"
|
|
105
69
|
}
|
|
106
70
|
}
|
package/src/style.css
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
* Aggregates structural CSS and official base theme (light + dark presets).
|
|
3
3
|
* Users who want fine-grained control can import each layer individually. */
|
|
4
4
|
|
|
5
|
-
/* Structural: component skeletons with --owo-* token slots */
|
|
6
|
-
@import './mdx-components/mdx-components.css';
|
|
7
|
-
|
|
8
5
|
/* Structural: editor base styles consuming --owo-editor-* tokens */
|
|
9
6
|
@import './theme/owomark.css';
|
|
10
7
|
@import './theme/side-annotation.css';
|
package/src/theme/dark.css
CHANGED
|
@@ -59,8 +59,14 @@
|
|
|
59
59
|
--owo-syntax-code-fence: #7f849c;
|
|
60
60
|
--owo-syntax-code-lang: #fab387;
|
|
61
61
|
--owo-syntax-list-marker: #fab387;
|
|
62
|
+
--owo-syntax-task-marker: #f9c74f;
|
|
63
|
+
--owo-syntax-task-marker-checked: #a6e3a1;
|
|
64
|
+
--owo-syntax-table-separator: #6c7086;
|
|
65
|
+
--owo-syntax-strikethrough: #cdd6f4;
|
|
62
66
|
--owo-syntax-blockquote-marker: #585b70;
|
|
63
67
|
--owo-syntax-hr: #45475a;
|
|
68
|
+
--owo-syntax-html: #cba6f7;
|
|
69
|
+
--owo-syntax-math: #94e2d5;
|
|
64
70
|
|
|
65
71
|
/* Toolbar */
|
|
66
72
|
--owo-toolbar-bg: #252536;
|