@owomark/view 0.1.6 → 0.1.8

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/index.js CHANGED
@@ -7,27 +7,27 @@ import {
7
7
  import {
8
8
  FALLBACK_BLOCK_HEIGHT,
9
9
  estimateBlockHeight
10
- } from "./chunk-KHKPOH74.js";
10
+ } from "./chunk-BPOZMVU7.js";
11
11
  import {
12
12
  VirtualViewportManager,
13
13
  createSkeletonHtml,
14
14
  ensureSkeletonStyles
15
- } from "./chunk-WA6XHBZS.js";
16
-
17
- // src/editor.ts
18
- import { createDomAdapter } from "@owomark/core/internal/dom-adapter";
15
+ } from "./chunk-656BO747.js";
19
16
 
20
17
  // src/view-engine.ts
21
18
  import {
22
- readSelection,
23
- restoreSelection,
24
- invalidateBlockCache,
25
19
  linearToVirtual,
26
20
  virtualToLinear,
27
21
  getBlockStartOffset,
28
22
  tokenizeBlock
29
23
  } from "@owomark/core";
30
- import { createBlockElement, updateBlockElement } from "@owomark/core";
24
+ import {
25
+ readSelection,
26
+ restoreSelection,
27
+ invalidateBlockCache,
28
+ createBlockElement,
29
+ updateBlockElement
30
+ } from "@owomark/core/browser";
31
31
 
32
32
  // src/dom/slash-menu.ts
33
33
  var MENU_GAP = 4;
@@ -635,22 +635,6 @@ function createOwoMarkView(core, element) {
635
635
  engine.mount(element);
636
636
  return engine;
637
637
  }
638
- function createOwoMarkVanillaEditor() {
639
- const adapter = createDomAdapter();
640
- let slashMenu = null;
641
- return {
642
- ...adapter,
643
- mount(element) {
644
- adapter.mount(element);
645
- slashMenu = createSlashMenuOverlay(element, adapter.getCore());
646
- },
647
- destroy() {
648
- slashMenu?.destroy();
649
- slashMenu = null;
650
- adapter.destroy();
651
- }
652
- };
653
- }
654
638
 
655
639
  // src/dom/patcher.ts
656
640
  var BLOCK_ATTR = "data-preview-block";
@@ -794,6 +778,11 @@ var PreviewDomPatcher = class {
794
778
  createBlockWrapper(doc, block) {
795
779
  const wrapper = doc.createElement("div");
796
780
  wrapper.setAttribute(BLOCK_ATTR, block.blockId);
781
+ if ("style" in wrapper && wrapper.style) {
782
+ wrapper.style.display = "flow-root";
783
+ } else {
784
+ wrapper.setAttribute("style", "display: flow-root;");
785
+ }
797
786
  this.updateBlockAttributes(wrapper, block);
798
787
  return wrapper;
799
788
  }
@@ -811,63 +800,13 @@ var PreviewDomPatcher = class {
811
800
  };
812
801
 
813
802
  // 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
- ];
821
- function createRendererRegistry() {
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
- }
827
- return {
828
- get(kind) {
829
- return renderers.get(kind) ?? null;
830
- },
831
- register(kind, renderer) {
832
- renderers.set(kind, renderer);
833
- if (!metadata.has(kind)) {
834
- metadata.set(kind, {
835
- mode: renderer.mode,
836
- priority: renderer.priority
837
- });
838
- }
839
- },
840
- unregister(kind) {
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);
868
- }
869
- };
870
- }
803
+ import {
804
+ CARDS_FAMILY_CUSTOM_BLOCK_KEY as CARDS_FAMILY_CUSTOM_BLOCK_KEY2,
805
+ runtimeBlockRegistry
806
+ } from "@owomark/core";
807
+
808
+ // src/renderer/side-annotation-renderer.ts
809
+ import { SIDE_ANNOTATION_RENDERER_KEY_BY_TYPE } from "@owomark/core/semantic/syntax";
871
810
 
872
811
  // src/renderer/default-renderer.ts
