@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.d.cts CHANGED
@@ -999,6 +999,30 @@ declare const tableColAlignFormat: Format<TableColAlignType>;
999
999
  */
1000
1000
  declare const blockFormat: Format<Record<string, unknown>>;
1001
1001
 
1002
+ /**
1003
+ * Code Widget embed format (Phase 8 Part 3.5)
1004
+ *
1005
+ * Delta: { insert: { codeWidget: "https://codesandbox.io/s/abc123" } }
1006
+ *
1007
+ * Value is a URL to an interactive code playground (StackBlitz, CodeSandbox,
1008
+ * Replit, CodePen, JSFiddle). Rendered as an <iframe> carrying a
1009
+ * `data-code-widget` marker so it can be told apart from a plain video iframe
1010
+ * during HTML → Delta (see videoFormat.match guard).
1011
+ *
1012
+ * Markdown: ![Widget](url)
1013
+ * HTML: <iframe data-code-widget src="<embed-url>" frameborder="0" allowfullscreen
1014
+ * allow="…; cross-origin-isolated">
1015
+ *
1016
+ * The `allow="…; cross-origin-isolated"` list (see CODE_WIDGET_IFRAME_ALLOW)
1017
+ * delegates the cross-origin-isolated capability so StackBlitz WebContainer
1018
+ * embeds can boot SharedArrayBuffer; without it those embeds render blank.
1019
+ *
1020
+ * The src is run through `toCodeWidgetEmbedUrl` at render time, which is
1021
+ * idempotent, so resize/float attributes and the Delta ↔ HTML round-trip stay
1022
+ * stable regardless of whether the stored value is the user URL or embed URL.
1023
+ */
1024
+ declare const codeWidgetFormat: Format<string>;
1025
+
1002
1026
  /**
1003
1027
  * Divider (Horizontal Rule) embed format
1004
1028
  *
@@ -1580,6 +1604,26 @@ declare function escapeHtml(text: string): string;
1580
1604
  * Unescape HTML entities
1581
1605
  */
1582
1606
  declare function unescapeHtml(text: string): string;
1607
+ /**
1608
+ * Convert a code-playground URL to an embeddable iframe URL (Phase 8 Part 3.5).
1609
+ *
1610
+ * Idempotent: a URL that is already in embed form is returned unchanged, so the
1611
+ * Delta → HTML → Delta round-trip is stable regardless of which form is stored.
1612
+ *
1613
+ * Provider | User URL | Embed URL
1614
+ * -------------|----------------------------------|-----------------------------------
1615
+ * StackBlitz | stackblitz.com/edit/{id} | …?embed=1
1616
+ * | stackblitz.com/github/{u}/{r} | …?embed=1
1617
+ * CodeSandbox | codesandbox.io/s/{id} | codesandbox.io/embed/{id}
1618
+ * Replit | replit.com/@{u}/{repl} | …?embed=true
1619
+ * CodePen | codepen.io/{u}/pen/{id} | codepen.io/{u}/embed/{id}
1620
+ * JSFiddle | jsfiddle.net/{u}/{id}/ | jsfiddle.net/{u}/{id}/embedded/
1621
+ *
1622
+ * Unknown hosts are returned unchanged (the marker `data-code-widget` still
1623
+ * makes them render as an iframe; auto-detection of bare URLs lives in the
1624
+ * editor layer).
1625
+ */
1626
+ declare function toCodeWidgetEmbedUrl(url: string): string;
1583
1627
 
1584
1628
  /**
1585
1629
  * GitHub-compatible slugify for heading anchor links.
@@ -1944,4 +1988,4 @@ declare function isTableNewlineOp(op: Op | undefined): boolean;
1944
1988
  */
1945
1989
  declare function extractTableRegion(ops: readonly Op[], hintOpIdx: number): TableRegion | null;
1946
1990
 
1947
- export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
1991
+ export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
package/dist/index.d.ts CHANGED
@@ -999,6 +999,30 @@ declare const tableColAlignFormat: Format<TableColAlignType>;
999
999
  */
1000
1000
  declare const blockFormat: Format<Record<string, unknown>>;
1001
1001
 
