react-next-editor-js 0.1.0

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.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +877 -0
  3. package/dist/chunk-3QWXTDLY.cjs +486 -0
  4. package/dist/chunk-3QWXTDLY.cjs.map +1 -0
  5. package/dist/chunk-5F6SPYCN.cjs +180 -0
  6. package/dist/chunk-5F6SPYCN.cjs.map +1 -0
  7. package/dist/chunk-6NTSXJX4.js +174 -0
  8. package/dist/chunk-6NTSXJX4.js.map +1 -0
  9. package/dist/chunk-7VYJDBH7.js +261 -0
  10. package/dist/chunk-7VYJDBH7.js.map +1 -0
  11. package/dist/chunk-DBSFCCBG.cjs +1712 -0
  12. package/dist/chunk-DBSFCCBG.cjs.map +1 -0
  13. package/dist/chunk-EFE6RHDL.cjs +4 -0
  14. package/dist/chunk-EFE6RHDL.cjs.map +1 -0
  15. package/dist/chunk-G6YRIEK4.js +3 -0
  16. package/dist/chunk-G6YRIEK4.js.map +1 -0
  17. package/dist/chunk-GFNFJ3FL.cjs +119 -0
  18. package/dist/chunk-GFNFJ3FL.cjs.map +1 -0
  19. package/dist/chunk-IG2YLUFW.js +114 -0
  20. package/dist/chunk-IG2YLUFW.js.map +1 -0
  21. package/dist/chunk-JQXTWLHL.js +176 -0
  22. package/dist/chunk-JQXTWLHL.js.map +1 -0
  23. package/dist/chunk-NJCEHQV3.cjs +454 -0
  24. package/dist/chunk-NJCEHQV3.cjs.map +1 -0
  25. package/dist/chunk-O4GTLC3T.js +478 -0
  26. package/dist/chunk-O4GTLC3T.js.map +1 -0
  27. package/dist/chunk-ODHABIIC.cjs +82 -0
  28. package/dist/chunk-ODHABIIC.cjs.map +1 -0
  29. package/dist/chunk-PZ5AY32C.js +9 -0
  30. package/dist/chunk-PZ5AY32C.js.map +1 -0
  31. package/dist/chunk-Q7SFCCGT.cjs +11 -0
  32. package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
  33. package/dist/chunk-QIUIYBCZ.js +80 -0
  34. package/dist/chunk-QIUIYBCZ.js.map +1 -0
  35. package/dist/chunk-QROUNVQK.js +450 -0
  36. package/dist/chunk-QROUNVQK.js.map +1 -0
  37. package/dist/chunk-T6FR37IC.js +41 -0
  38. package/dist/chunk-T6FR37IC.js.map +1 -0
  39. package/dist/chunk-TI44I654.cjs +265 -0
  40. package/dist/chunk-TI44I654.cjs.map +1 -0
  41. package/dist/chunk-TXPLBAH5.cjs +47 -0
  42. package/dist/chunk-TXPLBAH5.cjs.map +1 -0
  43. package/dist/chunk-U3O54IYI.cjs +187 -0
  44. package/dist/chunk-U3O54IYI.cjs.map +1 -0
  45. package/dist/chunk-VLC7SZMT.js +1669 -0
  46. package/dist/chunk-VLC7SZMT.js.map +1 -0
  47. package/dist/core/index.cjs +232 -0
  48. package/dist/core/index.cjs.map +1 -0
  49. package/dist/core/index.d.cts +122 -0
  50. package/dist/core/index.d.ts +122 -0
  51. package/dist/core/index.js +7 -0
  52. package/dist/core/index.js.map +1 -0
  53. package/dist/defaults-EQD5QKCU.js +4 -0
  54. package/dist/defaults-EQD5QKCU.js.map +1 -0
  55. package/dist/defaults-MLYXD2BG.cjs +49 -0
  56. package/dist/defaults-MLYXD2BG.cjs.map +1 -0
  57. package/dist/docx-BUrf4PFj.d.ts +49 -0
  58. package/dist/docx-DLfSdvXm.d.cts +49 -0
  59. package/dist/docx-LDETXV3L.js +5 -0
  60. package/dist/docx-LDETXV3L.js.map +1 -0
  61. package/dist/docx-N2LKIOK3.cjs +14 -0
  62. package/dist/docx-N2LKIOK3.cjs.map +1 -0
  63. package/dist/export/index.cjs +54 -0
  64. package/dist/export/index.cjs.map +1 -0
  65. package/dist/export/index.d.cts +60 -0
  66. package/dist/export/index.d.ts +60 -0
  67. package/dist/export/index.js +9 -0
  68. package/dist/export/index.js.map +1 -0
  69. package/dist/html-5BXJPQU3.js +7 -0
  70. package/dist/html-5BXJPQU3.js.map +1 -0
  71. package/dist/html-KU2KHLRF.cjs +24 -0
  72. package/dist/html-KU2KHLRF.cjs.map +1 -0
  73. package/dist/import/index.cjs +15 -0
  74. package/dist/import/index.cjs.map +1 -0
  75. package/dist/import/index.d.cts +37 -0
  76. package/dist/import/index.d.ts +37 -0
  77. package/dist/import/index.js +6 -0
  78. package/dist/import/index.js.map +1 -0
  79. package/dist/index.cjs +1035 -0
  80. package/dist/index.cjs.map +1 -0
  81. package/dist/index.d.cts +248 -0
  82. package/dist/index.d.ts +248 -0
  83. package/dist/index.js +885 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/persistence/index.cjs +37 -0
  86. package/dist/persistence/index.cjs.map +1 -0
  87. package/dist/persistence/index.d.cts +279 -0
  88. package/dist/persistence/index.d.ts +279 -0
  89. package/dist/persistence/index.js +4 -0
  90. package/dist/persistence/index.js.map +1 -0
  91. package/dist/sanitize-7IZ-SW1f.d.ts +361 -0
  92. package/dist/sanitize-CvmgqbsA.d.cts +361 -0
  93. package/dist/server/index.cjs +400 -0
  94. package/dist/server/index.cjs.map +1 -0
  95. package/dist/server/index.d.cts +229 -0
  96. package/dist/server/index.d.ts +229 -0
  97. package/dist/server/index.js +390 -0
  98. package/dist/server/index.js.map +1 -0
  99. package/dist/styles.css +680 -0
  100. package/dist/types-B4z0Quvv.d.cts +193 -0
  101. package/dist/types-B4z0Quvv.d.ts +193 -0
  102. package/package.json +183 -0
