@particle-academy/react-fancy 4.7.1 → 4.8.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 +101 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +101 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -11443,12 +11443,12 @@ function htmlToMarkdown(html) {
|
|
|
11443
11443
|
md = md.replace(/<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, (match, tagName) => {
|
|
11444
11444
|
return STANDARD_HTML_TAGS.has(tagName.toLowerCase()) ? "" : match;
|
|
11445
11445
|
});
|
|
11446
|
-
md = md.replace(/&/g, "&");
|
|
11447
11446
|
md = md.replace(/</g, "<");
|
|
11448
11447
|
md = md.replace(/>/g, ">");
|
|
11449
11448
|
md = md.replace(/"/g, '"');
|
|
11450
11449
|
md = md.replace(/'/g, "'");
|
|
11451
11450
|
md = md.replace(/ /g, " ");
|
|
11451
|
+
md = md.replace(/&/g, "&");
|
|
11452
11452
|
md = md.replace(/\n{3,}/g, "\n\n");
|
|
11453
11453
|
md = md.trim();
|
|
11454
11454
|
return md;
|
|
@@ -11591,6 +11591,71 @@ function mergeExtensions(instanceExtensions) {
|
|
|
11591
11591
|
}
|
|
11592
11592
|
return merged;
|
|
11593
11593
|
}
|
|
11594
|
+
function RenderedContent({
|
|
11595
|
+
html,
|
|
11596
|
+
extensions: instanceExtensions,
|
|
11597
|
+
unsafe = false
|
|
11598
|
+
}) {
|
|
11599
|
+
const extensions = react.useMemo(
|
|
11600
|
+
() => mergeExtensions(instanceExtensions),
|
|
11601
|
+
[instanceExtensions]
|
|
11602
|
+
);
|
|
11603
|
+
const segments = react.useMemo(
|
|
11604
|
+
() => parseSegments(html, extensions),
|
|
11605
|
+
[html, extensions]
|
|
11606
|
+
);
|
|
11607
|
+
const renderHtml = (content) => unsafe ? content : sanitizeHtml(content);
|
|
11608
|
+
if (segments.length === 1 && segments[0].type === "html") {
|
|
11609
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segments[0].content) } });
|
|
11610
|
+
}
|
|
11611
|
+
if (segments.length === 0) {
|
|
11612
|
+
return null;
|
|
11613
|
+
}
|
|
11614
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, i) => {
|
|
11615
|
+
if (segment.type === "html") {
|
|
11616
|
+
return segment.content ? /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segment.content) } }, i) : null;
|
|
11617
|
+
}
|
|
11618
|
+
const ext = extensions.find(
|
|
11619
|
+
(e) => e.tag.toLowerCase() === segment.tag
|
|
11620
|
+
);
|
|
11621
|
+
if (!ext) return null;
|
|
11622
|
+
const Component = ext.component;
|
|
11623
|
+
const isBlock = ext.block !== false;
|
|
11624
|
+
const Wrapper = isBlock ? "div" : "span";
|
|
11625
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { "data-render-extension": segment.tag, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { content: segment.content, attributes: segment.attributes }) }, i);
|
|
11626
|
+
}) });
|
|
11627
|
+
}
|
|
11628
|
+
RenderedContent.displayName = "RenderedContent";
|
|
11629
|
+
function ContentRenderer({
|
|
11630
|
+
value,
|
|
11631
|
+
format = "auto",
|
|
11632
|
+
lineSpacing = 1.6,
|
|
11633
|
+
className,
|
|
11634
|
+
extensions: instanceExtensions,
|
|
11635
|
+
unsafe = false
|
|
11636
|
+
}) {
|
|
11637
|
+
const extensions = react.useMemo(
|
|
11638
|
+
() => mergeExtensions(instanceExtensions),
|
|
11639
|
+
[instanceExtensions]
|
|
11640
|
+
);
|
|
11641
|
+
const html = react.useMemo(() => {
|
|
11642
|
+
const safe = value ?? "";
|
|
11643
|
+
const resolvedFormat = format === "auto" ? detectFormat(safe) : format;
|
|
11644
|
+
const raw = resolvedFormat === "markdown" ? marked.marked.parse(safe, { async: false }) : safe;
|
|
11645
|
+
return unsafe ? raw : sanitizeHtml(raw);
|
|
11646
|
+
}, [value, format, unsafe]);
|
|
11647
|
+
const hasExtensions = extensions.length > 0;
|
|
11648
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11649
|
+
"div",
|
|
11650
|
+
{
|
|
11651
|
+
"data-react-fancy-content-renderer": "",
|
|
11652
|
+
style: { lineHeight: lineSpacing },
|
|
11653
|
+
className: cn("text-sm", proseClasses, className),
|
|
11654
|
+
children: hasExtensions ? /* @__PURE__ */ jsxRuntime.jsx(RenderedContent, { html, extensions, unsafe }) : /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: html } })
|
|
11655
|
+
}
|
|
11656
|
+
);
|
|
11657
|
+
}
|
|
11658
|
+
ContentRenderer.displayName = "ContentRenderer";
|
|
11594
11659
|
function toHtml(value, outputFormat, unsafe) {
|
|
11595
11660
|
if (!value) return "";
|
|
11596
11661
|
const raw = (() => {
|
|
@@ -11610,16 +11675,22 @@ function EditorRoot({
|
|
|
11610
11675
|
outputFormat = "html",
|
|
11611
11676
|
lineSpacing = 1.6,
|
|
11612
11677
|
placeholder,
|
|
11678
|
+
mode: modeProp,
|
|
11613
11679
|
extensions: instanceExtensions,
|
|
11614
11680
|
unsafe = false
|
|
11615
11681
|
}) {
|
|
11616
11682
|
const contentRef = react.useRef(null);
|
|
11617
|
-
const [, setValue] = useControllableState(controlledValue, defaultValue, onChange);
|
|
11683
|
+
const [value, setValue] = useControllableState(controlledValue, defaultValue, onChange);
|
|
11684
|
+
const mode = useFieldMode(modeProp);
|
|
11685
|
+
const isView = mode === "view";
|
|
11618
11686
|
const initialHtml = react.useMemo(
|
|
11619
|
-
() => toHtml(
|
|
11620
|
-
//
|
|
11687
|
+
() => toHtml(value, outputFormat, unsafe),
|
|
11688
|
+
// Seed the contentEditable from the LIVE value when (re)entering edit mode.
|
|
11689
|
+
// EditorContent reads this once on mount, and it only mounts in edit mode —
|
|
11690
|
+
// so this captures the current value on view→edit, not a stale mount snapshot,
|
|
11691
|
+
// and does NOT re-run on every keystroke.
|
|
11621
11692
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
11622
|
-
[]
|
|
11693
|
+
[isView, outputFormat, unsafe]
|
|
11623
11694
|
);
|
|
11624
11695
|
const extensions = react.useMemo(
|
|
11625
11696
|
() => mergeExtensions(instanceExtensions),
|
|
@@ -11682,10 +11753,35 @@ function EditorRoot({
|
|
|
11682
11753
|
_initialHtml: initialHtml,
|
|
11683
11754
|
_onInput: handleInput
|
|
11684
11755
|
};
|
|
11756
|
+
if (isView) {
|
|
11757
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11758
|
+
"div",
|
|
11759
|
+
{
|
|
11760
|
+
"data-react-fancy-editor": "",
|
|
11761
|
+
"data-mode": "view",
|
|
11762
|
+
className: cn(
|
|
11763
|
+
"overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900",
|
|
11764
|
+
className
|
|
11765
|
+
),
|
|
11766
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11767
|
+
ContentRenderer,
|
|
11768
|
+
{
|
|
11769
|
+
value,
|
|
11770
|
+
format: outputFormat,
|
|
11771
|
+
lineSpacing,
|
|
11772
|
+
extensions: instanceExtensions,
|
|
11773
|
+
unsafe,
|
|
11774
|
+
className: "px-4 py-3"
|
|
11775
|
+
}
|
|
11776
|
+
)
|
|
11777
|
+
}
|
|
11778
|
+
);
|
|
11779
|
+
}
|
|
11685
11780
|
return /* @__PURE__ */ jsxRuntime.jsx(EditorContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11686
11781
|
"div",
|
|
11687
11782
|
{
|
|
11688
11783
|
"data-react-fancy-editor": "",
|
|
11784
|
+
"data-mode": "edit",
|
|
11689
11785
|
className: cn(
|
|
11690
11786
|
"overflow-hidden rounded-xl border border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900",
|
|
11691
11787
|
className
|
|
@@ -11701,71 +11797,6 @@ var Editor = Object.assign(EditorRoot, {
|
|
|
11701
11797
|
Toolbar: ToolbarWithSeparator,
|
|
11702
11798
|
Content: EditorContent
|
|
11703
11799
|
});
|
|
11704
|
-
function RenderedContent({
|
|
11705
|
-
html,
|
|
11706
|
-
extensions: instanceExtensions,
|
|
11707
|
-
unsafe = false
|
|
11708
|
-
}) {
|
|
11709
|
-
const extensions = react.useMemo(
|
|
11710
|
-
() => mergeExtensions(instanceExtensions),
|
|
11711
|
-
[instanceExtensions]
|
|
11712
|
-
);
|
|
11713
|
-
const segments = react.useMemo(
|
|
11714
|
-
() => parseSegments(html, extensions),
|
|
11715
|
-
[html, extensions]
|
|
11716
|
-
);
|
|
11717
|
-
const renderHtml = (content) => unsafe ? content : sanitizeHtml(content);
|
|
11718
|
-
if (segments.length === 1 && segments[0].type === "html") {
|
|
11719
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segments[0].content) } });
|
|
11720
|
-
}
|
|
11721
|
-
if (segments.length === 0) {
|
|
11722
|
-
return null;
|
|
11723
|
-
}
|
|
11724
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: segments.map((segment, i) => {
|
|
11725
|
-
if (segment.type === "html") {
|
|
11726
|
-
return segment.content ? /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: renderHtml(segment.content) } }, i) : null;
|
|
11727
|
-
}
|
|
11728
|
-
const ext = extensions.find(
|
|
11729
|
-
(e) => e.tag.toLowerCase() === segment.tag
|
|
11730
|
-
);
|
|
11731
|
-
if (!ext) return null;
|
|
11732
|
-
const Component = ext.component;
|
|
11733
|
-
const isBlock = ext.block !== false;
|
|
11734
|
-
const Wrapper = isBlock ? "div" : "span";
|
|
11735
|
-
return /* @__PURE__ */ jsxRuntime.jsx(Wrapper, { "data-render-extension": segment.tag, children: /* @__PURE__ */ jsxRuntime.jsx(Component, { content: segment.content, attributes: segment.attributes }) }, i);
|
|
11736
|
-
}) });
|
|
11737
|
-
}
|
|
11738
|
-
RenderedContent.displayName = "RenderedContent";
|
|
11739
|
-
function ContentRenderer({
|
|
11740
|
-
value,
|
|
11741
|
-
format = "auto",
|
|
11742
|
-
lineSpacing = 1.6,
|
|
11743
|
-
className,
|
|
11744
|
-
extensions: instanceExtensions,
|
|
11745
|
-
unsafe = false
|
|
11746
|
-
}) {
|
|
11747
|
-
const extensions = react.useMemo(
|
|
11748
|
-
() => mergeExtensions(instanceExtensions),
|
|
11749
|
-
[instanceExtensions]
|
|
11750
|
-
);
|
|
11751
|
-
const html = react.useMemo(() => {
|
|
11752
|
-
const safe = value ?? "";
|
|
11753
|
-
const resolvedFormat = format === "auto" ? detectFormat(safe) : format;
|
|
11754
|
-
const raw = resolvedFormat === "markdown" ? marked.marked.parse(safe, { async: false }) : safe;
|
|
11755
|
-
return unsafe ? raw : sanitizeHtml(raw);
|
|
11756
|
-
}, [value, format, unsafe]);
|
|
11757
|
-
const hasExtensions = extensions.length > 0;
|
|
11758
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11759
|
-
"div",
|
|
11760
|
-
{
|
|
11761
|
-
"data-react-fancy-content-renderer": "",
|
|
11762
|
-
style: { lineHeight: lineSpacing },
|
|
11763
|
-
className: cn("text-sm", proseClasses, className),
|
|
11764
|
-
children: hasExtensions ? /* @__PURE__ */ jsxRuntime.jsx(RenderedContent, { html, extensions, unsafe }) : /* @__PURE__ */ jsxRuntime.jsx("div", { dangerouslySetInnerHTML: { __html: html } })
|
|
11765
|
-
}
|
|
11766
|
-
);
|
|
11767
|
-
}
|
|
11768
|
-
ContentRenderer.displayName = "ContentRenderer";
|
|
11769
11800
|
var MenuContext = react.createContext(null);
|
|
11770
11801
|
function useMenu() {
|
|
11771
11802
|
const ctx = react.useContext(MenuContext);
|