1002
+ /**
1003
+ * Code Widget embed format (Phase 8 Part 3.5)
1004
+ *
1005
+ * Delta: { insert: { codeWidget: "https://codesandbox.io/s/abc123" } }
1006
+ *
1007
+ * Value is a URL to an interactive code playground (StackBlitz, CodeSandbox,
1008
+ * Replit, CodePen, JSFiddle). Rendered as an <iframe> carrying a
1009
+ * `data-code-widget` marker so it can be told apart from a plain video iframe
1010
+ * during HTML → Delta (see videoFormat.match guard).
1011
+ *
1012
+ * Markdown: ![Widget](url)
1013
+ * HTML: <iframe data-code-widget src="<embed-url>" frameborder="0" allowfullscreen
1014
+ * allow="…; cross-origin-isolated">
1015
+ *
1016
+ * The `allow="…; cross-origin-isolated"` list (see CODE_WIDGET_IFRAME_ALLOW)
1017
+ * delegates the cross-origin-isolated capability so StackBlitz WebContainer
1018
+ * embeds can boot SharedArrayBuffer; without it those embeds render blank.
1019
+ *
1020
+ * The src is run through `toCodeWidgetEmbedUrl` at render time, which is
1021
+ * idempotent, so resize/float attributes and the Delta ↔ HTML round-trip stay
1022
+ * stable regardless of whether the stored value is the user URL or embed URL.
1023
+ */
1024
+ declare const codeWidgetFormat: Format<string>;
1025
+
1002
1026
  /**
1003
1027
  * Divider (Horizontal Rule) embed format
1004
1028
  *
@@ -1580,6 +1604,26 @@ declare function escapeHtml(text: string): string;
1580
1604
  * Unescape HTML entities
1581
1605
  */
1582
1606
  declare function unescapeHtml(text: string): string;
1607
+ /**
1608
+ * Convert a code-playground URL to an embeddable iframe URL (Phase 8 Part 3.5).
1609
+ *
1610
+ * Idempotent: a URL that is already in embed form is returned unchanged, so the
1611
+ * Delta → HTML → Delta round-trip is stable regardless of which form is stored.
1612
+ *
1613
+ * Provider | User URL | Embed URL
1614
+ * -------------|----------------------------------|-----------------------------------
1615
+ * StackBlitz | stackblitz.com/edit/{id} | …?embed=1
1616
+ * | stackblitz.com/github/{u}/{r} | …?embed=1
1617
+ * CodeSandbox | codesandbox.io/s/{id} | codesandbox.io/embed/{id}
1618
+ * Replit | replit.com/@{u}/{repl} | …?embed=true
1619
+ * CodePen | codepen.io/{u}/pen/{id} | codepen.io/{u}/embed/{id}
1620
+ * JSFiddle | jsfiddle.net/{u}/{id}/ | jsfiddle.net/{u}/{id}/embedded/
1621
+ *
1622
+ * Unknown hosts are returned unchanged (the marker `data-code-widget` still
1623
+ * makes them render as an iframe; auto-detection of bare URLs lives in the
1624
+ * editor layer).
1625
+ */
1626
+ declare function toCodeWidgetEmbedUrl(url: string): string;
1583
1627
 
1584
1628
  /**
1585
1629
  * GitHub-compatible slugify for heading anchor links.
@@ -1944,4 +1988,4 @@ declare function isTableNewlineOp(op: Op | undefined): boolean;
1944
1988
  */
1945
1989
  declare function extractTableRegion(ops: readonly Op[], hintOpIdx: number): TableRegion | null;
1946
1990
 
1947
- export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
1991
+ export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
package/dist/index.js CHANGED
@@ -1897,6 +1897,25 @@ var EMBED_RENDERERS = {
1897
1897
  }
1898
1898
  return `<video src="${escapeHtml(src)}" controls${float}${style}></video>`;
1899
1899
  },