@@ -0,0 +1,41 @@
1
+ // src/security/css.ts
2
+ var ALIGN_VALUES = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
3
+ function cssAlign(value) {
4
+ return typeof value === "string" && ALIGN_VALUES.has(value) ? value : null;
5
+ }
6
+ function cssNumber(value, min, max) {
7
+ let n;
8
+ if (typeof value === "number") {
9
+ n = value;
10
+ } else if (typeof value === "string") {
11
+ const trimmed = value.trim();
12
+ if (!/^-?\d+(\.\d+)?$/.test(trimmed)) return null;
13
+ n = parseFloat(trimmed);
14
+ } else {
15
+ return null;
16
+ }
17
+ if (!Number.isFinite(n)) return null;
18
+ return Math.min(max, Math.max(min, n));
19
+ }
20
+ function cssInteger(value, min, max) {
21
+ const n = cssNumber(value, min, max);
22
+ return n === null ? null : Math.round(n);
23
+ }
24
+ function normalizeCssColor(value) {
25
+ if (typeof value !== "string") return null;
26
+ const v = value.trim().toLowerCase();
27
+ if (/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v;
28
+ if (/^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)$/.test(v)) return v;
29
+ if (/^rgba\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*(0|1|0?\.\d+)\s*\)$/.test(v)) return v;
30
+ if (/^[a-z]{3,20}$/.test(v)) return v;
31
+ return null;
32
+ }
33
+ function cssFontFamily(value) {
34
+ if (value == null) return null;
35
+ const cleaned = String(value).replace(/[^a-zA-Z0-9 ,_-]/g, "").replace(/\s+/g, " ").trim();
36
+ return cleaned ? cleaned : null;
37
+ }
38
+
39
+ export { cssAlign, cssFontFamily, cssInteger, cssNumber, normalizeCssColor };
40
+ //# sourceMappingURL=chunk-T6FR37IC.js.map
41
+ //# sourceMappingURL=chunk-T6FR37IC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/security/css.ts"],"names":[],"mappings":";AAWA,IAAM,YAAA,uBAAmB,GAAA,CAAI,CAAC,QAAQ,QAAA,EAAU,OAAA,EAAS,SAAS,CAAC,CAAA;AAG5D,SAAS,SAAS,KAAA,EAAgE;AACvF,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,aAAa,GAAA,CAAI,KAAK,IACrD,KAAA,GACD,IAAA;AACN;AAQO,SAAS,SAAA,CAAU,KAAA,EAAgB,GAAA,EAAa,GAAA,EAA4B;AACjF,EAAA,IAAI,CAAA;AACJ,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,CAAA,GAAI,KAAA;AAAA,EACN,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AAGpC,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,OAAO,GAAG,OAAO,IAAA;AAC7C,IAAA,CAAA,GAAI,WAAW,OAAO,CAAA;AAAA,EACxB,CAAA,MAAO;AACL,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,GAAG,OAAO,IAAA;AAChC,EAAA,OAAO,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,CAAC,CAAC,CAAA;AACvC;AAGO,SAAS,UAAA,CAAW,KAAA,EAAgB,GAAA,EAAa,GAAA,EAA4B;AAClF,EAAA,MAAM,CAAA,GAAI,SAAA,CAAU,KAAA,EAAO,GAAA,EAAK,GAAG,CAAA;AACnC,EAAA,OAAO,CAAA,KAAM,IAAA,GAAO,IAAA,GAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AACzC;AAMO,SAAS,kBAAkB,KAAA,EAA+B;AAC/D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,IAAA;AACtC,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AACnC,EAAA,IAAI,sDAAA,CAAuD,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AAC3E,EAAA,IAAI,oDAAA,CAAqD,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AACzE,EAAA,IAAI,yEAAA,CAA0E,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AAC9F,EAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AACpC,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,cAAc,KAAA,EAA+B;AAC3D,EAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAA,CACzB,OAAA,CAAQ,mBAAA,EAAqB,EAAE,CAAA,CAC/B,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,IAAA,EAAK;AACR,EAAA,OAAO,UAAU,OAAA,GAAU,IAAA;AAC7B","file":"chunk-T6FR37IC.js","sourcesContent":["/**\n * CSS value sanitization (§5.12). These DOM-free helpers are the single guard\n * for every attribute value that is interpolated into an inline `style` string\n * by a node/mark `toDOM`. They neutralize CSS injection from attacker-controlled\n * document JSON (e.g. a shared/loaded document) — values like\n * `\"left;background:url(//evil)\"` can never break out of their declaration or\n * introduce `url(...)` fetches.\n *\n * Pure and isomorphic: safe to import in the schema (browser and Node).\n */\n\nconst ALIGN_VALUES = new Set(['left', 'center', 'right', 'justify']);\n\n/** Validate a text-alignment keyword, or null. */\nexport function cssAlign(value: unknown): 'left' | 'center' | 'right' | 'justify' | null {\n return typeof value === 'string' && ALIGN_VALUES.has(value)\n ? (value as 'left' | 'center' | 'right' | 'justify')\n : null;\n}\n\n/**\n * Coerce a value to a finite number clamped to [min, max], or null if it is not\n * numeric. Accepts numbers or numeric strings (with an optional leading number),\n * so a malicious `\"0;background:url(x)\"` parses to `0` (or null) — never a\n * style breakout.\n */\nexport function cssNumber(value: unknown, min: number, max: number): number | null {\n let n: number;\n if (typeof value === 'number') {\n n = value;\n } else if (typeof value === 'string') {\n // Only accept a clean numeric token; reject anything with extra characters\n // (so \"5;x\" or \"1px;background:...\" is rejected rather than coerced to 5).\n const trimmed = value.trim();\n if (!/^-?\\d+(\\.\\d+)?$/.test(trimmed)) return null;\n n = parseFloat(trimmed);\n } else {\n return null;\n }\n if (!Number.isFinite(n)) return null;\n return Math.min(max, Math.max(min, n));\n}\n\n/** Coerce a value to a clamped, rounded integer, or null. */\nexport function cssInteger(value: unknown, min: number, max: number): number | null {\n const n = cssNumber(value, min, max);\n return n === null ? null : Math.round(n);\n}\n\n/**\n * Validate and normalize a CSS color (hex / rgb / rgba / named), rejecting\n * anything that could carry an injection (e.g. `url(...)`, `expression(...)`).\n */\nexport function normalizeCssColor(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n if (/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v;\n if (/^rgb\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*\\)$/.test(v)) return v;\n if (/^rgba\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*(0|1|0?\\.\\d+)\\s*\\)$/.test(v)) return v;\n if (/^[a-z]{3,20}$/.test(v)) return v; // named colors\n return null;\n}\n\n/**\n * Sanitize a font-family value to a safe character set (letters, digits, space,\n * comma, hyphen, underscore). Strips quotes, semicolons, parentheses, etc., so\n * `url(...)`/declaration breakouts are impossible. Returns null if empty.\n */\nexport function cssFontFamily(value: unknown): string | null {\n if (value == null) return null;\n const cleaned = String(value)\n .replace(/[^a-zA-Z0-9 ,_-]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n return cleaned ? cleaned : null;\n}\n"]}
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ var chunkTXPLBAH5_cjs = require('./chunk-TXPLBAH5.cjs');
4
+ var chunk5F6SPYCN_cjs = require('./chunk-5F6SPYCN.cjs');
5
+ var chunkU3O54IYI_cjs = require('./chunk-U3O54IYI.cjs');
6
+
7
+ // src/export/html.ts
8
+ function escapeHtml(value) {
9
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
10
+ }
11
+ function escapeAttr(value) {
12
+ return escapeHtml(value).replace(/"/g, "&quot;");
13
+ }
14
+ var MARK_ORDER = [
15
+ "link",
16
+ "textColor",
17
+ "highlight",
18
+ "fontFamily",
19
+ "fontSize",
20
+ "strong",
21
+ "em",
22
+ "underline",
23
+ "strikethrough",
24
+ "superscript",
25
+ "subscript",
26
+ "code"
27
+ ];
28
+ function openMark(mark) {
29
+ const attrs = mark.attrs ?? {};
30
+ switch (mark.type) {
31
+ case "strong":
32
+ return "<strong>";
33
+ case "em":
34
+ return "<em>";
35
+ case "underline":
36
+ return "<u>";
37
+ case "strikethrough":
38
+ return "<s>";
39
+ case "superscript":
40
+ return "<sup>";
41
+ case "subscript":
42
+ return "<sub>";
43
+ case "code":
44
+ return "<code>";
45
+ case "link": {
46
+ const href = chunk5F6SPYCN_cjs.sanitizeUrl(String(attrs.href ?? "")) ?? "";
47
+ const title = attrs.title ? ` title="${escapeAttr(String(attrs.title))}"` : "";
48
+ return `<a href="${escapeAttr(href)}"${title} rel="noopener noreferrer nofollow">`;
49
+ }
50
+ case "fontFamily": {
51
+ const family = chunkTXPLBAH5_cjs.cssFontFamily(attrs.family);
52
+ return family ? `<span style="font-family: ${family}">` : "<span>";
53
+ }
54
+ case "fontSize": {
55
+ const size = chunkTXPLBAH5_cjs.cssNumber(attrs.size, 1, 1638);
56
+ return size ? `<span style="font-size: ${size}pt">` : "<span>";
57
+ }
58
+ case "textColor": {
59
+ const color = chunkTXPLBAH5_cjs.normalizeCssColor(attrs.color);
60
+ return color ? `<span style="color: ${color}">` : "<span>";
61
+ }
62
+ case "highlight": {
63
+ const color = chunkTXPLBAH5_cjs.normalizeCssColor(attrs.color) ?? "#fff2a8";
64
+ return `<mark style="background-color: ${color}">`;
65
+ }
66
+ default:
67
+ return "";
68
+ }
69
+ }
70
+ function closeMark(mark) {
71
+ switch (mark.type) {
72
+ case "strong":
73
+ return "</strong>";
74
+ case "em":
75
+ return "</em>";
76
+ case "underline":
77
+ return "</u>";
78
+ case "strikethrough":
79
+ return "</s>";
80
+ case "superscript":
81
+ return "</sup>";
82
+ case "subscript":
83
+ return "</sub>";
84
+ case "code":
85
+ return "</code>";
86
+ case "link":
87
+ return "</a>";
88
+ case "fontFamily":
89
+ case "fontSize":
90
+ case "textColor":
91
+ return "</span>";
92
+ case "highlight":
93
+ return "</mark>";
94
+ default:
95
+ return "";
96
+ }
97
+ }
98
+ function sortMarks(marks) {
99
+ return [...marks].sort((a, b) => {
100
+ const ia = MARK_ORDER.indexOf(a.type);
101
+ const ib = MARK_ORDER.indexOf(b.type);
102
+ return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);
103
+ });
104
+ }
105
+ function serializeInline(content) {
106
+ if (!content) return "";
107
+ let out = "";
108
+ for (const node of content) {
109
+ if (node.type === "text") {
110
+ const marks = sortMarks(node.marks ?? []);
111
+ let text = escapeHtml(node.text ?? "");
112
+ for (let i = marks.length - 1; i >= 0; i--) text = openMark(marks[i]) + text;
113
+ for (const mark of marks) text += closeMark(mark);
114
+ out += text;
115
+ } else if (node.type === "hard_break") {
116
+ out += "<br>";
117
+ } else if (node.type === "image") {
118
+ out += serializeImage(node);
119
+ }
120
+ }
121
+ return out;
122
+ }
123
+ function serializeImage(node) {
124
+ const src = chunk5F6SPYCN_cjs.sanitizeImageSrc(String(node.attrs?.src ?? ""));
125
+ if (!src) return "";
126
+ const alt = node.attrs?.alt ? ` alt="${escapeAttr(String(node.attrs.alt))}"` : ' alt=""';
127
+ const title = node.attrs?.title ? ` title="${escapeAttr(String(node.attrs.title))}"` : "";
128
+ const safeWidth = chunkTXPLBAH5_cjs.cssInteger(node.attrs?.width, 1, 4e3);
129
+ const width = safeWidth ? ` style="width: ${safeWidth}px"` : "";
130
+ return `<img class="rne-image" src="${escapeAttr(src)}"${alt}${title}${width}>`;
131
+ }
132
+ function blockStyle(attrs) {
133
+ if (!attrs) return "";
134
+ const styles = [];
135
+ const align = chunkTXPLBAH5_cjs.cssAlign(attrs.align);
136
+ if (align) styles.push(`text-align: ${align}`);
137
+ const indent = chunkTXPLBAH5_cjs.cssInteger(attrs.indent, 0, 12);
138
+ if (indent && indent > 0) styles.push(`margin-left: ${indent * 3}em`);
139
+ const lineHeight = chunkTXPLBAH5_cjs.cssNumber(attrs.lineHeight, 0.1, 10);
140
+ if (lineHeight) styles.push(`line-height: ${lineHeight}`);
141
+ return styles.length ? ` style="${styles.join("; ")}"` : "";
142
+ }
143
+ function serializeBlock(node) {
144
+ switch (node.type) {
145
+ case "paragraph":
146
+ return `<p${blockStyle(node.attrs)}>${serializeInline(node.content) || "<br>"}</p>`;
147
+ case "heading": {
148
+ const level = Math.min(6, Math.max(1, Number(node.attrs?.level ?? 1)));
149
+ return `<h${level}${blockStyle(node.attrs)}>${serializeInline(node.content)}</h${level}>`;
150
+ }
151
+ case "blockquote":
152
+ return `<blockquote class="rne-blockquote">${(node.content ?? []).map(serializeBlock).join("")}</blockquote>`;
153
+ case "horizontal_rule":
154
+ return '<hr class="rne-hr">';
155
+ case "page_break":
156
+ return '<div class="rne-page-break"></div>';
157
+ case "bullet_list":
158
+ case "ordered_list":
159
+ return serializeList(node);
160
+ case "table":
161
+ return serializeTable(node);
162
+ default:
163
+ if (node.content) return node.content.map(serializeBlock).join("");
164
+ return "";
165
+ }
166
+ }
167
+ function serializeList(node) {
168
+ const ordered = node.type === "ordered_list";
169
+ const kind = node.attrs?.kind;
170
+ const tag = ordered ? "ol" : "ul";
171
+ const order = ordered ? Number(node.attrs?.order ?? 1) : 1;
172
+ const startAttr = ordered && order !== 1 ? ` start="${order}"` : "";
173
+ const classAttr = ordered ? ' class="rne-ordered-list"' : kind === "task" ? ' class="rne-task-list" data-type="task"' : ' class="rne-bullet-list"';
174
+ const items = (node.content ?? []).map((item) => {
175
+ if (item.type !== "list_item") return "";
176
+ const checked = item.attrs?.checked;
177
+ const inner = (item.content ?? []).map(serializeBlock).join("");
178
+ if (checked === true || checked === false) {
179
+ const box = checked ? "\u2611" : "\u2610";
180
+ return `<li class="rne-task-item" data-checked="${checked}"><span class="rne-task-checkbox">${box}</span><div class="rne-task-content">${inner}</div></li>`;
181
+ }
182
+ return `<li>${inner}</li>`;
183
+ }).join("");
184
+ return `<${tag}${classAttr}${startAttr}>${items}</${tag}>`;
185
+ }
186
+ function serializeTable(node) {
187
+ const rows = (node.content ?? []).map((row) => {
188
+ if (row.type !== "table_row") return "";
189
+ const cells = (row.content ?? []).map((cell) => {
190
+ const tag = cell.type === "table_header" ? "th" : "td";
191
+ const attrs = cell.attrs ?? {};
192
+ const parts = [];
193
+ const colspan = chunkTXPLBAH5_cjs.cssInteger(attrs.colspan, 1, 100);
194
+ if (colspan && colspan > 1) parts.push(`colspan="${colspan}"`);
195
+ const rowspan = chunkTXPLBAH5_cjs.cssInteger(attrs.rowspan, 1, 100);
196
+ if (rowspan && rowspan > 1) parts.push(`rowspan="${rowspan}"`);
197
+ const styles = [];
198
+ const bg = chunkTXPLBAH5_cjs.normalizeCssColor(attrs.background);
199
+ if (bg) styles.push(`background-color: ${bg}`);
200
+ const cellAlign = chunkTXPLBAH5_cjs.cssAlign(attrs.align);
201
+ if (cellAlign) styles.push(`text-align: ${cellAlign}`);
202
+ if (styles.length) parts.push(`style="${styles.join("; ")}"`);
203
+ const attrStr = parts.length ? ` ${parts.join(" ")}` : "";
204
+ return `<${tag}${attrStr}>${(cell.content ?? []).map(serializeBlock).join("")}</${tag}>`;
205
+ }).join("");
206
+ return `<tr>${cells}</tr>`;
207
+ }).join("");
208
+ return `<table class="rne-table"><tbody>${rows}</tbody></table>`;
209
+ }
210
+ function documentToHtml(doc) {
211
+ return (doc.content ?? []).map(serializeBlock).join("\n");
212
+ }
213
+ function printStylesheet(page) {
214
+ const { width, height } = chunkU3O54IYI_cjs.resolvePageDimensions(page);
215
+ const { top, right, bottom, left } = page.margins;
216
+ return `
217
+ @page { size: ${width}mm ${height}mm; margin: ${top}mm ${right}mm ${bottom}mm ${left}mm; }
218
+ * { box-sizing: border-box; }
219
+ html, body { margin: 0; padding: 0; }
220
+ body {
221
+ font-family: 'Times New Roman', Georgia, serif;
222
+ font-size: 12pt;
223
+ line-height: 1.5;
224
+ color: #111;
225
+ }
226
+ .rne-print-page { width: ${width - left - right}mm; margin: 0 auto; }
227
+ h1 { font-size: 2em; } h2 { font-size: 1.5em; } h3 { font-size: 1.25em; }
228
+ h4 { font-size: 1.1em; } h5 { font-size: 1em; } h6 { font-size: 0.9em; }
229
+ p { margin: 0 0 0.6em; }
230
+ blockquote.rne-blockquote { border-left: 3px solid #ccc; margin: 0 0 0.6em; padding-left: 1em; color: #444; }
231
+ hr.rne-hr { border: none; border-top: 1px solid #ccc; margin: 1em 0; }
232
+ img.rne-image { max-width: 100%; height: auto; }
233
+ table.rne-table { border-collapse: collapse; width: 100%; margin: 0 0 0.8em; }
234
+ table.rne-table td, table.rne-table th { border: 1px solid #999; padding: 4px 8px; vertical-align: top; }
235
+ table.rne-table th { background: #f0f0f0; font-weight: bold; }
236
+ ul, ol { margin: 0 0 0.6em; padding-left: 1.6em; }
237
+ ul.rne-task-list { list-style: none; padding-left: 0.4em; }
238
+ .rne-task-item { display: flex; gap: 0.4em; align-items: flex-start; }
239
+ .rne-page-break { break-after: page; page-break-after: always; height: 0; }
240
+ code { font-family: 'Courier New', monospace; background: #f3f3f3; padding: 0 2px; }
241
+ `.trim();
242
+ }
243
+ function buildPrintDocument(doc, page, title = "Document") {
244
+ const body = documentToHtml(doc);
245
+ return `<!DOCTYPE html>
246
+ <html lang="en">
247
+ <head>
248
+ <meta charset="utf-8">
249
+ <meta name="viewport" content="width=device-width, initial-scale=1">
250
+ <title>${escapeHtml(title)}</title>
251
+ <style>${printStylesheet(page)}</style>
252
+ </head>
253
+ <body>
254
+ <div class="rne-print-page">
255
+ ${body}
256
+ </div>
257
+ </body>
258
+ </html>`;
259
+ }
260
+
261
+ exports.buildPrintDocument = buildPrintDocument;
262
+ exports.documentToHtml = documentToHtml;
263
+ exports.printStylesheet = printStylesheet;
264
+ //# sourceMappingURL=chunk-TI44I654.cjs.map
265
+ //# sourceMappingURL=chunk-TI44I654.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/export/html.ts"],"names":["sanitizeUrl","cssFontFamily","cssNumber","normalizeCssColor","sanitizeImageSrc","cssInteger","cssAlign","resolvePageDimensions"],"mappings":"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","file":"chunk-TI44I654.cjs","sourcesContent":["import type { DocumentJSON, PageConfig } from '../config/types';\nimport { sanitizeImageSrc, sanitizeUrl } from '../security/sanitize';\nimport { cssAlign, cssFontFamily, cssInteger, cssNumber, normalizeCssColor } from '../security/css';\nimport { resolvePageDimensions } from '../config/defaults';\n\n/** Escape text for safe inclusion in HTML element content. */\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\n/** Escape a value for inclusion in a double-quoted HTML attribute. */\nfunction escapeAttr(value: string): string {\n return escapeHtml(value).replace(/\"/g, '&quot;');\n}\n\n/** Order in which inline marks are nested (outermost first). */\nconst MARK_ORDER = [\n 'link',\n 'textColor',\n 'highlight',\n 'fontFamily',\n 'fontSize',\n 'strong',\n 'em',\n 'underline',\n 'strikethrough',\n 'superscript',\n 'subscript',\n 'code',\n];\n\ninterface MarkJSON {\n type: string;\n attrs?: Record<string, unknown>;\n}\n\nfunction openMark(mark: MarkJSON): string {\n const attrs = mark.attrs ?? {};\n switch (mark.type) {\n case 'strong':\n return '<strong>';\n case 'em':\n return '<em>';\n case 'underline':\n return '<u>';\n case 'strikethrough':\n return '<s>';\n case 'superscript':\n return '<sup>';\n case 'subscript':\n return '<sub>';\n case 'code':\n return '<code>';\n case 'link': {\n const href = sanitizeUrl(String(attrs.href ?? '')) ?? '';\n const title = attrs.title ? ` title=\"${escapeAttr(String(attrs.title))}\"` : '';\n return `<a href=\"${escapeAttr(href)}\"${title} rel=\"noopener noreferrer nofollow\">`;\n }\n case 'fontFamily': {\n const family = cssFontFamily(attrs.family);\n return family ? `<span style=\"font-family: ${family}\">` : '<span>';\n }\n case 'fontSize': {\n const size = cssNumber(attrs.size, 1, 1638);\n return size ? `<span style=\"font-size: ${size}pt\">` : '<span>';\n }\n case 'textColor': {\n const color = normalizeCssColor(attrs.color);\n return color ? `<span style=\"color: ${color}\">` : '<span>';\n }\n case 'highlight': {\n const color = normalizeCssColor(attrs.color) ?? '#fff2a8';\n return `<mark style=\"background-color: ${color}\">`;\n }\n default:\n return '';\n }\n}\n\nfunction closeMark(mark: MarkJSON): string {\n switch (mark.type) {\n case 'strong':\n return '</strong>';\n case 'em':\n return '</em>';\n case 'underline':\n return '</u>';\n case 'strikethrough':\n return '</s>';\n case 'superscript':\n return '</sup>';\n case 'subscript':\n return '</sub>';\n case 'code':\n return '</code>';\n case 'link':\n return '</a>';\n case 'fontFamily':\n case 'fontSize':\n case 'textColor':\n return '</span>';\n case 'highlight':\n return '</mark>';\n default:\n return '';\n }\n}\n\nfunction sortMarks(marks: MarkJSON[]): MarkJSON[] {\n return [...marks].sort((a, b) => {\n const ia = MARK_ORDER.indexOf(a.type);\n const ib = MARK_ORDER.indexOf(b.type);\n return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib);\n });\n}\n\nfunction serializeInline(content: DocumentJSON[] | undefined): string {\n if (!content) return '';\n let out = '';\n for (const node of content) {\n if (node.type === 'text') {\n const marks = sortMarks((node.marks ?? []) as MarkJSON[]);\n let text = escapeHtml(node.text ?? '');\n for (let i = marks.length - 1; i >= 0; i--) text = openMark(marks[i]!) + text;\n for (const mark of marks) text += closeMark(mark);\n out += text;\n } else if (node.type === 'hard_break') {\n out += '<br>';\n } else if (node.type === 'image') {\n out += serializeImage(node);\n }\n }\n return out;\n}\n\nfunction serializeImage(node: DocumentJSON): string {\n const src = sanitizeImageSrc(String(node.attrs?.src ?? ''));\n if (!src) return '';\n const alt = node.attrs?.alt ? ` alt=\"${escapeAttr(String(node.attrs.alt))}\"` : ' alt=\"\"';\n const title = node.attrs?.title ? ` title=\"${escapeAttr(String(node.attrs.title))}\"` : '';\n const safeWidth = cssInteger(node.attrs?.width, 1, 4000);\n const width = safeWidth ? ` style=\"width: ${safeWidth}px\"` : '';\n return `<img class=\"rne-image\" src=\"${escapeAttr(src)}\"${alt}${title}${width}>`;\n}\n\nfunction blockStyle(attrs: Record<string, unknown> | undefined): string {\n if (!attrs) return '';\n const styles: string[] = [];\n const align = cssAlign(attrs.align);\n if (align) styles.push(`text-align: ${align}`);\n const indent = cssInteger(attrs.indent, 0, 12);\n if (indent && indent > 0) styles.push(`margin-left: ${indent * 3}em`);\n const lineHeight = cssNumber(attrs.lineHeight, 0.1, 10);\n if (lineHeight) styles.push(`line-height: ${lineHeight}`);\n return styles.length ? ` style=\"${styles.join('; ')}\"` : '';\n}\n\nfunction serializeBlock(node: DocumentJSON): string {\n switch (node.type) {\n case 'paragraph':\n return `<p${blockStyle(node.attrs)}>${serializeInline(node.content) || '<br>'}</p>`;\n case 'heading': {\n const level = Math.min(6, Math.max(1, Number(node.attrs?.level ?? 1)));\n return `<h${level}${blockStyle(node.attrs)}>${serializeInline(node.content)}</h${level}>`;\n }\n case 'blockquote':\n return `<blockquote class=\"rne-blockquote\">${(node.content ?? []).map(serializeBlock).join('')}</blockquote>`;\n case 'horizontal_rule':\n return '<hr class=\"rne-hr\">';\n case 'page_break':\n return '<div class=\"rne-page-break\"></div>';\n case 'bullet_list':\n case 'ordered_list':\n return serializeList(node);\n case 'table':\n return serializeTable(node);\n default:\n if (node.content) return node.content.map(serializeBlock).join('');\n return '';\n }\n}\n\nfunction serializeList(node: DocumentJSON): string {\n const ordered = node.type === 'ordered_list';\n const kind = node.attrs?.kind;\n const tag = ordered ? 'ol' : 'ul';\n const order = ordered ? Number(node.attrs?.order ?? 1) : 1;\n const startAttr = ordered && order !== 1 ? ` start=\"${order}\"` : '';\n const classAttr = ordered\n ? ' class=\"rne-ordered-list\"'\n : kind === 'task'\n ? ' class=\"rne-task-list\" data-type=\"task\"'\n : ' class=\"rne-bullet-list\"';\n\n const items = (node.content ?? [])\n .map((item) => {\n if (item.type !== 'list_item') return '';\n const checked = item.attrs?.checked;\n const inner = (item.content ?? []).map(serializeBlock).join('');\n if (checked === true || checked === false) {\n const box = checked ? '☑' : '☐';\n return `<li class=\"rne-task-item\" data-checked=\"${checked}\"><span class=\"rne-task-checkbox\">${box}</span><div class=\"rne-task-content\">${inner}</div></li>`;\n }\n return `<li>${inner}</li>`;\n })\n .join('');\n return `<${tag}${classAttr}${startAttr}>${items}</${tag}>`;\n}\n\nfunction serializeTable(node: DocumentJSON): string {\n const rows = (node.content ?? [])\n .map((row) => {\n if (row.type !== 'table_row') return '';\n const cells = (row.content ?? [])\n .map((cell) => {\n const tag = cell.type === 'table_header' ? 'th' : 'td';\n const attrs = cell.attrs ?? {};\n const parts: string[] = [];\n const colspan = cssInteger(attrs.colspan, 1, 100);\n if (colspan && colspan > 1) parts.push(`colspan=\"${colspan}\"`);\n const rowspan = cssInteger(attrs.rowspan, 1, 100);\n if (rowspan && rowspan > 1) parts.push(`rowspan=\"${rowspan}\"`);\n const styles: string[] = [];\n const bg = normalizeCssColor(attrs.background);\n if (bg) styles.push(`background-color: ${bg}`);\n const cellAlign = cssAlign(attrs.align);\n if (cellAlign) styles.push(`text-align: ${cellAlign}`);\n if (styles.length) parts.push(`style=\"${styles.join('; ')}\"`);\n const attrStr = parts.length ? ` ${parts.join(' ')}` : '';\n return `<${tag}${attrStr}>${(cell.content ?? []).map(serializeBlock).join('')}</${tag}>`;\n })\n .join('');\n return `<tr>${cells}</tr>`;\n })\n .join('');\n return `<table class=\"rne-table\"><tbody>${rows}</tbody></table>`;\n}\n\n/** Serialize a document (JSON) to an HTML fragment (the document body content). */\nexport function documentToHtml(doc: DocumentJSON): string {\n return (doc.content ?? []).map(serializeBlock).join('\\n');\n}\n\n/** Print-oriented stylesheet matching the on-screen document surface. */\nexport function printStylesheet(page: PageConfig): string {\n const { width, height } = resolvePageDimensions(page);\n const { top, right, bottom, left } = page.margins;\n return `\n @page { size: ${width}mm ${height}mm; margin: ${top}mm ${right}mm ${bottom}mm ${left}mm; }\n * { box-sizing: border-box; }\n html, body { margin: 0; padding: 0; }\n body {\n font-family: 'Times New Roman', Georgia, serif;\n font-size: 12pt;\n line-height: 1.5;\n color: #111;\n }\n .rne-print-page { width: ${width - left - right}mm; margin: 0 auto; }\n h1 { font-size: 2em; } h2 { font-size: 1.5em; } h3 { font-size: 1.25em; }\n h4 { font-size: 1.1em; } h5 { font-size: 1em; } h6 { font-size: 0.9em; }\n p { margin: 0 0 0.6em; }\n blockquote.rne-blockquote { border-left: 3px solid #ccc; margin: 0 0 0.6em; padding-left: 1em; color: #444; }\n hr.rne-hr { border: none; border-top: 1px solid #ccc; margin: 1em 0; }\n img.rne-image { max-width: 100%; height: auto; }\n table.rne-table { border-collapse: collapse; width: 100%; margin: 0 0 0.8em; }\n table.rne-table td, table.rne-table th { border: 1px solid #999; padding: 4px 8px; vertical-align: top; }\n table.rne-table th { background: #f0f0f0; font-weight: bold; }\n ul, ol { margin: 0 0 0.6em; padding-left: 1.6em; }\n ul.rne-task-list { list-style: none; padding-left: 0.4em; }\n .rne-task-item { display: flex; gap: 0.4em; align-items: flex-start; }\n .rne-page-break { break-after: page; page-break-after: always; height: 0; }\n code { font-family: 'Courier New', monospace; background: #f3f3f3; padding: 0 2px; }\n `.trim();\n}\n\n/**\n * Build a complete, standalone HTML document for PDF rendering — used by both\n * the client print path and the server headless-browser renderer so output is\n * consistent (F-6.4, F-6.11).\n */\nexport function buildPrintDocument(\n doc: DocumentJSON,\n page: PageConfig,\n title = 'Document',\n): string {\n const body = documentToHtml(doc);\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>${escapeHtml(title)}</title>\n<style>${printStylesheet(page)}</style>\n</head>\n<body>\n<div class=\"rne-print-page\">\n${body}\n</div>\n</body>\n</html>`;\n}\n"]}
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ // src/security/css.ts
4
+ var ALIGN_VALUES = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
5
+ function cssAlign(value) {
6
+ return typeof value === "string" && ALIGN_VALUES.has(value) ? value : null;
7
+ }
8
+ function cssNumber(value, min, max) {
9
+ let n;
10
+ if (typeof value === "number") {
11
+ n = value;
12
+ } else if (typeof value === "string") {
13
+ const trimmed = value.trim();
14
+ if (!/^-?\d+(\.\d+)?$/.test(trimmed)) return null;
15
+ n = parseFloat(trimmed);
16
+ } else {
17
+ return null;
18
+ }
19
+ if (!Number.isFinite(n)) return null;
20
+ return Math.min(max, Math.max(min, n));
21
+ }
22
+ function cssInteger(value, min, max) {
23
+ const n = cssNumber(value, min, max);
24
+ return n === null ? null : Math.round(n);
25
+ }
26
+ function normalizeCssColor(value) {
27
+ if (typeof value !== "string") return null;
28
+ const v = value.trim().toLowerCase();
29
+ if (/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v;
30
+ if (/^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)$/.test(v)) return v;
31
+ if (/^rgba\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*(0|1|0?\.\d+)\s*\)$/.test(v)) return v;
32
+ if (/^[a-z]{3,20}$/.test(v)) return v;
33
+ return null;
34
+ }
35
+ function cssFontFamily(value) {
36
+ if (value == null) return null;
37
+ const cleaned = String(value).replace(/[^a-zA-Z0-9 ,_-]/g, "").replace(/\s+/g, " ").trim();
38
+ return cleaned ? cleaned : null;
39
+ }
40
+
41
+ exports.cssAlign = cssAlign;
42
+ exports.cssFontFamily = cssFontFamily;
43
+ exports.cssInteger = cssInteger;
44
+ exports.cssNumber = cssNumber;
45
+ exports.normalizeCssColor = normalizeCssColor;
46
+ //# sourceMappingURL=chunk-TXPLBAH5.cjs.map
47
+ //# sourceMappingURL=chunk-TXPLBAH5.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/security/css.ts"],"names":[],"mappings":";;;AAWA,IAAM,YAAA,uBAAmB,GAAA,CAAI,CAAC,QAAQ,QAAA,EAAU,OAAA,EAAS,SAAS,CAAC,CAAA;AAG5D,SAAS,SAAS,KAAA,EAAgE;AACvF,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,aAAa,GAAA,CAAI,KAAK,IACrD,KAAA,GACD,IAAA;AACN;AAQO,SAAS,SAAA,CAAU,KAAA,EAAgB,GAAA,EAAa,GAAA,EAA4B;AACjF,EAAA,IAAI,CAAA;AACJ,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,CAAA,GAAI,KAAA;AAAA,EACN,CAAA,MAAA,IAAW,OAAO,KAAA,KAAU,QAAA,EAAU;AAGpC,IAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAA,CAAK,OAAO,GAAG,OAAO,IAAA;AAC7C,IAAA,CAAA,GAAI,WAAW,OAAO,CAAA;AAAA,EACxB,CAAA,MAAO;AACL,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,GAAG,OAAO,IAAA;AAChC,EAAA,OAAO,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,CAAC,CAAC,CAAA;AACvC;AAGO,SAAS,UAAA,CAAW,KAAA,EAAgB,GAAA,EAAa,GAAA,EAA4B;AAClF,EAAA,MAAM,CAAA,GAAI,SAAA,CAAU,KAAA,EAAO,GAAA,EAAK,GAAG,CAAA;AACnC,EAAA,OAAO,CAAA,KAAM,IAAA,GAAO,IAAA,GAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AACzC;AAMO,SAAS,kBAAkB,KAAA,EAA+B;AAC/D,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,EAAU,OAAO,IAAA;AACtC,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,IAAA,EAAK,CAAE,WAAA,EAAY;AACnC,EAAA,IAAI,sDAAA,CAAuD,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AAC3E,EAAA,IAAI,oDAAA,CAAqD,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AACzE,EAAA,IAAI,yEAAA,CAA0E,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AAC9F,EAAA,IAAI,eAAA,CAAgB,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA;AACpC,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,cAAc,KAAA,EAA+B;AAC3D,EAAA,IAAI,KAAA,IAAS,MAAM,OAAO,IAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAA,CACzB,OAAA,CAAQ,mBAAA,EAAqB,EAAE,CAAA,CAC/B,OAAA,CAAQ,MAAA,EAAQ,GAAG,CAAA,CACnB,IAAA,EAAK;AACR,EAAA,OAAO,UAAU,OAAA,GAAU,IAAA;AAC7B","file":"chunk-TXPLBAH5.cjs","sourcesContent":["/**\n * CSS value sanitization (§5.12). These DOM-free helpers are the single guard\n * for every attribute value that is interpolated into an inline `style` string\n * by a node/mark `toDOM`. They neutralize CSS injection from attacker-controlled\n * document JSON (e.g. a shared/loaded document) — values like\n * `\"left;background:url(//evil)\"` can never break out of their declaration or\n * introduce `url(...)` fetches.\n *\n * Pure and isomorphic: safe to import in the schema (browser and Node).\n */\n\nconst ALIGN_VALUES = new Set(['left', 'center', 'right', 'justify']);\n\n/** Validate a text-alignment keyword, or null. */\nexport function cssAlign(value: unknown): 'left' | 'center' | 'right' | 'justify' | null {\n return typeof value === 'string' && ALIGN_VALUES.has(value)\n ? (value as 'left' | 'center' | 'right' | 'justify')\n : null;\n}\n\n/**\n * Coerce a value to a finite number clamped to [min, max], or null if it is not\n * numeric. Accepts numbers or numeric strings (with an optional leading number),\n * so a malicious `\"0;background:url(x)\"` parses to `0` (or null) — never a\n * style breakout.\n */\nexport function cssNumber(value: unknown, min: number, max: number): number | null {\n let n: number;\n if (typeof value === 'number') {\n n = value;\n } else if (typeof value === 'string') {\n // Only accept a clean numeric token; reject anything with extra characters\n // (so \"5;x\" or \"1px;background:...\" is rejected rather than coerced to 5).\n const trimmed = value.trim();\n if (!/^-?\\d+(\\.\\d+)?$/.test(trimmed)) return null;\n n = parseFloat(trimmed);\n } else {\n return null;\n }\n if (!Number.isFinite(n)) return null;\n return Math.min(max, Math.max(min, n));\n}\n\n/** Coerce a value to a clamped, rounded integer, or null. */\nexport function cssInteger(value: unknown, min: number, max: number): number | null {\n const n = cssNumber(value, min, max);\n return n === null ? null : Math.round(n);\n}\n\n/**\n * Validate and normalize a CSS color (hex / rgb / rgba / named), rejecting\n * anything that could carry an injection (e.g. `url(...)`, `expression(...)`).\n */\nexport function normalizeCssColor(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const v = value.trim().toLowerCase();\n if (/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(v)) return v;\n if (/^rgb\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*\\)$/.test(v)) return v;\n if (/^rgba\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*(0|1|0?\\.\\d+)\\s*\\)$/.test(v)) return v;\n if (/^[a-z]{3,20}$/.test(v)) return v; // named colors\n return null;\n}\n\n/**\n * Sanitize a font-family value to a safe character set (letters, digits, space,\n * comma, hyphen, underscore). Strips quotes, semicolons, parentheses, etc., so\n * `url(...)`/declaration breakouts are impossible. Returns null if empty.\n */\nexport function cssFontFamily(value: unknown): string | null {\n if (value == null) return null;\n const cleaned = String(value)\n .replace(/[^a-zA-Z0-9 ,_-]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n return cleaned ? cleaned : null;\n}\n"]}
@@ -0,0 +1,187 @@
1
+ 'use strict';
2
+
3
+ // src/config/defaults.ts
4
+ var DEFAULT_FEATURES = {
5
+ bold: true,
6
+ italic: true,
7
+ underline: true,
8
+ strikethrough: true,
9
+ superscript: true,
10
+ subscript: true,
11
+ code: true,
12
+ fontFamily: true,
13
+ fontSize: true,
14
+ textColor: true,
15
+ highlight: true,
16
+ clearFormatting: true,
17
+ headings: true,
18
+ alignment: true,
19
+ lineSpacing: true,
20
+ indentation: true,
21
+ bulletList: true,
22
+ orderedList: true,
23
+ taskList: true,
24
+ blockquote: true,
25
+ horizontalRule: true,
26
+ table: true,
27
+ image: true,
28
+ link: true,
29
+ pageBreak: true,
30
+ history: true,
31
+ wordCount: true,
32
+ docxImport: true
33
+ };
34
+ var PAGE_DIMENSIONS_MM = {
35
+ A4: { width: 210, height: 297 },
36
+ Letter: { width: 215.9, height: 279.4 },
37
+ Legal: { width: 215.9, height: 355.6 },
38
+ A5: { width: 148, height: 210 }
39
+ };
40
+ var DEFAULT_PAGE = {
41
+ size: "A4",
42
+ orientation: "portrait",
43
+ margins: { top: 25.4, right: 25.4, bottom: 25.4, left: 25.4 },
44
+ showPageChrome: true
45
+ };
46
+ function resolvePageDimensions(page) {
47
+ let width;
48
+ let height;
49
+ if (page.size === "custom") {
50
+ width = page.widthMm ?? PAGE_DIMENSIONS_MM.A4.width;
51
+ height = page.heightMm ?? PAGE_DIMENSIONS_MM.A4.height;
52
+ } else {
53
+ ({ width, height } = PAGE_DIMENSIONS_MM[page.size]);
54
+ }
55
+ if (page.orientation === "landscape") {
56
+ return { width: height, height: width };
57
+ }
58
+ return { width, height };
59
+ }
60
+ var DEFAULT_STRINGS = {
61
+ bold: "Bold",
62
+ italic: "Italic",
63
+ underline: "Underline",
64
+ strikethrough: "Strikethrough",
65
+ superscript: "Superscript",
66
+ subscript: "Subscript",
67
+ code: "Inline code",
68
+ textColor: "Text color",
69
+ highlight: "Highlight",
70
+ clearFormatting: "Clear formatting",
71
+ fontFamily: "Font",
72
+ fontSize: "Font size",
73
+ paragraphStyle: "Style",
74
+ paragraph: "Normal text",
75
+ heading: "Heading",
76
+ alignLeft: "Align left",
77
+ alignCenter: "Align center",
78
+ alignRight: "Align right",
79
+ alignJustify: "Justify",
80
+ bulletList: "Bulleted list",
81
+ orderedList: "Numbered list",
82
+ taskList: "Task list",
83
+ indent: "Increase indent",
84
+ outdent: "Decrease indent",
85
+ blockquote: "Blockquote",
86
+ horizontalRule: "Horizontal rule",
87
+ link: "Link",
88
+ linkPrompt: "Enter URL",
89
+ removeLink: "Remove link",
90
+ image: "Image",
91
+ imagePrompt: "Enter image URL",
92
+ imageAltPrompt: "Describe the image (alt text)",
93
+ table: "Table",
94
+ insertTable: "Insert table",
95
+ addRowBefore: "Insert row above",
96
+ addRowAfter: "Insert row below",
97
+ deleteRow: "Delete row",
98
+ addColumnBefore: "Insert column left",
99
+ addColumnAfter: "Insert column right",
100
+ deleteColumn: "Delete column",
101
+ mergeCells: "Merge cells",
102
+ splitCell: "Split cell",
103
+ deleteTable: "Delete table",
104
+ pageBreak: "Page break",
105
+ importDocx: "Import .docx",
106
+ undo: "Undo",
107
+ redo: "Redo",
108
+ words: "words",
109
+ characters: "characters",
110
+ readOnly: "Read only"
111
+ };
112
+ var DEFAULT_FONT_FAMILIES = [
113
+ "Arial",
114
+ "Calibri",
115
+ "Cambria",
116
+ "Georgia",
117
+ "Helvetica",
118
+ "Times New Roman",
119
+ "Trebuchet MS",
120
+ "Verdana",
121
+ "Courier New"
122
+ ];
123
+ var DEFAULT_FONT_SIZES = [8, 9, 10, 11, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72];
124
+ var DEFAULT_COLOR_PALETTE = [
125
+ "#000000",
126
+ "#434343",
127
+ "#666666",
128
+ "#999999",
129
+ "#b7b7b7",
130
+ "#cccccc",
131
+ "#ffffff",
132
+ "#df4a36",
133
+ "#e69138",
134
+ "#f1c232",
135
+ "#6aa84f",
136
+ "#45818e",
137
+ "#3d85c6",
138
+ "#674ea7",
139
+ "#a64d79"
140
+ ];
141
+ var DEFAULT_TOOLBAR_GROUPS = [
142
+ ["undo", "redo"],
143
+ ["paragraphStyle", "fontFamily", "fontSize"],
144
+ ["bold", "italic", "underline", "strikethrough", "superscript", "subscript", "code"],
145
+ ["textColor", "highlight", "clearFormatting"],
146
+ ["alignLeft", "alignCenter", "alignRight", "alignJustify"],
147
+ ["bulletList", "orderedList", "taskList", "indent", "outdent"],
148
+ ["blockquote", "horizontalRule", "link", "image", "table", "pageBreak"],
149
+ ["importDocx"]
150
+ ];
151
+ function themeToCssVars(theme) {
152
+ if (!theme) return {};
153
+ const map = [
154
+ ["fontFamily", "--rne-font-family"],
155
+ ["fontSize", "--rne-font-size"],
156
+ ["textColor", "--rne-text-color"],
157
+ ["background", "--rne-background"],
158
+ ["canvasBackground", "--rne-canvas-background"],
159
+ ["pageBackground", "--rne-page-background"],
160
+ ["accent", "--rne-accent"],
161
+ ["toolbarBackground", "--rne-toolbar-background"],
162
+ ["toolbarColor", "--rne-toolbar-color"],
163
+ ["toolbarActiveBackground", "--rne-toolbar-active-background"],
164
+ ["borderColor", "--rne-border-color"],
165
+ ["borderRadius", "--rne-border-radius"],
166
+ ["selectionColor", "--rne-selection-color"]
167
+ ];
168
+ const out = {};
169
+ for (const [key, cssVar] of map) {
170
+ const value = theme[key];
171
+ if (value != null) out[cssVar] = value;
172
+ }
173
+ return out;
174
+ }
175
+
176
+ exports.DEFAULT_COLOR_PALETTE = DEFAULT_COLOR_PALETTE;
177
+ exports.DEFAULT_FEATURES = DEFAULT_FEATURES;
178
+ exports.DEFAULT_FONT_FAMILIES = DEFAULT_FONT_FAMILIES;
179
+ exports.DEFAULT_FONT_SIZES = DEFAULT_FONT_SIZES;
180
+ exports.DEFAULT_PAGE = DEFAULT_PAGE;
181
+ exports.DEFAULT_STRINGS = DEFAULT_STRINGS;
182
+ exports.DEFAULT_TOOLBAR_GROUPS = DEFAULT_TOOLBAR_GROUPS;
183
+ exports.PAGE_DIMENSIONS_MM = PAGE_DIMENSIONS_MM;
184
+ exports.resolvePageDimensions = resolvePageDimensions;
185
+ exports.themeToCssVars = themeToCssVars;
186
+ //# sourceMappingURL=chunk-U3O54IYI.cjs.map
187
+ //# sourceMappingURL=chunk-U3O54IYI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/defaults.ts"],"names":[],"mappings":"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","file":"chunk-U3O54IYI.cjs","sourcesContent":["import type {\n EditorStrings,\n FeatureFlags,\n PageConfig,\n PageSize,\n ThemeTokens,\n ToolbarItemId,\n} from './types';\n\n/** All features enabled by default; integrations opt out per instance. */\nexport const DEFAULT_FEATURES: FeatureFlags = {\n bold: true,\n italic: true,\n underline: true,\n strikethrough: true,\n superscript: true,\n subscript: true,\n code: true,\n fontFamily: true,\n fontSize: true,\n textColor: true,\n highlight: true,\n clearFormatting: true,\n headings: true,\n alignment: true,\n lineSpacing: true,\n indentation: true,\n bulletList: true,\n orderedList: true,\n taskList: true,\n blockquote: true,\n horizontalRule: true,\n table: true,\n image: true,\n link: true,\n pageBreak: true,\n history: true,\n wordCount: true,\n docxImport: true,\n};\n\n/** Physical page dimensions in millimetres for the supported standard sizes. */\nexport const PAGE_DIMENSIONS_MM: Record<Exclude<PageSize, 'custom'>, { width: number; height: number }> =\n {\n A4: { width: 210, height: 297 },\n Letter: { width: 215.9, height: 279.4 },\n Legal: { width: 215.9, height: 355.6 },\n A5: { width: 148, height: 210 },\n };\n\nexport const DEFAULT_PAGE: PageConfig = {\n size: 'A4',\n orientation: 'portrait',\n margins: { top: 25.4, right: 25.4, bottom: 25.4, left: 25.4 },\n showPageChrome: true,\n};\n\n/** Resolve a {@link PageConfig} to concrete content-box dimensions in millimetres. */\nexport function resolvePageDimensions(page: PageConfig): { width: number; height: number } {\n let width: number;\n let height: number;\n if (page.size === 'custom') {\n width = page.widthMm ?? PAGE_DIMENSIONS_MM.A4.width;\n height = page.heightMm ?? PAGE_DIMENSIONS_MM.A4.height;\n } else {\n ({ width, height } = PAGE_DIMENSIONS_MM[page.size]);\n }\n if (page.orientation === 'landscape') {\n return { width: height, height: width };\n }\n return { width, height };\n}\n\n/** Default English UI strings (NF-6: externalized for localization). */\nexport const DEFAULT_STRINGS: EditorStrings = {\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n strikethrough: 'Strikethrough',\n superscript: 'Superscript',\n subscript: 'Subscript',\n code: 'Inline code',\n textColor: 'Text color',\n highlight: 'Highlight',\n clearFormatting: 'Clear formatting',\n fontFamily: 'Font',\n fontSize: 'Font size',\n paragraphStyle: 'Style',\n paragraph: 'Normal text',\n heading: 'Heading',\n alignLeft: 'Align left',\n alignCenter: 'Align center',\n alignRight: 'Align right',\n alignJustify: 'Justify',\n bulletList: 'Bulleted list',\n orderedList: 'Numbered list',\n taskList: 'Task list',\n indent: 'Increase indent',\n outdent: 'Decrease indent',\n blockquote: 'Blockquote',\n horizontalRule: 'Horizontal rule',\n link: 'Link',\n linkPrompt: 'Enter URL',\n removeLink: 'Remove link',\n image: 'Image',\n imagePrompt: 'Enter image URL',\n imageAltPrompt: 'Describe the image (alt text)',\n table: 'Table',\n insertTable: 'Insert table',\n addRowBefore: 'Insert row above',\n addRowAfter: 'Insert row below',\n deleteRow: 'Delete row',\n addColumnBefore: 'Insert column left',\n addColumnAfter: 'Insert column right',\n deleteColumn: 'Delete column',\n mergeCells: 'Merge cells',\n splitCell: 'Split cell',\n deleteTable: 'Delete table',\n pageBreak: 'Page break',\n importDocx: 'Import .docx',\n undo: 'Undo',\n redo: 'Redo',\n words: 'words',\n characters: 'characters',\n readOnly: 'Read only',\n};\n\n/** Font families offered by the font picker. Consumers can override via config. */\nexport const DEFAULT_FONT_FAMILIES: string[] = [\n 'Arial',\n 'Calibri',\n 'Cambria',\n 'Georgia',\n 'Helvetica',\n 'Times New Roman',\n 'Trebuchet MS',\n 'Verdana',\n 'Courier New',\n];\n\n/** Font sizes (pt) offered by the size picker. */\nexport const DEFAULT_FONT_SIZES: number[] = [8, 9, 10, 11, 12, 14, 16, 18, 24, 30, 36, 48, 60, 72];\n\n/** A palette of colors offered by the color/highlight pickers. */\nexport const DEFAULT_COLOR_PALETTE: string[] = [\n '#000000',\n '#434343',\n '#666666',\n '#999999',\n '#b7b7b7',\n '#cccccc',\n '#ffffff',\n '#df4a36',\n '#e69138',\n '#f1c232',\n '#6aa84f',\n '#45818e',\n '#3d85c6',\n '#674ea7',\n '#a64d79',\n];\n\n/** Default toolbar layout, grouped. Filtered by enabled features at render time. */\nexport const DEFAULT_TOOLBAR_GROUPS: ToolbarItemId[][] = [\n ['undo', 'redo'],\n ['paragraphStyle', 'fontFamily', 'fontSize'],\n ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'code'],\n ['textColor', 'highlight', 'clearFormatting'],\n ['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],\n ['bulletList', 'orderedList', 'taskList', 'indent', 'outdent'],\n ['blockquote', 'horizontalRule', 'link', 'image', 'table', 'pageBreak'],\n ['importDocx'],\n];\n\n/** Map a {@link ThemeTokens} object to a CSS custom-property style record. */\nexport function themeToCssVars(theme: ThemeTokens | undefined): Record<string, string> {\n if (!theme) return {};\n const map: Array<[keyof ThemeTokens, string]> = [\n ['fontFamily', '--rne-font-family'],\n ['fontSize', '--rne-font-size'],\n ['textColor', '--rne-text-color'],\n ['background', '--rne-background'],\n ['canvasBackground', '--rne-canvas-background'],\n ['pageBackground', '--rne-page-background'],\n ['accent', '--rne-accent'],\n ['toolbarBackground', '--rne-toolbar-background'],\n ['toolbarColor', '--rne-toolbar-color'],\n ['toolbarActiveBackground', '--rne-toolbar-active-background'],\n ['borderColor', '--rne-border-color'],\n ['borderRadius', '--rne-border-radius'],\n ['selectionColor', '--rne-selection-color'],\n ];\n const out: Record<string, string> = {};\n for (const [key, cssVar] of map) {\n const value = theme[key];\n if (value != null) out[cssVar] = value;\n }\n return out;\n}\n"]}