@scrider/formatter 1.5.0 → 1.6.1
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 +174 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -1
- package/dist/index.d.ts +45 -1
- package/dist/index.js +172 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
cloneDelta: () => cloneDelta,
|
|
61
61
|
codeBlockFormat: () => codeBlockFormat,
|
|
62
62
|
codeFormat: () => codeFormat,
|
|
63
|
+
codeWidgetFormat: () => codeWidgetFormat,
|
|
63
64
|
colorFormat: () => colorFormat,
|
|
64
65
|
columnsBlockHandler: () => columnsBlockHandler,
|
|
65
66
|
createDefaultBlockHandlers: () => createDefaultBlockHandlers,
|
|
@@ -123,6 +124,7 @@ __export(index_exports, {
|
|
|
123
124
|
tableColFormat: () => tableColFormat,
|
|
124
125
|
tableHeaderFormat: () => tableHeaderFormat,
|
|
125
126
|
tableRowFormat: () => tableRowFormat,
|
|
127
|
+
toCodeWidgetEmbedUrl: () => toCodeWidgetEmbedUrl,
|
|
126
128
|
toHexColor: () => toHexColor,
|
|
127
129
|
underlineFormat: () => underlineFormat,
|
|
128
130
|
unescapeHtml: () => unescapeHtml,
|
|
@@ -2021,6 +2023,25 @@ var EMBED_RENDERERS = {
|
|
|
2021
2023
|
}
|
|
2022
2024
|
return `<video src="${escapeHtml(src)}" controls${float}${style}></video>`;
|
|
2023
2025
|
},
|
|
2026
|
+
codeWidget: (value, attrs) => {
|
|
2027
|
+
const src = typeof value === "string" ? value : "";
|
|
2028
|
+
const floatVal = attrs?.float;
|
|
2029
|
+
const widthVal = attrs?.width;
|
|
2030
|
+
const heightVal = attrs?.height;
|
|
2031
|
+
const float = floatVal != null && typeof floatVal === "string" && floatVal !== "none" ? ` data-float="${escapeHtml(floatVal)}"` : "";
|
|
2032
|
+
const styles = [];
|
|
2033
|
+
if (widthVal != null && (typeof widthVal === "string" || typeof widthVal === "number")) {
|
|
2034
|
+
const w = String(widthVal);
|
|
2035
|
+
if (w && w !== "auto") styles.push(`width: ${/^\d+$/.test(w) ? w + "px" : w}`);
|
|
2036
|
+
}
|
|
2037
|
+
if (heightVal != null && (typeof heightVal === "string" || typeof heightVal === "number")) {
|
|
2038
|
+
const h = String(heightVal);
|
|
2039
|
+
if (h && h !== "auto") styles.push(`height: ${/^\d+$/.test(h) ? h + "px" : h}`);
|
|
2040
|
+
}
|
|
2041
|
+
const style = styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
|
|
2042
|
+
const embedSrc = toCodeWidgetEmbedUrl(src);
|
|
2043
|
+
return `<iframe data-code-widget src="${escapeHtml(embedSrc)}" frameborder="0" allowfullscreen allow="${CODE_WIDGET_IFRAME_ALLOW}"${float}${style}></iframe>`;
|
|
2044
|
+
},
|
|
2024
2045
|
formula: (value) => {
|
|
2025
2046
|
const latex = typeof value === "string" ? value : "";
|
|
2026
2047
|
return `<span class="formula" data-formula="${escapeHtml(latex)}">${escapeHtml(latex)}</span>`;
|
|
@@ -2114,6 +2135,125 @@ function fromVideoEmbedUrl(embedUrl) {
|
|
|
2114
2135
|
}
|
|
2115
2136
|
return embedUrl;
|
|
2116
2137
|
}
|
|
2138
|
+
function splitUrl(url) {
|
|
2139
|
+
let rest = url;
|
|
2140
|
+
let hash = "";
|
|
2141
|
+
const hashIdx = rest.indexOf("#");
|
|
2142
|
+
if (hashIdx >= 0) {
|
|
2143
|
+
hash = rest.slice(hashIdx);
|
|
2144
|
+
rest = rest.slice(0, hashIdx);
|
|
2145
|
+
}
|
|
2146
|
+
let query = "";
|
|
2147
|
+
const qIdx = rest.indexOf("?");
|
|
2148
|
+
if (qIdx >= 0) {
|
|
2149
|
+
query = rest.slice(qIdx);
|
|
2150
|
+
rest = rest.slice(0, qIdx);
|
|
2151
|
+
}
|
|
2152
|
+
return { base: rest, query, hash };
|
|
2153
|
+
}
|
|
2154
|
+
function hasQueryParam(url, key) {
|
|
2155
|
+
const { query } = splitUrl(url);
|
|
2156
|
+
return new RegExp(`[?&]${key}=`, "i").test(query);
|
|
2157
|
+
}
|
|
2158
|
+
function appendQueryParam(url, key, value) {
|
|
2159
|
+
const { base, query, hash } = splitUrl(url);
|
|
2160
|
+
const next = query ? `${query}&${key}=${value}` : `?${key}=${value}`;
|
|
2161
|
+
return `${base}${next}${hash}`;
|
|
2162
|
+
}
|
|
2163
|
+
var CODE_WIDGET_IFRAME_ALLOW = "accelerometer; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; usb; vr; xr-spatial-tracking; cross-origin-isolated";
|
|
2164
|
+
function toCodeWidgetEmbedUrl(url) {
|
|
2165
|
+
const u = typeof url === "string" ? url.trim() : "";
|
|
2166
|
+
if (!u) return "";
|
|
2167
|
+
if (/(?:\/\/|^)(?:[\w-]+\.)*stackblitz\.com\//i.test(u)) {
|
|
2168
|
+
return hasQueryParam(u, "embed") ? u : appendQueryParam(u, "embed", "1");
|
|
2169
|
+
}
|
|
2170
|
+
if (/(?:\/\/|^)(?:[\w-]+\.)*codesandbox\.io\//i.test(u)) {
|
|
2171
|
+
if (/codesandbox\.io\/embed\//i.test(u)) return u;
|
|
2172
|
+
return u.replace(/codesandbox\.io\/s\//i, "codesandbox.io/embed/");
|
|
2173
|
+
}
|
|
2174
|
+
if (/(?:\/\/|^)(?:[\w-]+\.)*replit\.com\//i.test(u)) {
|
|
2175
|
+
return hasQueryParam(u, "embed") ? u : appendQueryParam(u, "embed", "true");
|
|
2176
|
+
}
|
|
2177
|
+
if (/(?:\/\/|^)(?:[\w-]+\.)*codepen\.io\//i.test(u)) {
|
|
2178
|
+
if (/codepen\.io\/[^/]+\/embed\//i.test(u)) return u;
|
|
2179
|
+
return u.replace(/(codepen\.io\/[^/]+)\/pen\//i, "$1/embed/");
|
|
2180
|
+
}
|
|
2181
|
+
if (/(?:\/\/|^)(?:[\w-]+\.)*jsfiddle\.net\//i.test(u)) {
|
|
2182
|
+
const { base, query, hash } = splitUrl(u);
|
|
2183
|
+
if (/\/embedded(?:\/|$)/i.test(base)) return u;
|
|
2184
|
+
const trimmed = base.replace(/\/+$/, "");
|
|
2185
|
+
return `${trimmed}/embedded/${query}${hash}`;
|
|
2186
|
+
}
|
|
2187
|
+
return u;
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
// src/schema/formats/embed/codeWidget.ts
|
|
2191
|
+
var codeWidgetFormat = {
|
|
2192
|
+
name: "codeWidget",
|
|
2193
|
+
scope: "embed",
|
|
2194
|
+
normalize(value) {
|
|
2195
|
+
return typeof value === "string" ? value.trim() : value;
|
|
2196
|
+
},
|
|
2197
|
+
validate(value) {
|
|
2198
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
2199
|
+
return false;
|
|
2200
|
+
}
|
|
2201
|
+
const trimmed = value.trim();
|
|
2202
|
+
if (trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../")) {
|
|
2203
|
+
return true;
|
|
2204
|
+
}
|
|
2205
|
+
if (trimmed.startsWith("//")) {
|
|
2206
|
+
return true;
|
|
2207
|
+
}
|
|
2208
|
+
try {
|
|
2209
|
+
const url = new URL(trimmed);
|
|
2210
|
+
return url.protocol === "http:" || url.protocol === "https:";
|
|
2211
|
+
} catch {
|
|
2212
|
+
return false;
|
|
2213
|
+
}
|
|
2214
|
+
},
|
|
2215
|
+
render(value, attributes) {
|
|
2216
|
+
const src = typeof value === "string" ? value : "";
|
|
2217
|
+
const floatVal = attributes?.float;
|
|
2218
|
+
const widthVal = attributes?.width;
|
|
2219
|
+
const heightVal = attributes?.height;
|
|
2220
|
+
const float = floatVal != null && typeof floatVal === "string" && floatVal !== "none" ? ` data-float="${escapeHtml(floatVal)}"` : "";
|
|
2221
|
+
const styles = [];
|
|
2222
|
+
if (widthVal != null && (typeof widthVal === "string" || typeof widthVal === "number")) {
|
|
2223
|
+
const w = String(widthVal);
|
|
2224
|
+
if (w && w !== "auto") styles.push(`width: ${/^\d+$/.test(w) ? w + "px" : w}`);
|
|
2225
|
+
}
|
|
2226
|
+
if (heightVal != null && (typeof heightVal === "string" || typeof heightVal === "number")) {
|
|
2227
|
+
const h = String(heightVal);
|
|
2228
|
+
if (h && h !== "auto") styles.push(`height: ${/^\d+$/.test(h) ? h + "px" : h}`);
|
|
2229
|
+
}
|
|
2230
|
+
const style = styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
|
|
2231
|
+
const embedSrc = toCodeWidgetEmbedUrl(src);
|
|
2232
|
+
return `<iframe data-code-widget src="${escapeHtml(embedSrc)}" frameborder="0" allowfullscreen allow="${CODE_WIDGET_IFRAME_ALLOW}"${float}${style}></iframe>`;
|
|
2233
|
+
},
|
|
2234
|
+
match(element) {
|
|
2235
|
+
if (element.tagName.toLowerCase() !== "iframe") return null;
|
|
2236
|
+
if (element.getAttribute("data-code-widget") === null) return null;
|
|
2237
|
+
const src = element.getAttribute("src");
|
|
2238
|
+
if (!src) return null;
|
|
2239
|
+
const attrs = {};
|
|
2240
|
+
const float = element.getAttribute("data-float");
|
|
2241
|
+
const styleAttr = element.getAttribute("style") || "";
|
|
2242
|
+
if (float) attrs.float = float;
|
|
2243
|
+
const widthMatch = styleAttr.match(/(?:^|;\s*)width:\s*([^;]+)/);
|
|
2244
|
+
if (widthMatch?.[1]) attrs.width = widthMatch[1].trim().replace(/px$/, "");
|
|
2245
|
+
const heightMatch = styleAttr.match(/(?:^|;\s*)height:\s*([^;]+)/);
|
|
2246
|
+
if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, "");
|
|
2247
|
+
if (Object.keys(attrs).length > 0) {
|
|
2248
|
+
return { value: src, attributes: attrs };
|
|
2249
|
+
}
|
|
2250
|
+
return { value: src };
|
|
2251
|
+
},
|
|
2252
|
+
toMarkdown(value) {
|
|
2253
|
+
const src = typeof value === "string" ? value : "";
|
|
2254
|
+
return ``;
|
|
2255
|
+
}
|
|
2256
|
+
};
|
|
2117
2257
|
|
|
2118
2258
|
// src/schema/formats/embed/divider.ts
|
|
2119
2259
|
var dividerFormat = {
|
|
@@ -2358,6 +2498,7 @@ var videoFormat = {
|
|
|
2358
2498
|
return `<video src="${escapeHtml(src)}" controls${float}${style}></video>`;
|
|
2359
2499
|
},
|
|
2360
2500
|
match(element) {
|
|
2501
|
+
if (element.getAttribute("data-code-widget") !== null) return null;
|
|
2361
2502
|
const tagName = element.tagName.toLowerCase();
|
|
2362
2503
|
if (tagName !== "video" && tagName !== "iframe") return null;
|
|
2363
2504
|
const src = element.getAttribute("src");
|
|
@@ -2410,6 +2551,7 @@ var defaultBlockFormats = [
|
|
|
2410
2551
|
var defaultEmbedFormats = [
|
|
2411
2552
|
imageFormat,
|
|
2412
2553
|
videoFormat,
|
|
2554
|
+
codeWidgetFormat,
|
|
2413
2555
|
formulaFormat,
|
|
2414
2556
|
dividerFormat,
|
|
2415
2557
|
softBreakFormat,
|
|
@@ -3752,6 +3894,10 @@ function htmlToDelta(html, options = {}) {
|
|
|
3752
3894
|
const heightMatch = style.match(/(?:^|;\s*)height:\s*([^;]+)/);
|
|
3753
3895
|
if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, "");
|
|
3754
3896
|
const embedAttrs = Object.keys(attrs).length > 0 ? attrs : void 0;
|
|
3897
|
+
if (element.getAttribute("data-code-widget") !== null) {
|
|
3898
|
+
context.pushEmbed({ codeWidget: src }, embedAttrs);
|
|
3899
|
+
return;
|
|
3900
|
+
}
|
|
3755
3901
|
context.pushEmbed({ video: fromVideoEmbedUrl(src) }, embedAttrs);
|
|
3756
3902
|
}
|
|
3757
3903
|
function processFootnotesSection(section) {
|
|
@@ -4609,6 +4755,28 @@ function renderEmbed2(embed, attributes, customRenderers, useLatexDelimiters = f
|
|
|
4609
4755
|
}
|
|
4610
4756
|
return ``;
|
|
4611
4757
|
}
|
|
4758
|
+
if (embedType === "codeWidget") {
|
|
4759
|
+
const src = typeof embedValue === "string" ? embedValue : "";
|
|
4760
|
+
const hasFloat = attributes?.float != null && typeof attributes.float === "string" && attributes.float !== "none";
|
|
4761
|
+
const hasWidth = attributes?.width != null;
|
|
4762
|
+
const hasHeight = attributes?.height != null;
|
|
4763
|
+
if (hasFloat || hasWidth || hasHeight) {
|
|
4764
|
+
const floatAttr = hasFloat ? ` data-float="${escapeHtml(String(attributes.float))}"` : "";
|
|
4765
|
+
const styles = [];
|
|
4766
|
+
if (hasWidth) {
|
|
4767
|
+
const w = typeof attributes.width === "string" || typeof attributes.width === "number" ? String(attributes.width) : "";
|
|
4768
|
+
if (w && w !== "auto") styles.push(`width: ${/^\d+$/.test(w) ? w + "px" : w}`);
|
|
4769
|
+
}
|
|
4770
|
+
if (hasHeight) {
|
|
4771
|
+
const h = typeof attributes.height === "string" || typeof attributes.height === "number" ? String(attributes.height) : "";
|
|
4772
|
+
if (h && h !== "auto") styles.push(`height: ${/^\d+$/.test(h) ? h + "px" : h}`);
|
|
4773
|
+
}
|
|
4774
|
+
const styleAttr = styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
|
|
4775
|
+
const embedSrc = toCodeWidgetEmbedUrl(src);
|
|
4776
|
+
return `<iframe data-code-widget src="${escapeHtml(embedSrc)}" frameborder="0" allowfullscreen${floatAttr}${styleAttr}></iframe>`;
|
|
4777
|
+
}
|
|
4778
|
+
return ``;
|
|
4779
|
+
}
|
|
4612
4780
|
if (embedType === "formula") {
|
|
4613
4781
|
const latex = typeof embedValue === "string" ? embedValue : "";
|
|
4614
4782
|
return useLatexDelimiters ? `\\(${latex}\\)` : `$${latex}$`;
|
|
@@ -5075,6 +5243,10 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
|
|
|
5075
5243
|
context.pushEmbed({ video: url });
|
|
5076
5244
|
return;
|
|
5077
5245
|
}
|
|
5246
|
+
if (alt.toLowerCase() === "widget") {
|
|
5247
|
+
context.pushEmbed({ codeWidget: url });
|
|
5248
|
+
return;
|
|
5249
|
+
}
|
|
5078
5250
|
const attrs = {};
|
|
5079
5251
|
if (node.alt) attrs.alt = node.alt;
|
|
5080
5252
|
if (url.toLowerCase().endsWith(".drawio")) {
|
|
@@ -5442,6 +5614,7 @@ function extractTableRegion(ops, hintOpIdx) {
|
|
|
5442
5614
|
cloneDelta,
|
|
5443
5615
|
codeBlockFormat,
|
|
5444
5616
|
codeFormat,
|
|
5617
|
+
codeWidgetFormat,
|
|
5445
5618
|
colorFormat,
|
|
5446
5619
|
columnsBlockHandler,
|
|
5447
5620
|
createDefaultBlockHandlers,
|
|
@@ -5505,6 +5678,7 @@ function extractTableRegion(ops, hintOpIdx) {
|
|
|
5505
5678
|
tableColFormat,
|
|
5506
5679
|
tableHeaderFormat,
|
|
5507
5680
|
tableRowFormat,
|
|
5681
|
+
toCodeWidgetEmbedUrl,
|
|
5508
5682
|
toHexColor,
|
|
5509
5683
|
underlineFormat,
|
|
5510
5684
|
unescapeHtml,
|