@scrider/formatter 1.10.5 → 1.10.7
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.cjs +74 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +74 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -32,8 +32,8 @@ interface TablePresentation {
|
|
|
32
32
|
}
|
|
33
33
|
/** Default table border (HTML / clipboard / PDF host should share). */
|
|
34
34
|
declare const TABLE_BORDER_COLOR = "#e7e7e7";
|
|
35
|
-
/** Header shade fill — matches editor light `--color-bg-hover`
|
|
36
|
-
declare const TABLE_HEADER_BG = "#
|
|
35
|
+
/** Header shade fill — matches editor light `--color-bg-hover` (`#e9ecef`). */
|
|
36
|
+
declare const TABLE_HEADER_BG = "#e9ecef";
|
|
37
37
|
/**
|
|
38
38
|
* Zebra body-row fill — canon aligned with editor/demo light
|
|
39
39
|
* `--color-table-zebra` (`#f6f8fa`, arch-set1 #12).
|
|
@@ -50,8 +50,12 @@ interface ResolvedTablePresentation {
|
|
|
50
50
|
defaultCellAlign: TableCellAlign;
|
|
51
51
|
}
|
|
52
52
|
declare function resolveTablePresentation(presentation?: TablePresentation): ResolvedTablePresentation;
|
|
53
|
-
/**
|
|
54
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Match editor/CSS zebra on `tbody tr:nth-child(even) td`.
|
|
55
|
+
* First body row stays light; 2nd, 4th, … get {@link TABLE_ZEBRA_BG}.
|
|
56
|
+
* `headerRowCount` is unused (thead/tbody split) — kept for call-site stability.
|
|
57
|
+
*/
|
|
58
|
+
declare function isZebraBodyRow(_headerRowCount: number, bodyRowIndex: number): boolean;
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
61
|
* Document-level metadata (Scrider format extension).
|
package/dist/index.d.ts
CHANGED
|
@@ -32,8 +32,8 @@ interface TablePresentation {
|
|
|
32
32
|
}
|
|
33
33
|
/** Default table border (HTML / clipboard / PDF host should share). */
|
|
34
34
|
declare const TABLE_BORDER_COLOR = "#e7e7e7";
|
|
35
|
-
/** Header shade fill — matches editor light `--color-bg-hover`
|
|
36
|
-
declare const TABLE_HEADER_BG = "#
|
|
35
|
+
/** Header shade fill — matches editor light `--color-bg-hover` (`#e9ecef`). */
|
|
36
|
+
declare const TABLE_HEADER_BG = "#e9ecef";
|
|
37
37
|
/**
|
|
38
38
|
* Zebra body-row fill — canon aligned with editor/demo light
|
|
39
39
|
* `--color-table-zebra` (`#f6f8fa`, arch-set1 #12).
|
|
@@ -50,8 +50,12 @@ interface ResolvedTablePresentation {
|
|
|
50
50
|
defaultCellAlign: TableCellAlign;
|
|
51
51
|
}
|
|
52
52
|
declare function resolveTablePresentation(presentation?: TablePresentation): ResolvedTablePresentation;
|
|
53
|
-
/**
|
|
54
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Match editor/CSS zebra on `tbody tr:nth-child(even) td`.
|
|
55
|
+
* First body row stays light; 2nd, 4th, … get {@link TABLE_ZEBRA_BG}.
|
|
56
|
+
* `headerRowCount` is unused (thead/tbody split) — kept for call-site stability.
|
|
57
|
+
*/
|
|
58
|
+
declare function isZebraBodyRow(_headerRowCount: number, bodyRowIndex: number): boolean;
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
61
|
* Document-level metadata (Scrider format extension).
|
package/dist/index.js
CHANGED
|
@@ -2597,6 +2597,10 @@ var imageFormat = {
|
|
|
2597
2597
|
if (element.tagName.toLowerCase() !== "img") return null;
|
|
2598
2598
|
const src = element.getAttribute("src");
|
|
2599
2599
|
if (!src) return null;
|
|
2600
|
+
const style = element.getAttribute("style") || "";
|
|
2601
|
+
if (/(?:^|;)\s*opacity\s*:\s*0(?:\.0+)?\s*(?:;|$)/i.test(style)) {
|
|
2602
|
+
return null;
|
|
2603
|
+
}
|
|
2600
2604
|
const attrs = {};
|
|
2601
2605
|
const alt = element.getAttribute("alt");
|
|
2602
2606
|
const width = element.getAttribute("width");
|
|
@@ -3214,7 +3218,7 @@ function headingPolicyStyleParts(tag, blockAttributes, policy) {
|
|
|
3214
3218
|
|
|
3215
3219
|
// src/conversion/html/table-presentation.ts
|
|
3216
3220
|
var TABLE_BORDER_COLOR = "#e7e7e7";
|
|
3217
|
-
var TABLE_HEADER_BG = "#
|
|
3221
|
+
var TABLE_HEADER_BG = "#e9ecef";
|
|
3218
3222
|
var TABLE_ZEBRA_BG = "#f6f8fa";
|
|
3219
3223
|
var DEFAULT_BORDER_COLOR = TABLE_BORDER_COLOR;
|
|
3220
3224
|
var DEFAULT_HEADER_BG = TABLE_HEADER_BG;
|
|
@@ -3232,8 +3236,8 @@ function resolveTablePresentation(presentation) {
|
|
|
3232
3236
|
defaultCellAlign: presentation?.defaultCellAlign ?? "left"
|
|
3233
3237
|
};
|
|
3234
3238
|
}
|
|
3235
|
-
function isZebraBodyRow(
|
|
3236
|
-
return
|
|
3239
|
+
function isZebraBodyRow(_headerRowCount, bodyRowIndex) {
|
|
3240
|
+
return bodyRowIndex % 2 === 1;
|
|
3237
3241
|
}
|
|
3238
3242
|
function isTableCellAlign(value) {
|
|
3239
3243
|
return value === "left" || value === "center" || value === "right";
|
|
@@ -3870,15 +3874,6 @@ function renderInlineText(text, attributes) {
|
|
|
3870
3874
|
if (!text) return "";
|
|
3871
3875
|
let html = escapeHtml(text);
|
|
3872
3876
|
if (!attributes) return html;
|
|
3873
|
-
const styles = [];
|
|
3874
|
-
for (const [format, cssProperty] of Object.entries(INLINE_STYLE_FORMATS)) {
|
|
3875
|
-
if (format in attributes) {
|
|
3876
|
-
styles.push(`${cssProperty}: ${String(attributes[format])}`);
|
|
3877
|
-
}
|
|
3878
|
-
}
|
|
3879
|
-
if (styles.length > 0) {
|
|
3880
|
-
html = `<span style="${styles.join("; ")}">${html}</span>`;
|
|
3881
|
-
}
|
|
3882
3877
|
for (let i = INLINE_FORMAT_ORDER.length - 1; i >= 0; i--) {
|
|
3883
3878
|
const format = INLINE_FORMAT_ORDER[i];
|
|
3884
3879
|
if (!format) continue;
|
|
@@ -3892,6 +3887,15 @@ function renderInlineText(text, attributes) {
|
|
|
3892
3887
|
html = `<${tag}>${html}</${tag}>`;
|
|
3893
3888
|
}
|
|
3894
3889
|
}
|
|
3890
|
+
const styles = [];
|
|
3891
|
+
for (const [format, cssProperty] of Object.entries(INLINE_STYLE_FORMATS)) {
|
|
3892
|
+
if (format in attributes) {
|
|
3893
|
+
styles.push(`${cssProperty}: ${String(attributes[format])}`);
|
|
3894
|
+
}
|
|
3895
|
+
}
|
|
3896
|
+
if (styles.length > 0) {
|
|
3897
|
+
html = `<span style="${styles.join("; ")}">${html}</span>`;
|
|
3898
|
+
}
|
|
3895
3899
|
return html;
|
|
3896
3900
|
}
|
|
3897
3901
|
function renderEmbed(value, attributes, renderers, blockHandlers, options) {
|
|
@@ -3937,6 +3941,44 @@ function renderEmbed(value, attributes, renderers, blockHandlers, options) {
|
|
|
3937
3941
|
|
|
3938
3942
|
// src/conversion/html/html-to-delta.ts
|
|
3939
3943
|
import { Delta as Delta8 } from "@scrider/delta";
|
|
3944
|
+
function isCssWideKeyword(value) {
|
|
3945
|
+
return /^(inherit|initial|unset|revert|revert-layer)$/i.test(value.trim());
|
|
3946
|
+
}
|
|
3947
|
+
function cleanPastedFontFamily(value) {
|
|
3948
|
+
if (value == null) return null;
|
|
3949
|
+
const trimmed = value.trim();
|
|
3950
|
+
if (!trimmed || isCssWideKeyword(trimmed)) return null;
|
|
3951
|
+
const first = trimmed.split(",").map((part) => part.trim().replace(/^["']|["']$/g, "")).find((part) => part && !isCssWideKeyword(part) && !part.startsWith("var("));
|
|
3952
|
+
if (!first) return null;
|
|
3953
|
+
const lower = first.toLowerCase();
|
|
3954
|
+
if (lower === "serif" || lower === "sans-serif" || lower === "monospace" || lower === "cursive" || lower === "fantasy" || lower === "system-ui") {
|
|
3955
|
+
return null;
|
|
3956
|
+
}
|
|
3957
|
+
return first;
|
|
3958
|
+
}
|
|
3959
|
+
function cleanPastedFontSize(value) {
|
|
3960
|
+
if (value == null) return null;
|
|
3961
|
+
const trimmed = value.trim();
|
|
3962
|
+
if (!trimmed || isCssWideKeyword(trimmed)) return null;
|
|
3963
|
+
if (/^(medium|smaller|larger|xx-small|x-small|small|large|x-large|xx-large)$/i.test(trimmed)) {
|
|
3964
|
+
return null;
|
|
3965
|
+
}
|
|
3966
|
+
const px = trimmed.match(/^([\d.]+)\s*px$/i);
|
|
3967
|
+
if (px?.[1]) {
|
|
3968
|
+
const pt = Math.round(Number(px[1]) * 72 / 96);
|
|
3969
|
+
return pt > 0 ? `${pt}pt` : null;
|
|
3970
|
+
}
|
|
3971
|
+
return trimmed;
|
|
3972
|
+
}
|
|
3973
|
+
function isSelectionBackgroundColor(value) {
|
|
3974
|
+
const m = value.trim().match(/^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/i);
|
|
3975
|
+
if (!m) return false;
|
|
3976
|
+
const r = Number(m[1]);
|
|
3977
|
+
const g = Number(m[2]);
|
|
3978
|
+
const b = Number(m[3]);
|
|
3979
|
+
if (![r, g, b].every((n) => Number.isFinite(n))) return false;
|
|
3980
|
+
return r >= 180 && g >= 180 && b >= 180 && b >= r - 5 && b >= g - 5 && b - Math.min(r, g) <= 40;
|
|
3981
|
+
}
|
|
3940
3982
|
function htmlToDelta(html, options = {}) {
|
|
3941
3983
|
const adapter = options.adapter ?? getAdapter();
|
|
3942
3984
|
const normalizeWhitespace = options.normalizeWhitespace ?? true;
|
|
@@ -4285,20 +4327,30 @@ function htmlToDelta(html, options = {}) {
|
|
|
4285
4327
|
flushText();
|
|
4286
4328
|
const prevAttrs = { ...currentAttributes };
|
|
4287
4329
|
const color = element.style?.color || element.style?.getPropertyValue?.("color");
|
|
4288
|
-
if (color) {
|
|
4330
|
+
if (color && !isCssWideKeyword(color)) {
|
|
4289
4331
|
currentAttributes.color = color;
|
|
4290
4332
|
}
|
|
4291
4333
|
const bg = element.style?.backgroundColor || element.style?.getPropertyValue?.("background-color");
|
|
4292
|
-
if (bg) {
|
|
4334
|
+
if (bg && !isCssWideKeyword(bg) && !isSelectionBackgroundColor(bg)) {
|
|
4293
4335
|
currentAttributes.background = bg;
|
|
4294
4336
|
}
|
|
4295
4337
|
const fontFamily = element.style?.fontFamily || element.style?.getPropertyValue?.("font-family");
|
|
4296
|
-
|
|
4297
|
-
|
|
4338
|
+
const cleanedFont = cleanPastedFontFamily(fontFamily);
|
|
4339
|
+
if (cleanedFont) {
|
|
4340
|
+
currentAttributes.font = cleanedFont;
|
|
4298
4341
|
}
|
|
4299
4342
|
const fontSize = element.style?.fontSize || element.style?.getPropertyValue?.("font-size");
|
|
4300
|
-
|
|
4301
|
-
|
|
4343
|
+
const cleanedSize = cleanPastedFontSize(fontSize);
|
|
4344
|
+
if (cleanedSize) {
|
|
4345
|
+
currentAttributes.size = cleanedSize;
|
|
4346
|
+
}
|
|
4347
|
+
const fontWeight = element.style?.fontWeight || element.style?.getPropertyValue?.("font-weight");
|
|
4348
|
+
if (fontWeight === "bold" || fontWeight === "bolder" || fontWeight != null && Number.parseInt(String(fontWeight), 10) >= 600) {
|
|
4349
|
+
currentAttributes.bold = true;
|
|
4350
|
+
}
|
|
4351
|
+
const fontStyle = element.style?.fontStyle || element.style?.getPropertyValue?.("font-style");
|
|
4352
|
+
if (fontStyle === "italic" || fontStyle === "oblique") {
|
|
4353
|
+
currentAttributes.italic = true;
|
|
4302
4354
|
}
|
|
4303
4355
|
processChildren(element);
|
|
4304
4356
|
flushText();
|
|
@@ -4307,6 +4359,10 @@ function htmlToDelta(html, options = {}) {
|
|
|
4307
4359
|
function processImageElement(element) {
|
|
4308
4360
|
const src = element.getAttribute("src");
|
|
4309
4361
|
if (!src) return;
|
|
4362
|
+
const style = element.getAttribute("style") || "";
|
|
4363
|
+
if (/(?:^|;)\s*opacity\s*:\s*0(?:\.0+)?\s*(?:;|$)/i.test(style)) {
|
|
4364
|
+
return;
|
|
4365
|
+
}
|
|
4310
4366
|
const attrs = {};
|
|
4311
4367
|
const alt = element.getAttribute("alt");
|
|
4312
4368
|
const width = element.getAttribute("width");
|