@particle-academy/fancy-code 0.9.1 → 0.11.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.
- package/dist/index.cjs +113 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -5
- package/dist/index.d.ts +14 -5
- package/dist/index.js +114 -102
- package/dist/index.js.map +1 -1
- package/package.json +10 -7
package/dist/index.cjs
CHANGED
|
@@ -1635,105 +1635,6 @@ var CodeEditor = Object.assign(CodeEditorRoot, {
|
|
|
1635
1635
|
Panel: CodeEditorPanel,
|
|
1636
1636
|
StatusBar: CodeEditorStatusBar
|
|
1637
1637
|
});
|
|
1638
|
-
|
|
1639
|
-
// src/engine/markdown-render.ts
|
|
1640
|
-
function escapeHtml(s) {
|
|
1641
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1642
|
-
}
|
|
1643
|
-
function escapeAttr(s) {
|
|
1644
|
-
return s.replace(/"/g, """).replace(/'/g, "'");
|
|
1645
|
-
}
|
|
1646
|
-
function inline(text) {
|
|
1647
|
-
return text.replace(/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g, (_m, alt, src, title) => `<img src="${escapeAttr(src)}" alt="${escapeAttr(alt)}"${title ? ` title="${escapeAttr(title)}"` : ""}>`).replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g, (_m, t, href, title) => `<a href="${escapeAttr(href)}"${title ? ` title="${escapeAttr(title)}"` : ""} rel="noopener">${t}</a>`).replace(/`([^`]+)`/g, (_m, c) => `<code>${c}</code>`).replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g, "<strong>$2</strong>").replace(/(\*|_)(?=\S)([\s\S]*?\S)\1/g, "<em>$2</em>");
|
|
1648
|
-
}
|
|
1649
|
-
function renderMarkdown(markdown) {
|
|
1650
|
-
const lines = markdown.replace(/\r\n?/g, "\n").split("\n");
|
|
1651
|
-
const out = [];
|
|
1652
|
-
let i = 0;
|
|
1653
|
-
let para = [];
|
|
1654
|
-
let listType = null;
|
|
1655
|
-
const flushPara = () => {
|
|
1656
|
-
if (para.length) {
|
|
1657
|
-
out.push(`<p>${inline(para.join(" "))}</p>`);
|
|
1658
|
-
para = [];
|
|
1659
|
-
}
|
|
1660
|
-
};
|
|
1661
|
-
const closeList = () => {
|
|
1662
|
-
if (listType) {
|
|
1663
|
-
out.push(`</${listType}>`);
|
|
1664
|
-
listType = null;
|
|
1665
|
-
}
|
|
1666
|
-
};
|
|
1667
|
-
while (i < lines.length) {
|
|
1668
|
-
const line = lines[i];
|
|
1669
|
-
const fence = line.match(/^\s*(```|~~~)(.*)$/);
|
|
1670
|
-
if (fence) {
|
|
1671
|
-
flushPara();
|
|
1672
|
-
closeList();
|
|
1673
|
-
const lang = fence[2].trim();
|
|
1674
|
-
const body = [];
|
|
1675
|
-
i++;
|
|
1676
|
-
while (i < lines.length && !/^\s*(```|~~~)/.test(lines[i])) {
|
|
1677
|
-
body.push(lines[i]);
|
|
1678
|
-
i++;
|
|
1679
|
-
}
|
|
1680
|
-
i++;
|
|
1681
|
-
out.push(`<pre><code${lang ? ` class="language-${escapeAttr(escapeHtml(lang))}"` : ""}>${escapeHtml(body.join("\n"))}</code></pre>`);
|
|
1682
|
-
continue;
|
|
1683
|
-
}
|
|
1684
|
-
const esc = escapeHtml(line);
|
|
1685
|
-
if (/^\s*$/.test(line)) {
|
|
1686
|
-
flushPara();
|
|
1687
|
-
closeList();
|
|
1688
|
-
i++;
|
|
1689
|
-
continue;
|
|
1690
|
-
}
|
|
1691
|
-
const heading = esc.match(/^(#{1,6})\s+(.*)$/);
|
|
1692
|
-
if (heading) {
|
|
1693
|
-
flushPara();
|
|
1694
|
-
closeList();
|
|
1695
|
-
const level = heading[1].length;
|
|
1696
|
-
out.push(`<h${level}>${inline(heading[2])}</h${level}>`);
|
|
1697
|
-
i++;
|
|
1698
|
-
continue;
|
|
1699
|
-
}
|
|
1700
|
-
if (/^\s*([-*_])(\s*\1){2,}\s*$/.test(line)) {
|
|
1701
|
-
flushPara();
|
|
1702
|
-
closeList();
|
|
1703
|
-
out.push("<hr>");
|
|
1704
|
-
i++;
|
|
1705
|
-
continue;
|
|
1706
|
-
}
|
|
1707
|
-
const quote = esc.match(/^\s*>\s?(.*)$/);
|
|
1708
|
-
if (quote) {
|
|
1709
|
-
flushPara();
|
|
1710
|
-
closeList();
|
|
1711
|
-
out.push(`<blockquote>${inline(quote[1])}</blockquote>`);
|
|
1712
|
-
i++;
|
|
1713
|
-
continue;
|
|
1714
|
-
}
|
|
1715
|
-
const ol = esc.match(/^\s*\d+\.\s+(.*)$/);
|
|
1716
|
-
const ul = esc.match(/^\s*[-*+]\s+(.*)$/);
|
|
1717
|
-
if (ol || ul) {
|
|
1718
|
-
flushPara();
|
|
1719
|
-
const type = ol ? "ol" : "ul";
|
|
1720
|
-
if (listType !== type) {
|
|
1721
|
-
closeList();
|
|
1722
|
-
out.push(`<${type}>`);
|
|
1723
|
-
listType = type;
|
|
1724
|
-
}
|
|
1725
|
-
out.push(`<li>${inline((ol ?? ul)[1])}</li>`);
|
|
1726
|
-
i++;
|
|
1727
|
-
continue;
|
|
1728
|
-
}
|
|
1729
|
-
closeList();
|
|
1730
|
-
para.push(esc);
|
|
1731
|
-
i++;
|
|
1732
|
-
}
|
|
1733
|
-
flushPara();
|
|
1734
|
-
closeList();
|
|
1735
|
-
return out.join("\n");
|
|
1736
|
-
}
|
|
1737
1638
|
function MarkdownEditor({
|
|
1738
1639
|
value,
|
|
1739
1640
|
defaultValue = "",
|
|
@@ -1747,7 +1648,7 @@ function MarkdownEditor({
|
|
|
1747
1648
|
minHeight,
|
|
1748
1649
|
maxHeight,
|
|
1749
1650
|
className,
|
|
1750
|
-
renderPreview
|
|
1651
|
+
renderPreview
|
|
1751
1652
|
}) {
|
|
1752
1653
|
const [content, setContent] = reactFancy.useControllableState(value, defaultValue, onValueChange);
|
|
1753
1654
|
const showEditor = mode !== "preview";
|
|
@@ -1780,7 +1681,19 @@ function MarkdownEditor({
|
|
|
1780
1681
|
{
|
|
1781
1682
|
"data-fancy-markdown-preview": "",
|
|
1782
1683
|
className: "fancy-md-preview",
|
|
1783
|
-
|
|
1684
|
+
style: maxHeight ? { maxHeight, overflowY: "auto" } : void 0,
|
|
1685
|
+
children: renderPreview ? (
|
|
1686
|
+
// The host imposed its own pipeline; its HTML is injected as-is and
|
|
1687
|
+
// is its own responsibility to sanitise.
|
|
1688
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderPreview(content) } })
|
|
1689
|
+
) : (
|
|
1690
|
+
// The kit's own renderer — a full CommonMark + GFM parse that
|
|
1691
|
+
// sanitises by default. `marked` already sits in this tree as a
|
|
1692
|
+
// react-fancy runtime dependency, so the built-in renderer this
|
|
1693
|
+
// replaced was a second, weaker markdown implementation next to a
|
|
1694
|
+
// complete one.
|
|
1695
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContentRenderer, { value: content, format: "markdown" })
|
|
1696
|
+
)
|
|
1784
1697
|
}
|
|
1785
1698
|
)
|
|
1786
1699
|
]
|
|
@@ -1862,6 +1775,105 @@ function FileViewer({
|
|
|
1862
1775
|
);
|
|
1863
1776
|
}
|
|
1864
1777
|
FileViewer.displayName = "FileViewer";
|
|
1778
|
+
|
|
1779
|
+
// src/engine/markdown-render.ts
|
|
1780
|
+
function escapeHtml(s) {
|
|
1781
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1782
|
+
}
|
|
1783
|
+
function escapeAttr(s) {
|
|
1784
|
+
return s.replace(/"/g, """).replace(/'/g, "'");
|
|
1785
|
+
}
|
|
1786
|
+
function inline(text) {
|
|
1787
|
+
return text.replace(/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g, (_m, alt, src, title) => `<img src="${escapeAttr(src)}" alt="${escapeAttr(alt)}"${title ? ` title="${escapeAttr(title)}"` : ""}>`).replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g, (_m, t, href, title) => `<a href="${escapeAttr(href)}"${title ? ` title="${escapeAttr(title)}"` : ""} rel="noopener">${t}</a>`).replace(/`([^`]+)`/g, (_m, c) => `<code>${c}</code>`).replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g, "<strong>$2</strong>").replace(/(\*|_)(?=\S)([\s\S]*?\S)\1/g, "<em>$2</em>");
|
|
1788
|
+
}
|
|
1789
|
+
function renderMarkdown(markdown) {
|
|
1790
|
+
const lines = markdown.replace(/\r\n?/g, "\n").split("\n");
|
|
1791
|
+
const out = [];
|
|
1792
|
+
let i = 0;
|
|
1793
|
+
let para = [];
|
|
1794
|
+
let listType = null;
|
|
1795
|
+
const flushPara = () => {
|
|
1796
|
+
if (para.length) {
|
|
1797
|
+
out.push(`<p>${inline(para.join(" "))}</p>`);
|
|
1798
|
+
para = [];
|
|
1799
|
+
}
|
|
1800
|
+
};
|
|
1801
|
+
const closeList = () => {
|
|
1802
|
+
if (listType) {
|
|
1803
|
+
out.push(`</${listType}>`);
|
|
1804
|
+
listType = null;
|
|
1805
|
+
}
|
|
1806
|
+
};
|
|
1807
|
+
while (i < lines.length) {
|
|
1808
|
+
const line = lines[i];
|
|
1809
|
+
const fence = line.match(/^\s*(```|~~~)(.*)$/);
|
|
1810
|
+
if (fence) {
|
|
1811
|
+
flushPara();
|
|
1812
|
+
closeList();
|
|
1813
|
+
const lang = fence[2].trim();
|
|
1814
|
+
const body = [];
|
|
1815
|
+
i++;
|
|
1816
|
+
while (i < lines.length && !/^\s*(```|~~~)/.test(lines[i])) {
|
|
1817
|
+
body.push(lines[i]);
|
|
1818
|
+
i++;
|
|
1819
|
+
}
|
|
1820
|
+
i++;
|
|
1821
|
+
out.push(`<pre><code${lang ? ` class="language-${escapeAttr(escapeHtml(lang))}"` : ""}>${escapeHtml(body.join("\n"))}</code></pre>`);
|
|
1822
|
+
continue;
|
|
1823
|
+
}
|
|
1824
|
+
const esc = escapeHtml(line);
|
|
1825
|
+
if (/^\s*$/.test(line)) {
|
|
1826
|
+
flushPara();
|
|
1827
|
+
closeList();
|
|
1828
|
+
i++;
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
const heading = esc.match(/^(#{1,6})\s+(.*)$/);
|
|
1832
|
+
if (heading) {
|
|
1833
|
+
flushPara();
|
|
1834
|
+
closeList();
|
|
1835
|
+
const level = heading[1].length;
|
|
1836
|
+
out.push(`<h${level}>${inline(heading[2])}</h${level}>`);
|
|
1837
|
+
i++;
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
if (/^\s*([-*_])(\s*\1){2,}\s*$/.test(line)) {
|
|
1841
|
+
flushPara();
|
|
1842
|
+
closeList();
|
|
1843
|
+
out.push("<hr>");
|
|
1844
|
+
i++;
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1847
|
+
const quote = esc.match(/^\s*>\s?(.*)$/);
|
|
1848
|
+
if (quote) {
|
|
1849
|
+
flushPara();
|
|
1850
|
+
closeList();
|
|
1851
|
+
out.push(`<blockquote>${inline(quote[1])}</blockquote>`);
|
|
1852
|
+
i++;
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
const ol = esc.match(/^\s*\d+\.\s+(.*)$/);
|
|
1856
|
+
const ul = esc.match(/^\s*[-*+]\s+(.*)$/);
|
|
1857
|
+
if (ol || ul) {
|
|
1858
|
+
flushPara();
|
|
1859
|
+
const type = ol ? "ol" : "ul";
|
|
1860
|
+
if (listType !== type) {
|
|
1861
|
+
closeList();
|
|
1862
|
+
out.push(`<${type}>`);
|
|
1863
|
+
listType = type;
|
|
1864
|
+
}
|
|
1865
|
+
out.push(`<li>${inline((ol ?? ul)[1])}</li>`);
|
|
1866
|
+
i++;
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1869
|
+
closeList();
|
|
1870
|
+
para.push(esc);
|
|
1871
|
+
i++;
|
|
1872
|
+
}
|
|
1873
|
+
flushPara();
|
|
1874
|
+
closeList();
|
|
1875
|
+
return out.join("\n");
|
|
1876
|
+
}
|
|
1865
1877
|
function useCodeEditorInputTagAdapter() {
|
|
1866
1878
|
const ctx = useCodeEditor();
|
|
1867
1879
|
return react.useMemo(() => reactFancy.textareaAdapter(ctx.textareaRef), [ctx.textareaRef]);
|