1900
+ codeWidget: (value, attrs) => {
1901
+ const src = typeof value === "string" ? value : "";
1902
+ const floatVal = attrs?.float;
1903
+ const widthVal = attrs?.width;
1904
+ const heightVal = attrs?.height;
1905
+ const float = floatVal != null && typeof floatVal === "string" && floatVal !== "none" ? ` data-float="${escapeHtml(floatVal)}"` : "";
1906
+ const styles = [];
1907
+ if (widthVal != null && (typeof widthVal === "string" || typeof widthVal === "number")) {
1908
+ const w = String(widthVal);
1909
+ if (w && w !== "auto") styles.push(`width: ${/^\d+$/.test(w) ? w + "px" : w}`);
1910
+ }
1911
+ if (heightVal != null && (typeof heightVal === "string" || typeof heightVal === "number")) {
1912
+ const h = String(heightVal);
1913
+ if (h && h !== "auto") styles.push(`height: ${/^\d+$/.test(h) ? h + "px" : h}`);
1914
+ }
1915
+ const style = styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
1916
+ const embedSrc = toCodeWidgetEmbedUrl(src);
1917
+ return `<iframe data-code-widget src="${escapeHtml(embedSrc)}" frameborder="0" allowfullscreen allow="${CODE_WIDGET_IFRAME_ALLOW}"${float}${style}></iframe>`;
1918
+ },
1900
1919
  formula: (value) => {
1901
1920
  const latex = typeof value === "string" ? value : "";
1902
1921
  return `<span class="formula" data-formula="${escapeHtml(latex)}">${escapeHtml(latex)}</span>`;
@@ -1990,6 +2009,125 @@ function fromVideoEmbedUrl(embedUrl) {
1990
2009
  }
1991
2010
  return embedUrl;
1992
2011
  }
