@lumir-company/editor 0.4.13 → 0.4.14
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 +1511 -1511
- package/dist/api/link-preview.js.map +1 -1
- package/dist/api/link-preview.mjs.map +1 -1
- package/dist/index.js +239 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +239 -0
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +1041 -1041
- package/package.json +94 -94
package/dist/index.mjs
CHANGED
|
@@ -3231,6 +3231,235 @@ function patchBlocks(blocks, tableVAMap) {
|
|
|
3231
3231
|
});
|
|
3232
3232
|
}
|
|
3233
3233
|
|
|
3234
|
+
// src/utils/excel-paste.ts
|
|
3235
|
+
var NAMED_COLORS = {
|
|
3236
|
+
black: "#000000",
|
|
3237
|
+
white: "#ffffff",
|
|
3238
|
+
red: "#ff0000",
|
|
3239
|
+
green: "#008000",
|
|
3240
|
+
blue: "#0000ff",
|
|
3241
|
+
yellow: "#ffff00",
|
|
3242
|
+
orange: "#ffa500",
|
|
3243
|
+
purple: "#800080",
|
|
3244
|
+
gray: "#808080",
|
|
3245
|
+
grey: "#808080"
|
|
3246
|
+
};
|
|
3247
|
+
function parseCssColorToRgb(input) {
|
|
3248
|
+
if (!input) return null;
|
|
3249
|
+
const s = input.trim().toLowerCase();
|
|
3250
|
+
if (!s || s === "transparent" || s === "none" || s === "inherit") return null;
|
|
3251
|
+
let m = s.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/);
|
|
3252
|
+
if (m) {
|
|
3253
|
+
let h = m[1];
|
|
3254
|
+
if (h.length === 3)
|
|
3255
|
+
h = h.split("").map((c) => c + c).join("");
|
|
3256
|
+
return [
|
|
3257
|
+
parseInt(h.slice(0, 2), 16),
|
|
3258
|
+
parseInt(h.slice(2, 4), 16),
|
|
3259
|
+
parseInt(h.slice(4, 6), 16)
|
|
3260
|
+
];
|
|
3261
|
+
}
|
|
3262
|
+
m = s.match(/^rgba?\(([^)]+)\)$/);
|
|
3263
|
+
if (m) {
|
|
3264
|
+
const parts = m[1].split(",").map((x) => parseFloat(x.trim()));
|
|
3265
|
+
if (parts.length >= 3 && parts.slice(0, 3).every((n) => !isNaN(n))) {
|
|
3266
|
+
return [parts[0], parts[1], parts[2]];
|
|
3267
|
+
}
|
|
3268
|
+
return null;
|
|
3269
|
+
}
|
|
3270
|
+
if (NAMED_COLORS[s]) return parseCssColorToRgb(NAMED_COLORS[s]);
|
|
3271
|
+
return null;
|
|
3272
|
+
}
|
|
3273
|
+
function rgbToHsl([r, g, b]) {
|
|
3274
|
+
r /= 255;
|
|
3275
|
+
g /= 255;
|
|
3276
|
+
b /= 255;
|
|
3277
|
+
const max = Math.max(r, g, b);
|
|
3278
|
+
const min = Math.min(r, g, b);
|
|
3279
|
+
const l = (max + min) / 2;
|
|
3280
|
+
let h = 0;
|
|
3281
|
+
let s = 0;
|
|
3282
|
+
const d = max - min;
|
|
3283
|
+
if (d !== 0) {
|
|
3284
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
3285
|
+
switch (max) {
|
|
3286
|
+
case r:
|
|
3287
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
|
|
3288
|
+
break;
|
|
3289
|
+
case g:
|
|
3290
|
+
h = ((b - r) / d + 2) * 60;
|
|
3291
|
+
break;
|
|
3292
|
+
default:
|
|
3293
|
+
h = ((r - g) / d + 4) * 60;
|
|
3294
|
+
break;
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
return [h, s, l];
|
|
3298
|
+
}
|
|
3299
|
+
var HUE_REFERENCE = [
|
|
3300
|
+
{ value: "red", hue: 0 },
|
|
3301
|
+
{ value: "brown", hue: 17 },
|
|
3302
|
+
{ value: "orange", hue: 30 },
|
|
3303
|
+
{ value: "yellow", hue: 46 },
|
|
3304
|
+
{ value: "green", hue: 150 },
|
|
3305
|
+
{ value: "blue", hue: 197 },
|
|
3306
|
+
{ value: "purple", hue: 262 },
|
|
3307
|
+
{ value: "pink", hue: 324 }
|
|
3308
|
+
];
|
|
3309
|
+
function hueDist(a, b) {
|
|
3310
|
+
const d = Math.abs(a - b) % 360;
|
|
3311
|
+
return d > 180 ? 360 - d : d;
|
|
3312
|
+
}
|
|
3313
|
+
function paletteValueFromRgb(rgb) {
|
|
3314
|
+
const [h, s, l] = rgbToHsl(rgb);
|
|
3315
|
+
if (s < 0.15) {
|
|
3316
|
+
if (l < 0.35) return "default";
|
|
3317
|
+
if (l > 0.85) return "default";
|
|
3318
|
+
return "gray";
|
|
3319
|
+
}
|
|
3320
|
+
let best = "gray";
|
|
3321
|
+
let bestDist = Infinity;
|
|
3322
|
+
for (const ref of HUE_REFERENCE) {
|
|
3323
|
+
const d = hueDist(h, ref.hue);
|
|
3324
|
+
if (d < bestDist) {
|
|
3325
|
+
bestDist = d;
|
|
3326
|
+
best = ref.value;
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
return best;
|
|
3330
|
+
}
|
|
3331
|
+
function nearestTextColorValue(rgb) {
|
|
3332
|
+
return paletteValueFromRgb(rgb);
|
|
3333
|
+
}
|
|
3334
|
+
function nearestBackgroundColorValue(rgb) {
|
|
3335
|
+
const [, s, l] = rgbToHsl(rgb);
|
|
3336
|
+
if (s < 0.12 && l > 0.85) return "default";
|
|
3337
|
+
return paletteValueFromRgb(rgb);
|
|
3338
|
+
}
|
|
3339
|
+
function parseStyle(style) {
|
|
3340
|
+
const out = {};
|
|
3341
|
+
style.split(";").forEach((decl) => {
|
|
3342
|
+
const idx = decl.indexOf(":");
|
|
3343
|
+
if (idx === -1) return;
|
|
3344
|
+
const k = decl.slice(0, idx).trim().toLowerCase();
|
|
3345
|
+
const v = decl.slice(idx + 1).trim();
|
|
3346
|
+
if (k) out[k] = v;
|
|
3347
|
+
});
|
|
3348
|
+
return out;
|
|
3349
|
+
}
|
|
3350
|
+
function colorFromBackgroundShorthand(value) {
|
|
3351
|
+
if (!value) return null;
|
|
3352
|
+
const direct = parseCssColorToRgb(value);
|
|
3353
|
+
if (direct) return direct;
|
|
3354
|
+
for (const token of value.split(/\s+/)) {
|
|
3355
|
+
const rgb = parseCssColorToRgb(token);
|
|
3356
|
+
if (rgb) return rgb;
|
|
3357
|
+
}
|
|
3358
|
+
return null;
|
|
3359
|
+
}
|
|
3360
|
+
function isTransparentColor(css) {
|
|
3361
|
+
if (!css) return true;
|
|
3362
|
+
const s = css.trim().toLowerCase();
|
|
3363
|
+
if (s === "transparent" || s === "none") return true;
|
|
3364
|
+
const m = s.match(/^rgba?\(([^)]+)\)$/);
|
|
3365
|
+
if (m) {
|
|
3366
|
+
const p = m[1].split(",").map((x) => parseFloat(x.trim()));
|
|
3367
|
+
if (p.length >= 4 && p[3] === 0) return true;
|
|
3368
|
+
}
|
|
3369
|
+
return false;
|
|
3370
|
+
}
|
|
3371
|
+
function normalizeAlign(ta) {
|
|
3372
|
+
const v = (ta || "").trim().toLowerCase();
|
|
3373
|
+
if (v === "right" || v === "end") return "right";
|
|
3374
|
+
if (v === "center") return "center";
|
|
3375
|
+
if (v === "justify") return "justify";
|
|
3376
|
+
return "";
|
|
3377
|
+
}
|
|
3378
|
+
function applyCellFormatting(el, fmt) {
|
|
3379
|
+
if (fmt.bgRgb && !fmt.bgTransparent) {
|
|
3380
|
+
const v = nearestBackgroundColorValue(fmt.bgRgb);
|
|
3381
|
+
if (v !== "default") el.setAttribute("data-background-color", v);
|
|
3382
|
+
}
|
|
3383
|
+
if (fmt.colorRgb) {
|
|
3384
|
+
const v = nearestTextColorValue(fmt.colorRgb);
|
|
3385
|
+
if (v !== "default") el.setAttribute("data-text-color", v);
|
|
3386
|
+
}
|
|
3387
|
+
if (["right", "center", "justify"].includes(fmt.align)) {
|
|
3388
|
+
el.setAttribute("data-text-alignment", fmt.align);
|
|
3389
|
+
}
|
|
3390
|
+
if ((fmt.bold || fmt.italic || fmt.underline) && el.innerHTML.trim()) {
|
|
3391
|
+
let inner = el.innerHTML;
|
|
3392
|
+
if (fmt.underline) inner = `<u>${inner}</u>`;
|
|
3393
|
+
if (fmt.italic) inner = `<em>${inner}</em>`;
|
|
3394
|
+
if (fmt.bold) inner = `<strong>${inner}</strong>`;
|
|
3395
|
+
el.innerHTML = inner;
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
function readComputedFormat(el) {
|
|
3399
|
+
const cs = getComputedStyle(el);
|
|
3400
|
+
const fw = cs.fontWeight;
|
|
3401
|
+
const fwNum = parseInt(fw, 10);
|
|
3402
|
+
const decoration = cs.textDecorationLine || cs.textDecoration || "";
|
|
3403
|
+
return {
|
|
3404
|
+
bgRgb: parseCssColorToRgb(cs.backgroundColor),
|
|
3405
|
+
bgTransparent: isTransparentColor(cs.backgroundColor),
|
|
3406
|
+
colorRgb: parseCssColorToRgb(cs.color),
|
|
3407
|
+
align: normalizeAlign(cs.textAlign),
|
|
3408
|
+
bold: fw === "bold" || fw === "bolder" || !isNaN(fwNum) && fwNum >= 600,
|
|
3409
|
+
italic: (cs.fontStyle || "").toLowerCase().includes("italic"),
|
|
3410
|
+
underline: decoration.toLowerCase().includes("underline")
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3413
|
+
function readInlineFormat(el) {
|
|
3414
|
+
const sm = parseStyle(el.getAttribute("style") || "");
|
|
3415
|
+
const bgRaw = sm["background-color"] || sm["background"] || "";
|
|
3416
|
+
const bgRgb = colorFromBackgroundShorthand(bgRaw) || parseCssColorToRgb(el.getAttribute("bgcolor"));
|
|
3417
|
+
const fw = (sm["font-weight"] || "").toLowerCase();
|
|
3418
|
+
const decoration = sm["text-decoration"] || sm["text-decoration-line"] || "";
|
|
3419
|
+
return {
|
|
3420
|
+
bgRgb,
|
|
3421
|
+
bgTransparent: !bgRaw && !el.getAttribute("bgcolor"),
|
|
3422
|
+
colorRgb: parseCssColorToRgb(sm["color"]),
|
|
3423
|
+
align: normalizeAlign(sm["text-align"] || el.getAttribute("align")),
|
|
3424
|
+
bold: fw === "bold" || fw === "bolder" || parseInt(fw, 10) >= 600,
|
|
3425
|
+
italic: (sm["font-style"] || "").toLowerCase().includes("italic"),
|
|
3426
|
+
underline: decoration.toLowerCase().includes("underline")
|
|
3427
|
+
};
|
|
3428
|
+
}
|
|
3429
|
+
function normalizeExcelTableHtml(html) {
|
|
3430
|
+
if (!html || typeof DOMParser === "undefined") return html;
|
|
3431
|
+
try {
|
|
3432
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
3433
|
+
doc.querySelectorAll("script").forEach((s) => s.remove());
|
|
3434
|
+
if (!doc.querySelector("table")) return html;
|
|
3435
|
+
if (typeof document !== "undefined" && document.body && typeof HTMLElement !== "undefined" && typeof HTMLElement.prototype.attachShadow === "function") {
|
|
3436
|
+
let host = null;
|
|
3437
|
+
try {
|
|
3438
|
+
host = document.createElement("div");
|
|
3439
|
+
host.setAttribute("aria-hidden", "true");
|
|
3440
|
+
host.style.cssText = "position:absolute;left:-99999px;top:0;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none";
|
|
3441
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
3442
|
+
const styles = Array.from(doc.querySelectorAll("style")).map((s) => s.outerHTML).join("");
|
|
3443
|
+
shadow.innerHTML = styles + doc.body.innerHTML;
|
|
3444
|
+
document.body.appendChild(host);
|
|
3445
|
+
shadow.querySelectorAll("td, th").forEach((node) => {
|
|
3446
|
+
applyCellFormatting(node, readComputedFormat(node));
|
|
3447
|
+
});
|
|
3448
|
+
const out = Array.from(shadow.querySelectorAll("table")).map((t) => t.outerHTML).join("");
|
|
3449
|
+
return out || html;
|
|
3450
|
+
} finally {
|
|
3451
|
+
if (host && host.parentNode) host.parentNode.removeChild(host);
|
|
3452
|
+
}
|
|
3453
|
+
}
|
|
3454
|
+
doc.querySelectorAll("td, th").forEach((node) => {
|
|
3455
|
+
applyCellFormatting(node, readInlineFormat(node));
|
|
3456
|
+
});
|
|
3457
|
+
return Array.from(doc.querySelectorAll("table")).map((t) => t.outerHTML).join("") || html;
|
|
3458
|
+
} catch {
|
|
3459
|
+
return html;
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3234
3463
|
// src/constants/limits.ts
|
|
3235
3464
|
var MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
3236
3465
|
var MAX_VIDEO_FILE_SIZE = 100 * 1024 * 1024;
|
|
@@ -3749,6 +3978,16 @@ function LumirEditor({
|
|
|
3749
3978
|
return true;
|
|
3750
3979
|
}
|
|
3751
3980
|
}
|
|
3981
|
+
const pastedHtml = event?.clipboardData?.getData?.("text/html") || "";
|
|
3982
|
+
if (/<table[\s>]/i.test(pastedHtml)) {
|
|
3983
|
+
DEBUG_LOG("paste:step0:table", "table HTML detected, using pasteHTML", {
|
|
3984
|
+
htmlLen: pastedHtml.length,
|
|
3985
|
+
hasFiles: !!event?.clipboardData?.files?.length
|
|
3986
|
+
});
|
|
3987
|
+
event.preventDefault();
|
|
3988
|
+
editor2.pasteHTML(normalizeExcelTableHtml(pastedHtml));
|
|
3989
|
+
return true;
|
|
3990
|
+
}
|
|
3752
3991
|
const fileList = event?.clipboardData?.files ?? null;
|
|
3753
3992
|
const files = fileList ? Array.from(fileList) : [];
|
|
3754
3993
|
const acceptedFiles = files.filter(
|