873
812
  function escapeHtml(text) {
@@ -877,6 +816,39 @@ var SAFE_URL_PATTERN = /^(?:https?:|mailto:|#|\/)/i;
877
816
  function sanitizeUrl(url) {
878
817
  return SAFE_URL_PATTERN.test(url) ? url : "";
879
818
  }
819
+ function stripCommonBlockquotePrefixes(raw) {
820
+ let lines = raw.split("\n");
821
+ let depth = 0;
822
+ while (lines.length > 0 && lines.every((line) => line.trim() === "" || /^ {0,3}>\s?/.test(line))) {
823
+ lines = lines.map((line) => line.trim() === "" ? line : line.replace(/^ {0,3}>\s?/, ""));
824
+ depth += 1;
825
+ }
826
+ return {
827
+ depth,
828
+ content: lines.join("\n")
829
+ };
830
+ }
831
+ function wrapInBlockquotes(content, depth) {
832
+ let wrapped = content;
833
+ for (let index = 0; index < depth; index += 1) {
834
+ wrapped = `<blockquote>${wrapped}</blockquote>`;
835
+ }
836
+ return wrapped;
837
+ }
838
+ function extractHeadingText(raw) {
839
+ const { depth, content } = stripCommonBlockquotePrefixes(raw);
840
+ const setextMatch = content.match(/^([^\n]+)\n {0,3}(?:=+|-+)\s*$/);
841
+ if (setextMatch) {
842
+ return {
843
+ depth,
844
+ text: setextMatch[1]
845
+ };
846
+ }
847
+ return {
848
+ depth,
849
+ text: content.replace(/^#{1,6}\s*/, "")
850
+ };
851
+ }
880
852
  function renderInline(text) {
881
853
  let html = escapeHtml(text);
882
854
  html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
@@ -897,8 +869,8 @@ function renderBlockDefault(block) {
897
869
  }
898
870
  case "heading": {
899
871
  const level = block.headingLevel ?? 1;
900
- const text = block.raw.replace(/^#{1,6}\s*/, "");
901
- return `<h${level}>${renderInline(text)}</h${level}>`;
872
+ const { depth, text } = extractHeadingText(block.raw);
873
+ return wrapInBlockquotes(`<h${level}>${renderInline(text)}</h${level}>`, depth);
902
874
  }
903
875
  case "code-fence": {
904
876
  const lines = block.raw.split("\n");
@@ -940,6 +912,409 @@ function renderBlockDefault(block) {
940
912
  }
941
913
  }
942
914
 
915
+ // src/renderer/side-annotation-renderer.ts
916
+ function escapeHtml2(text) {
917
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
918
+ }
919
+ function escapeAttribute(text) {
920
+ return escapeHtml2(text).replace(/'/g, "&#39;");
921
+ }
922
+ function svgSegment(className, width, height, body, extraAttrs = "") {
923
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}" class="${className}"${extraAttrs}>${body}</svg>`;
924
+ }
925
+ function stretchLineDiv() {
926
+ return '<div class="side-svg-line"></div>';
927
+ }
928
+ function segmented(width, axisPx, segments, extraClass = "") {
929
+ const className = ["side-annotation-svg", "side-svg-segmented", extraClass].filter(Boolean).join(" ");
930
+ return `<div class="${className}" style="width:${width};--side-svg-axis:${axisPx}px">${segments.join("")}</div>`;
931
+ }
932
+ function svgPath(d, extra = "") {
933
+ return `<path d="${d}" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"${extra}></path>`;
934
+ }
935
+ function svgLine(x1, y1, x2, y2, extra = "") {
936
+ return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"${extra}></line>`;
937
+ }
938
+ function svgPolyline(points, extra = "") {
939
+ return `<polyline points="${points}" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square" stroke-linejoin="miter" shape-rendering="geometricPrecision"${extra}></polyline>`;
940
+ }
941
+ function makeSvgForSideType(sideType, orphan) {
942
+ const rendererKey = SIDE_ANNOTATION_RENDERER_KEY_BY_TYPE[sideType] ?? sideType;
943
+ if (orphan) {
944
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="4" viewBox="0 0 4 100" preserveAspectRatio="none" class="side-annotation-svg side-svg-vline">${svgLine(2, "2", 2, "98", ' vector-effect="non-scaling-stroke"')}</svg>`;
945
+ }
946
+ switch (rendererKey) {
947
+ case "brace":
948
+ return segmented("12px", 6, [
949
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 1 0.75 C 3.5 0.75, 6 2.5, 6 5.25")),
950
+ stretchLineDiv(),
951
+ svgSegment("side-svg-beak", 12, 8, svgPath("M 6 0 C 6 2.5, 11 4, 11 4 C 11 4, 6 5.5, 6 8")),
952
+ stretchLineDiv(),
953
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 6 0.75 C 6 3.5, 3.5 5.25, 1 5.25"))
954
+ ]);
955
+ case "left-brace":
956
+ return segmented("12px", 6, [
957
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 11 0.75 C 8.5 0.75, 6 2.5, 6 5.25")),
958
+ stretchLineDiv(),
959
+ svgSegment("side-svg-beak", 12, 8, svgPath("M 6 0 C 6 2.5, 1 4, 1 4 C 1 4, 6 5.5, 6 8")),
960
+ stretchLineDiv(),
961
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 6 0.75 C 6 3.5, 8.5 5.25, 11 5.25"))
962
+ ]);
963
+ case "bracket":
964
+ return segmented("8px", 4, [
965
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("1,0.75 4,0.75 4,5.25")),
966
+ stretchLineDiv(),
967
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("4,0.75 4,5.25 1,5.25"))
968
+ ], "side-svg-bracket");
969
+ case "left-bracket":
970
+ return segmented("8px", 4, [
971
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("7,0.75 4,0.75 4,5.25")),
972
+ stretchLineDiv(),
973
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("4,0.75 4,5.25 7,5.25"))
974
+ ], "side-svg-left-bracket");
975
+ case "line":
976
+ case "warning":
977
+ case "question":
978
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="4" viewBox="0 0 4 100" preserveAspectRatio="none" class="side-annotation-svg side-svg-vline">${svgLine(2, "2", 2, "98", ' vector-effect="non-scaling-stroke"')}</svg>`;
979
+ case "dash":
980
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="4" viewBox="0 0 20 4" class="side-annotation-svg side-svg-dash">${svgLine(1, "2", 19, "2")}</svg>`;
981
+ case "arrow":
982
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="16" viewBox="0 0 24 16" class="side-annotation-svg side-svg-arrow">${svgPath("M 1 8 L 20 8 M 16 3 L 21 8 L 16 13")}</svg>`;
983
+ case "fat-arrow":
984
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="16" viewBox="0 0 24 16" class="side-annotation-svg side-svg-fat-arrow">${svgPath("M 1 5 L 16 5 M 1 11 L 16 11 M 15 2 L 22 8 L 15 14")}</svg>`;
985
+ case "wave-arrow":
986
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="16" viewBox="0 0 28 16" class="side-annotation-svg side-svg-wave-arrow">${svgPath("M 1 8 C 4 3, 8 13, 12 8 C 16 3, 20 8, 20 8 M 18 3 L 23 8 L 18 13")}</svg>`;
987
+ case "brace-arrow":
988
+ return segmented("12px", 6, [
989
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 1 0.75 C 3.5 0.75, 6 2.5, 6 5.25")),
990
+ stretchLineDiv(),
991
+ svgSegment("side-svg-beak", 12, 8, `${svgLine(6, "0", 6, "8", ' stroke-linecap="square" shape-rendering="geometricPrecision"')}${svgPath("M 6 4 L 19 4 M 16 1.5 L 20 4 L 16 6.5")}`, ' overflow="visible"'),
992
+ stretchLineDiv(),
993
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 6 0.75 C 6 3.5, 3.5 5.25, 1 5.25"))
994
+ ], "side-svg-compound-arrow");
995
+ case "brace-fat-arrow":
996
+ return segmented("12px", 6, [
997
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 1 0.75 C 3.5 0.75, 6 2.5, 6 5.25")),
998
+ stretchLineDiv(),
999
+ svgSegment("side-svg-beak", 12, 8, `${svgLine(6, "0", 6, "8", ' stroke-linecap="square" shape-rendering="geometricPrecision"')}${svgPath("M 6 2.5 L 14 2.5 M 6 5.5 L 14 5.5 M 13 0.5 L 18 4 L 13 7.5")}`, ' overflow="visible"'),
1000
+ stretchLineDiv(),
1001
+ svgSegment("side-svg-cap", 12, 6, svgPath("M 6 0.75 C 6 3.5, 3.5 5.25, 1 5.25"))
1002
+ ], "side-svg-compound-arrow");
1003
+ case "bracket-arrow":
1004
+ return segmented("8px", 4, [
1005
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("1,0.75 4,0.75 4,5.25")),
1006
+ stretchLineDiv(),
1007
+ svgSegment("side-svg-beak", 8, 8, `${svgLine(4, "0", 4, "8", ' stroke-linecap="square" shape-rendering="geometricPrecision"')}${svgPath("M 4 4 L 17 4 M 14 1.5 L 18 4 L 14 6.5")}`, ' overflow="visible"'),
1008
+ stretchLineDiv(),
1009
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("4,0.75 4,5.25 1,5.25"))
1010
+ ], "side-svg-bracket side-svg-compound-arrow");
1011
+ case "bracket-fat-arrow":
1012
+ return segmented("8px", 4, [
1013
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("1,0.75 4,0.75 4,5.25")),
1014
+ stretchLineDiv(),
1015
+ svgSegment("side-svg-beak", 8, 8, `${svgLine(4, "0", 4, "8", ' stroke-linecap="square" shape-rendering="geometricPrecision"')}${svgPath("M 4 2.5 L 13 2.5 M 4 5.5 L 13 5.5 M 12 0.5 L 17 4 L 12 7.5")}`, ' overflow="visible"'),
1016
+ stretchLineDiv(),
1017
+ svgSegment("side-svg-cap", 8, 6, svgPolyline("4,0.75 4,5.25 1,5.25"))
1018
+ ], "side-svg-bracket side-svg-compound-arrow");
1019
+ case "line-arrow":
1020
+ return segmented("4px", 2, [
1021
+ stretchLineDiv(),
1022
+ svgSegment("side-svg-beak", 4, 8, `${svgLine(2, "0", 2, "8", ' stroke-linecap="square" shape-rendering="geometricPrecision"')}${svgPath("M 2 4 L 15 4 M 12 1.5 L 16 4 L 12 6.5")}`, ' overflow="visible"'),
1023
+ stretchLineDiv()
1024
+ ], "side-svg-compound-arrow");
1025
+ case "line-fat-arrow":
1026
+ return segmented("4px", 2, [
1027
+ stretchLineDiv(),
1028
+ svgSegment("side-svg-beak", 4, 8, `${svgLine(2, "0", 2, "8", ' stroke-linecap="square" shape-rendering="geometricPrecision"')}${svgPath("M 2 2.5 L 11 2.5 M 2 5.5 L 11 5.5 M 10 0.5 L 15 4 L 10 7.5")}`, ' overflow="visible"'),
1029
+ stretchLineDiv()
1030
+ ], "side-svg-compound-arrow");
1031
+ case "brace-warning":
1032
+ case "brace-question":
1033
+ return makeSvgForSideType("brace", false);
1034
+ default:
1035
+ return "";
1036
+ }
1037
+ }
1038
+ function toPreviewKind(type) {
1039
+ switch (type) {
1040
+ case "heading":
1041
+ return "heading";
1042
+ case "unordered-list":
1043
+ return "unordered-list";
1044
+ case "ordered-list":
1045
+ return "ordered-list";
1046
+ case "blockquote":
1047
+ return "blockquote";
1048
+ case "code-fence":
1049
+ return "code-fence";
1050
+ case "thematic-break":
1051
+ return "thematic-break";
1052
+ case "math-block":
1053
+ return "math-block";
1054
+ case "table":
1055
+ return "table";
1056
+ case "html-block":
1057
+ return "html-block";
1058
+ default:
1059
+ return "paragraph";
1060
+ }
1061
+ }
1062
+ function renderMainBlocks(block) {
1063
+ const rawMembers = Array.isArray(block.attributes?.mainBlocks) ? block.attributes?.mainBlocks : [];
1064
+ return rawMembers.map((entry, index) => {
1065
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
1066
+ return "";
1067
+ }
1068
+ const type = typeof entry.type === "string" ? entry.type : "paragraph";
1069
+ const raw = typeof entry.raw === "string" ? entry.raw : "";
1070
+ const memberBlock = {
1071
+ blockId: `${block.blockId}:member:${index}`,
1072
+ kind: toPreviewKind(type),
1073
+ raw,
1074
+ startLine: block.startLine,
1075
+ endLine: block.endLine,
1076
+ renderKey: `${block.renderKey}:member:${index}`
1077
+ };
1078
+ if (type === "heading" && typeof entry.headingLevel === "number") {
1079
+ memberBlock.headingLevel = entry.headingLevel;
1080
+ }
1081
+ if (type === "code-fence" && typeof entry.language === "string") {
1082
+ memberBlock.language = entry.language;
1083
+ }
1084
+ return renderBlockDefault(memberBlock);
1085
+ }).join("");
1086
+ }
1087
+ function isSideAnnotationPreviewBlock(block) {
1088
+ return block.kind === "custom" && block.attributes?.customBlockKey === "side-annotation";
1089
+ }
1090
+ function renderSideAnnotationPreviewBlock(block) {
1091
+ if (!isSideAnnotationPreviewBlock(block)) {
1092
+ return `<div>${escapeHtml2(block.raw)}</div>`;
1093
+ }
1094
+ const sideType = typeof block.attributes?.sideType === "string" ? block.attributes.sideType : "plain";
1095
+ const annotationText = typeof block.attributes?.annotationText === "string" ? block.attributes.annotationText : "";
1096
+ const orphan = Boolean(block.attributes?.orphan);
1097
+ const className = ["side-annotation", `side-type-${sideType}`, orphan ? "side-orphan" : ""].filter(Boolean).join(" ");
1098
+ const asideClass = ["side-annotation-aside", orphan ? "side-annotation-orphan" : ""].filter(Boolean).join(" ");
1099
+ const decoration = makeSvgForSideType(sideType, orphan);
1100
+ const mainHtml = renderMainBlocks(block);
1101
+ const textHtml = annotationText ? `<span class="side-annotation-text">${escapeHtml2(annotationText)}</span>` : "";
1102
+ return [
1103
+ `<div class="${className}" data-side-type="${escapeAttribute(sideType)}"${orphan ? ' data-side-orphan="true"' : ""}${annotationText ? ` data-side-text="${escapeAttribute(annotationText)}"` : ""}>`,
1104
+ `<div class="side-annotation-main">${mainHtml}</div>`,
1105
+ `<div class="${asideClass}">${decoration}${textHtml}</div>`,
1106
+ "</div>"
1107
+ ].join("");
1108
+ }
1109
+
1110
+ // src/renderer/cards-renderer.ts
1111
+ import {
1112
+ CARDS_FAMILY_CUSTOM_BLOCK_KEY,
1113
+ isCardsFamilyAttributes,
1114
+ parseMarkdownToDocument
1115
+ } from "@owomark/core";
1116
+ function escapeHtml3(text) {
1117
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1118
+ }
1119
+ function isCardsFamilyPreviewBlock(block) {
1120
+ return block.kind === "custom" && block.attributes?.customBlockKey === CARDS_FAMILY_CUSTOM_BLOCK_KEY && isCardsFamilyAttributes(block.attributes);
1121
+ }
1122
+ function renderCardBody(markdown) {
1123
+ if (!markdown.trim()) {
1124
+ return "";
1125
+ }
1126
+ const nestedBlocks = parseMarkdownToDocument(markdown).previewBlocks;
1127
+ return nestedBlocks.map((nestedBlock) => {
1128
+ if (isCardsFamilyPreviewBlock(nestedBlock)) {
1129
+ return renderCardsFamilyPreviewBlock(nestedBlock);
1130
+ }
1131
+ if (nestedBlock.kind === "custom" && nestedBlock.attributes?.customBlockKey === "side-annotation") {
1132
+ return renderSideAnnotationPreviewBlock(nestedBlock);
1133
+ }
1134
+ return renderBlockDefault(nestedBlock);
1135
+ }).join("");
1136
+ }
1137
+ function renderCardsFamilyPreviewBlock(block) {
1138
+ if (!isCardsFamilyPreviewBlock(block)) {
1139
+ throw new Error("[owomark/view] cards renderer requires a cards-family preview block");
1140
+ }
1141
+ const attributes = block.attributes;
1142
+ const cardsHtml = attributes.cards.map((card) => {
1143
+ const toneAttr = card.tone ? ` data-owo-card-tone="${card.tone}"` : "";
1144
+ const toneClass = card.tone ? ` owo-card-tone-${card.tone}` : "";
1145
+ const titleHtml = card.title ? `<header class="owo-card-title">${escapeHtml3(card.title)}</header>` : "";
1146
+ const bodyHtml = renderCardBody(card.bodyMarkdown);
1147
+ return [
1148
+ `<article class="owo-card${toneClass}" data-owo-card${toneAttr}>`,
1149
+ titleHtml,
1150
+ `<div class="owo-card-body">${bodyHtml}</div>`,
1151
+ "</article>"
1152
+ ].join("");
1153
+ }).join("");
1154
+ return [
1155
+ `<section class="owo-cards" data-owo-cards data-owo-cards-cols="${attributes.layout.cols}">`,
1156
+ cardsHtml,
1157
+ "</section>"
1158
+ ].join("");
1159
+ }
1160
+
1161
+ // src/renderer/registry.ts
1162
+ function normalizeTarget(target) {
1163
+ const normalized = {
1164
+ kind: target.kind,
1165
+ customBlockKey: target.customBlockKey ?? null
1166
+ };
1167
+ if (normalized.kind === "custom" && !normalized.customBlockKey) {
1168
+ throw new Error("[owomark/view] custom renderer targets must declare customBlockKey");
1169
+ }
1170
+ return normalized;
1171
+ }
1172
+ function resolveTargetFromLookup(lookup) {
1173
+ if ("blockId" in lookup) {
1174
+ const block = lookup;
1175
+ if (block.kind === "custom") {
1176
+ const customBlockKey = typeof block.attributes?.customBlockKey === "string" ? block.attributes.customBlockKey : null;
1177
+ if (!customBlockKey) {
1178
+ return {
1179
+ kind: "custom",
1180
+ customBlockKey: null
1181
+ };
1182
+ }
1183
+ return {
1184
+ kind: "custom",
1185
+ customBlockKey
1186
+ };
1187
+ }
1188
+ return {
1189
+ kind: block.kind
1190
+ };
1191
+ }
1192
+ return normalizeTarget(lookup);
1193
+ }
1194
+ function toSpecificKey(target) {
1195
+ return target.kind === "custom" ? `custom:${target.customBlockKey}` : `kind:${target.kind}`;
1196
+ }
1197
+ function createRendererRegistry() {
1198
+ const renderers = /* @__PURE__ */ new Map();
1199
+ const metadata = /* @__PURE__ */ new Map();
1200
+ const targets = /* @__PURE__ */ new Map();
1201
+ for (const descriptor of runtimeBlockRegistry.list()) {
1202
+ const target = {
1203
+ kind: descriptor.previewKind,
1204
+ customBlockKey: descriptor.customBlockKey ?? null
1205
+ };
1206
+ const key = toSpecificKey(target);
1207
+ metadata.set(key, {
1208
+ mode: descriptor.rendererMode,
1209
+ priority: descriptor.rendererPriority,
1210
+ heavy: descriptor.heavy
1211
+ });
1212
+ targets.set(key, target);
1213
+ }
1214
+ renderers.set("custom:side-annotation", {
1215
+ mode: metadata.get("custom:side-annotation")?.mode ?? "html-worker-safe",
1216
+ priority: metadata.get("custom:side-annotation")?.priority ?? "realtime",
1217
+ version: "builtin-side-annotation-v1",
1218
+ workerRendererId: "builtin:side-annotation",
1219
+ render(block) {
1220
+ return {
1221
+ kind: "html",
1222
+ html: renderSideAnnotationPreviewBlock(block)
1223
+ };
1224
+ }
1225
+ });
1226
+ targets.set("custom:side-annotation", {
1227
+ kind: "custom",
1228
+ customBlockKey: "side-annotation"
1229
+ });
1230
+ renderers.set(`custom:${CARDS_FAMILY_CUSTOM_BLOCK_KEY2}`, {
1231
+ mode: "html-worker-safe",
1232
+ priority: "realtime",
1233
+ version: "builtin-cards-family-v1",
1234
+ render(block) {
1235
+ return {
1236
+ kind: "html",
1237
+ html: renderCardsFamilyPreviewBlock(block)
1238
+ };
1239
+ }
1240
+ });
1241
+ metadata.set(`custom:${CARDS_FAMILY_CUSTOM_BLOCK_KEY2}`, {
1242
+ mode: "html-worker-safe",
1243
+ priority: "realtime"
1244
+ });
1245
+ targets.set(`custom:${CARDS_FAMILY_CUSTOM_BLOCK_KEY2}`, {
1246
+ kind: "custom",
1247
+ customBlockKey: CARDS_FAMILY_CUSTOM_BLOCK_KEY2
1248
+ });
1249
+ function getMetadata(target) {
1250
+ if (target.kind === "custom" && !target.customBlockKey) {
1251
+ return null;
1252
+ }
1253
+ const specificKey = toSpecificKey(target);
1254
+ return metadata.get(specificKey) ?? null;
1255
+ }
1256
+ function getRenderer(target) {
1257
+ if (target.kind === "custom" && !target.customBlockKey) {
1258
+ return null;
1259
+ }
1260
+ const specificKey = toSpecificKey(target);
1261
+ return renderers.get(specificKey) ?? null;
1262
+ }
1263
+ return {
1264
+ get(lookup) {
1265
+ return getRenderer(resolveTargetFromLookup(lookup));
1266
+ },
1267
+ register(targetLike, renderer) {
1268
+ const target = normalizeTarget(targetLike);
1269
+ const key = toSpecificKey(target);
1270
+ renderers.set(key, renderer);
1271
+ targets.set(key, target);
1272
+ if (!metadata.has(key)) {
1273
+ metadata.set(key, {
1274
+ mode: renderer.mode,
1275
+ priority: renderer.priority
1276
+ });
1277
+ }
1278
+ },
1279
+ unregister(targetLike) {
1280
+ const key = toSpecificKey(normalizeTarget(targetLike));
1281
+ renderers.delete(key);
1282
+ },
1283
+ registerMetadata(targetLike, meta) {
1284
+ const target = normalizeTarget(targetLike);
1285
+ const key = toSpecificKey(target);
1286
+ metadata.set(key, meta);
1287
+ targets.set(key, target);
1288
+ },
1289
+ isHeavy(lookup) {
1290
+ const target = resolveTargetFromLookup(lookup);
1291
+ const meta = getMetadata(target);
1292
+ if (meta?.heavy) return true;
1293
+ const def = getRenderer(target);
1294
+ return def?.priority === "deferred" || false;
1295
+ },
1296
+ getMode(lookup) {
1297
+ const target = resolveTargetFromLookup(lookup);
1298
+ const def = getRenderer(target);
1299
+ if (def) return def.mode;
1300
+ return getMetadata(target)?.mode ?? null;
1301
+ },
1302
+ getPriority(lookup) {
1303
+ const target = resolveTargetFromLookup(lookup);
1304
+ const def = getRenderer(target);
1305
+ if (def) return def.priority;
1306
+ return getMetadata(target)?.priority ?? null;
1307
+ },
1308
+ listRegistered() {
1309
+ const keys = /* @__PURE__ */ new Set([
1310
+ ...renderers.keys(),
1311
+ ...metadata.keys()
1312
+ ]);
1313
+ return Array.from(keys).map((key) => targets.get(key)).filter((target) => target != null);
1314
+ }
1315
+ };
1316
+ }
1317
+
943
1318
  // src/strategies/shared.ts
944
1319
  var scheduleIdle = typeof globalThis.requestIdleCallback === "function" ? (fn) => globalThis.requestIdleCallback(fn) : (fn) => setTimeout(fn, 1);
945
1320
  var cancelIdle = typeof globalThis.cancelIdleCallback === "function" ? (id) => globalThis.cancelIdleCallback(id) : (id) => clearTimeout(id);
@@ -970,7 +1345,7 @@ function cancelAllIdle(pendingIdleIds) {
970
1345
  pendingIdleIds.length = 0;
971
1346
  }
972
1347
  function isDeferred(block, registry) {
973
- const def = registry.get(block.kind);
1348
+ const def = registry.get(block);
974
1349
  return def?.priority === "deferred";
975
1350
  }
976
1351
  function createRenderBlockFull(registry, renderCache, externalRenderBlock, scheduler) {
@@ -979,9 +1354,14 @@ function createRenderBlockFull(registry, renderCache, externalRenderBlock, sched
979
1354
  ...baseContext,
980
1355
  sourceLineOffset: block.startLine - 1
981
1356
  };
982
- const customRenderer = registry.get(block.kind);
1357
+ if (externalRenderBlock && block.kind === "custom") {
1358
+ const html2 = await externalRenderBlock(block, context);
1359
+ renderCache.set(block.renderKey, html2);
1360
+ return { kind: "html", html: html2 };
1361
+ }
1362
+ const customRenderer = registry.get(block);
983
1363
  if (customRenderer) {
984
- if (customRenderer.mode === "html-worker-safe" && customRenderer.workerModuleUrl && scheduler) {
1364
+ if (customRenderer.mode === "html-worker-safe" && customRenderer.workerRendererId && scheduler) {
985
1365
  try {
986
1366
  const html2 = await scheduler.submitWorkerTask(block, customRenderer, context);
987
1367
  renderCache.set(block.renderKey, html2);
@@ -1708,7 +2088,8 @@ function createPreviewTaskScheduler(options) {
1708
2088
  }
1709
2089
  const scheduler = {
1710
2090
  submitWorkerTask(block, rendererDef, context) {
1711
- if (permanentlyFailed || !rendererDef.workerModuleUrl) {
2091
+ const rendererId = rendererDef.workerRendererId;
2092
+ if (permanentlyFailed || !rendererId) {
1712
2093
  return Promise.reject(new Error("Worker unavailable"));
1713
2094
  }
1714
2095
  const slot = getLeastBusySlot();
@@ -1723,7 +2104,7 @@ function createPreviewTaskScheduler(options) {
1723
2104
  type: "render",
1724
2105
  taskId,
1725
2106
  block: serializeBlock(block),
1726
- rendererModuleUrl: rendererDef.workerModuleUrl,
2107
+ rendererId,
1727
2108
  context: {
1728
2109
  version: context.version,
1729
2110
  themeKey: context.themeKey,
@@ -1879,7 +2260,6 @@ export {
1879
2260
  THEME_DARK_CLASS,
1880
2261
  THEME_LIGHT_CLASS,
1881
2262
  createOwoMarkPreviewEngine,
1882
- createOwoMarkVanillaEditor,
1883
2263
  createOwoMarkView,
1884
2264
  createPreviewTaskScheduler,
1885
2265
  createRendererRegistry,
@@ -1887,5 +2267,9 @@ export {
1887
2267
  createViewEngine,
1888
2268
  ensureSkeletonStyles,
1889
2269
  getThemeClassName,
1890
- renderBlockDefault
2270
+ isCardsFamilyPreviewBlock,
2271
+ isSideAnnotationPreviewBlock,
2272
+ renderBlockDefault,
2273
+ renderCardsFamilyPreviewBlock,
2274
+ renderSideAnnotationPreviewBlock
1891
2275
  };
@@ -1,5 +1,5 @@
1
1
  import { PreviewBlock } from '@owomark/core';
2
- import { P as PreviewRendererRegistry } from '../../types-DsL_4tUb.js';
2
+ import { P as PreviewRendererRegistry } from '../../types-D4TVpyP7.js';
3
3
 
4
4
  declare function estimateBlockHeight(block: PreviewBlock, registry?: PreviewRendererRegistry): number;
5
5
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  estimateBlockHeight
3
- } from "../../chunk-KHKPOH74.js";
3
+ } from "../../chunk-BPOZMVU7.js";
4
4
  export {
5
5
  estimateBlockHeight
6
6
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VirtualViewportManager
3
- } from "../../chunk-WA6XHBZS.js";
3
+ } from "../../chunk-656BO747.js";
4
4
  export {
5
5
  VirtualViewportManager
6
6
  };