2012
+ function splitUrl(url) {
2013
+ let rest = url;
2014
+ let hash = "";
2015
+ const hashIdx = rest.indexOf("#");
2016
+ if (hashIdx >= 0) {
2017
+ hash = rest.slice(hashIdx);
2018
+ rest = rest.slice(0, hashIdx);
2019
+ }
2020
+ let query = "";
2021
+ const qIdx = rest.indexOf("?");
2022
+ if (qIdx >= 0) {
2023
+ query = rest.slice(qIdx);
2024
+ rest = rest.slice(0, qIdx);
2025
+ }
2026
+ return { base: rest, query, hash };
2027
+ }
2028
+ function hasQueryParam(url, key) {
2029
+ const { query } = splitUrl(url);
2030
+ return new RegExp(`[?&]${key}=`, "i").test(query);
2031
+ }
2032
+ function appendQueryParam(url, key, value) {
2033
+ const { base, query, hash } = splitUrl(url);
2034
+ const next = query ? `${query}&${key}=${value}` : `?${key}=${value}`;
2035
+ return `${base}${next}${hash}`;
2036
+ }
2037
+ var CODE_WIDGET_IFRAME_ALLOW = "accelerometer; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; usb; vr; xr-spatial-tracking; cross-origin-isolated";
2038
+ function toCodeWidgetEmbedUrl(url) {
2039
+ const u = typeof url === "string" ? url.trim() : "";
2040
+ if (!u) return "";
2041
+ if (/(?:\/\/|^)(?:[\w-]+\.)*stackblitz\.com\//i.test(u)) {
2042
+ return hasQueryParam(u, "embed") ? u : appendQueryParam(u, "embed", "1");
2043
+ }
2044
+ if (/(?:\/\/|^)(?:[\w-]+\.)*codesandbox\.io\//i.test(u)) {
2045
+ if (/codesandbox\.io\/embed\//i.test(u)) return u;
2046
+ return u.replace(/codesandbox\.io\/s\//i, "codesandbox.io/embed/");
2047
+ }
2048
+ if (/(?:\/\/|^)(?:[\w-]+\.)*replit\.com\//i.test(u)) {
2049
+ return hasQueryParam(u, "embed") ? u : appendQueryParam(u, "embed", "true");
2050
+ }
2051
+ if (/(?:\/\/|^)(?:[\w-]+\.)*codepen\.io\//i.test(u)) {
2052
+ if (/codepen\.io\/[^/]+\/embed\//i.test(u)) return u;
2053
+ return u.replace(/(codepen\.io\/[^/]+)\/pen\//i, "$1/embed/");
2054
+ }
2055
+ if (/(?:\/\/|^)(?:[\w-]+\.)*jsfiddle\.net\//i.test(u)) {
2056
+ const { base, query, hash } = splitUrl(u);
2057
+ if (/\/embedded(?:\/|$)/i.test(base)) return u;
2058
+ const trimmed = base.replace(/\/+$/, "");
2059
+ return `${trimmed}/embedded/${query}${hash}`;
2060
+ }
2061
+ return u;
2062
+ }
2063
+
2064
+ // src/schema/formats/embed/codeWidget.ts
2065
+ var codeWidgetFormat = {
2066
+ name: "codeWidget",
2067
+ scope: "embed",
2068
+ normalize(value) {
2069
+ return typeof value === "string" ? value.trim() : value;
2070
+ },
2071
+ validate(value) {
2072
+ if (typeof value !== "string" || value.length === 0) {
2073
+ return false;
2074
+ }
2075
+ const trimmed = value.trim();
2076
+ if (trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../")) {
2077
+ return true;
2078
+ }
2079
+ if (trimmed.startsWith("//")) {
2080
+ return true;
2081
+ }
2082
+ try {
2083
+ const url = new URL(trimmed);
2084
+ return url.protocol === "http:" || url.protocol === "https:";
2085
+ } catch {
2086
+ return false;
2087
+ }
2088
+ },
2089
+ render(value, attributes) {
2090
+ const src = typeof value === "string" ? value : "";
2091
+ const floatVal = attributes?.float;
2092
+ const widthVal = attributes?.width;
2093
+ const heightVal = attributes?.height;
2094
+ const float = floatVal != null && typeof floatVal === "string" && floatVal !== "none" ? ` data-float="${escapeHtml(floatVal)}"` : "";
2095
+ const styles = [];
2096
+ if (widthVal != null && (typeof widthVal === "string" || typeof widthVal === "number")) {
2097
+ const w = String(widthVal);
2098
+ if (w && w !== "auto") styles.push(`width: ${/^\d+$/.test(w) ? w + "px" : w}`);
2099
+ }
2100
+ if (heightVal != null && (typeof heightVal === "string" || typeof heightVal === "number")) {
2101
+ const h = String(heightVal);
2102
+ if (h && h !== "auto") styles.push(`height: ${/^\d+$/.test(h) ? h + "px" : h}`);
2103
+ }
2104
+ const style = styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
2105
+ const embedSrc = toCodeWidgetEmbedUrl(src);
2106
+ return `<iframe data-code-widget src="${escapeHtml(embedSrc)}" frameborder="0" allowfullscreen allow="${CODE_WIDGET_IFRAME_ALLOW}"${float}${style}></iframe>`;
2107
+ },
2108
+ match(element) {
2109
+ if (element.tagName.toLowerCase() !== "iframe") return null;
2110
+ if (element.getAttribute("data-code-widget") === null) return null;
2111
+ const src = element.getAttribute("src");
2112
+ if (!src) return null;
2113
+ const attrs = {};
2114
+ const float = element.getAttribute("data-float");
2115
+ const styleAttr = element.getAttribute("style") || "";
2116
+ if (float) attrs.float = float;
2117
+ const widthMatch = styleAttr.match(/(?:^|;\s*)width:\s*([^;]+)/);
2118
+ if (widthMatch?.[1]) attrs.width = widthMatch[1].trim().replace(/px$/, "");
2119
+ const heightMatch = styleAttr.match(/(?:^|;\s*)height:\s*([^;]+)/);
2120
+ if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, "");
2121
+ if (Object.keys(attrs).length > 0) {
2122
+ return { value: src, attributes: attrs };
2123
+ }
2124
+ return { value: src };
2125
+ },
2126
+ toMarkdown(value) {
2127
+ const src = typeof value === "string" ? value : "";
2128
+ return `![Widget](${src})`;
2129
+ }
2130
+ };
1993
2131
 
1994
2132
  // src/schema/formats/embed/divider.ts
1995
2133
  var dividerFormat = {
@@ -2234,6 +2372,7 @@ var videoFormat = {
2234
2372
  return `<video src="${escapeHtml(src)}" controls${float}${style}></video>`;
2235
2373
  },
2236
2374
  match(element) {
2375
+ if (element.getAttribute("data-code-widget") !== null) return null;
2237
2376
  const tagName = element.tagName.toLowerCase();
2238
2377
  if (tagName !== "video" && tagName !== "iframe") return null;
2239
2378
  const src = element.getAttribute("src");
@@ -2286,6 +2425,7 @@ var defaultBlockFormats = [
2286
2425
  var defaultEmbedFormats = [
2287
2426
  imageFormat,
2288
2427
  videoFormat,
2428
+ codeWidgetFormat,
2289
2429
  formulaFormat,
2290
2430
  dividerFormat,
2291
2431
  softBreakFormat,
@@ -3628,6 +3768,10 @@ function htmlToDelta(html, options = {}) {
3628
3768
  const heightMatch = style.match(/(?:^|;\s*)height:\s*([^;]+)/);
3629
3769
  if (heightMatch?.[1]) attrs.height = heightMatch[1].trim().replace(/px$/, "");
3630
3770
  const embedAttrs = Object.keys(attrs).length > 0 ? attrs : void 0;
3771
+ if (element.getAttribute("data-code-widget") !== null) {
3772
+ context.pushEmbed({ codeWidget: src }, embedAttrs);
3773
+ return;
3774
+ }
3631
3775
  context.pushEmbed({ video: fromVideoEmbedUrl(src) }, embedAttrs);
3632
3776
  }
3633
3777
  function processFootnotesSection(section) {
@@ -4485,6 +4629,28 @@ function renderEmbed2(embed, attributes, customRenderers, useLatexDelimiters = f
4485
4629
  }
4486
4630
  return `![Video](${src})`;
4487
4631
  }
4632
+ if (embedType === "codeWidget") {
4633
+ const src = typeof embedValue === "string" ? embedValue : "";
4634
+ const hasFloat = attributes?.float != null && typeof attributes.float === "string" && attributes.float !== "none";
4635
+ const hasWidth = attributes?.width != null;
4636
+ const hasHeight = attributes?.height != null;
4637
+ if (hasFloat || hasWidth || hasHeight) {
4638
+ const floatAttr = hasFloat ? ` data-float="${escapeHtml(String(attributes.float))}"` : "";
4639
+ const styles = [];
4640
+ if (hasWidth) {
4641
+ const w = typeof attributes.width === "string" || typeof attributes.width === "number" ? String(attributes.width) : "";
4642
+ if (w && w !== "auto") styles.push(`width: ${/^\d+$/.test(w) ? w + "px" : w}`);
4643
+ }
4644
+ if (hasHeight) {
4645
+ const h = typeof attributes.height === "string" || typeof attributes.height === "number" ? String(attributes.height) : "";
4646
+ if (h && h !== "auto") styles.push(`height: ${/^\d+$/.test(h) ? h + "px" : h}`);
4647
+ }
4648
+ const styleAttr = styles.length > 0 ? ` style="${styles.join("; ")}"` : "";
4649
+ const embedSrc = toCodeWidgetEmbedUrl(src);
4650
+ return `<iframe data-code-widget src="${escapeHtml(embedSrc)}" frameborder="0" allowfullscreen${floatAttr}${styleAttr}></iframe>`;
4651
+ }
4652
+ return `![Widget](${src})`;
4653
+ }
4488
4654
  if (embedType === "formula") {
4489
4655
  const latex = typeof embedValue === "string" ? embedValue : "";
4490
4656
  return useLatexDelimiters ? `\\(${latex}\\)` : `$${latex}$`;
@@ -4951,6 +5117,10 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
4951
5117
  context.pushEmbed({ video: url });
4952
5118
  return;
4953
5119
  }
5120
+ if (alt.toLowerCase() === "widget") {
5121
+ context.pushEmbed({ codeWidget: url });
5122
+ return;
5123
+ }
4954
5124
  const attrs = {};
4955
5125
  if (node.alt) attrs.alt = node.alt;
4956
5126
  if (url.toLowerCase().endsWith(".drawio")) {
@@ -5317,6 +5487,7 @@ export {
5317
5487
  cloneDelta,
5318
5488
  codeBlockFormat,
5319
5489
  codeFormat,
5490
+ codeWidgetFormat,
5320
5491
  colorFormat,
5321
5492
  columnsBlockHandler,
5322
5493
  createDefaultBlockHandlers,
@@ -5380,6 +5551,7 @@ export {
5380
5551
  tableColFormat,
5381
5552
  tableHeaderFormat,
5382
5553
  tableRowFormat,
5554
+ toCodeWidgetEmbedUrl,
5383
5555
  toHexColor,
5384
5556
  underlineFormat,
5385
5557
  unescapeHtml,