@nestledjs/forms
Version:
A flexible React form library supporting both declarative and imperative usage patterns with TypeScript support
333 lines (332 loc) • 11.3 kB
JavaScript
import { jsxs as d, Fragment as b, jsx as n } from "react/jsx-runtime";
import W, { Suspense as I, lazy as K, useEffect as G, useCallback as J } from "react";
import { u as Q, c as x, C as Y } from "./index-_yiSpXfV.js";
const f = (o) => async (e) => {
if (o === "base64")
return new Promise((t, r) => {
const i = new FileReader();
i.onload = () => t(i.result), i.onerror = r, i.readAsDataURL(e);
});
throw new Error("Custom image upload handler required for non-base64 mode");
}, ee = async ({
file: o,
maxImageSize: e,
allowedImageTypes: t,
imageUploadHandler: r
}) => {
if (o.size > e)
throw new Error(`Image size must be less than ${Math.round(e / 1024 / 1024)}MB`);
if (!t.includes(o.type))
throw new Error(`Image type must be one of: ${t.join(", ")}`);
return await r(o);
}, oe = async (o) => {
if (o.length > 102400 && (console.warn("Markdown input too large, truncating to prevent DoS"), o = o.substring(0, 102400)), typeof window < "u")
try {
return o.replace(/^### ([^\r\n]{0,200})$/gim, "<h3>$1</h3>").replace(/^## ([^\r\n]{0,200})$/gim, "<h2>$1</h2>").replace(/^# ([^\r\n]{0,200})$/gim, "<h1>$1</h1>").replace(/\*\*([^*\r\n]{1,500}?)\*\*/gim, "<strong>$1</strong>").replace(/\*([^*\r\n]{1,500}?)\*/gim, "<em>$1</em>").replace(/!\[([^\]]{0,200})\]\(([^)\s]{1,500})\)/gim, '<img alt="$1" src="$2" />').replace(/\[([^\]]{0,200})\]\(([^)\s]{1,500})\)/gim, '<a href="$2">$1</a>').replace(/\n$/gim, "<br />");
} catch (t) {
return console.warn("Failed to convert markdown to HTML:", t), o;
}
return o;
}, te = ({
enableImageUpload: o,
UndoRedo: e,
Separator: t,
BoldItalicUnderlineToggles: r,
CodeToggle: i,
ListsToggle: a,
CreateLink: m,
InsertImage: p
}) => /* @__PURE__ */ d(b, { children: [
/* @__PURE__ */ n(e, {}),
/* @__PURE__ */ n(t, {}),
/* @__PURE__ */ n(r, {}),
/* @__PURE__ */ n(i, {}),
/* @__PURE__ */ n(t, {}),
/* @__PURE__ */ n(a, {}),
/* @__PURE__ */ n(t, {}),
/* @__PURE__ */ n(m, {}),
o && /* @__PURE__ */ d(b, { children: [
/* @__PURE__ */ n(t, {}),
/* @__PURE__ */ n(p, {})
] })
] }), C = ({ height: o = 300 }) => /* @__PURE__ */ n(
"div",
{
className: "border border-gray-300 rounded-md p-4 flex items-center justify-center text-gray-500",
style: { minHeight: `${o}px` },
children: "Loading editor..."
}
);
let y = 0;
const ne = (o) => (G(() => {
if (!o || typeof window > "u") return;
const e = "mdx-editor-popup-z-index";
let t = document.getElementById(e);
return y++, t || (t = document.createElement("style"), t.id = e, document.head.appendChild(t)), t.textContent = `
.mdxeditor-popup-container {
z-index: ${o} !important;
}
.mdxeditor .mdxeditor-popup-container * {
z-index: ${o} !important;
}
`, () => {
if (y--, y <= 0) {
const r = document.getElementById(e);
r && document.head.removeChild(r), y = 0;
}
};
}, [o]), o ? {
"--mdx-popup-z-index": o.toString()
} : void 0), ae = (o, e, t, r) => {
const {
headingsPlugin: i,
listsPlugin: a,
quotePlugin: m,
linkPlugin: p,
linkDialogPlugin: g,
imagePlugin: l,
markdownShortcutPlugin: u,
toolbarPlugin: c
} = r, h = [
i(),
a(),
m(),
p(),
g(),
u()
], s = o ? [l({ imageUploadHandler: e })] : [], w = t ? [] : [
c({
toolbarContents: () => te({
enableImageUpload: o,
...r.toolbarComponents
})
})
];
return [...h, ...s, ...w];
}, re = (o, e = "base64", t = 5 * 1024 * 1024, r = ["image/png", "image/jpeg", "image/gif", "image/webp"]) => {
const i = o || f(e);
return async (a) => ee({
file: a,
maxImageSize: t,
allowedImageTypes: r,
imageUploadHandler: i
});
}, ie = (o, e, t) => J(
async (r) => {
if (o(r), (e === "html" || e === "both") && t)
try {
const i = await oe(r);
t(i);
} catch (i) {
console.warn("Failed to convert markdown to HTML:", i);
}
},
[o, t, e]
), se = (o) => {
const {
MDXEditor: e,
toolbarPlugin: t,
listsPlugin: r,
quotePlugin: i,
headingsPlugin: a,
linkPlugin: m,
linkDialogPlugin: p,
imagePlugin: g,
markdownShortcutPlugin: l,
UndoRedo: u,
BoldItalicUnderlineToggles: c,
CodeToggle: h,
CreateLink: s,
InsertImage: w,
ListsToggle: v,
Separator: P
} = o, U = {
headingsPlugin: a,
listsPlugin: r,
quotePlugin: i,
linkPlugin: m,
linkDialogPlugin: p,
imagePlugin: g,
markdownShortcutPlugin: l,
toolbarPlugin: t,
toolbarComponents: {
UndoRedo: u,
Separator: P,
BoldItalicUnderlineToggles: c,
CodeToggle: h,
ListsToggle: v,
CreateLink: s,
InsertImage: w
}
};
return W.forwardRef((T, _) => {
const {
value: $,
onChange: N,
onBlur: M,
placeholder: H,
readOnly: E = !1,
className: S,
enableImageUpload: L = !1,
imageUploadHandler: z,
maxImageSize: F = 5 * 1024 * 1024,
allowedImageTypes: D = ["image/png", "image/jpeg", "image/gif", "image/webp"],
imageUploadMode: O = "base64",
outputFormat: j = "markdown",
onHtmlChange: R,
overlayContainer: X,
popupZIndex: q
} = T, B = ne(q), Z = ie(N, j, R), A = re(
z,
O,
F,
D
), V = ae(L, A, E, U);
return /* @__PURE__ */ n("div", { style: B, children: /* @__PURE__ */ n(
e,
{
ref: _,
markdown: $ || "",
onChange: Z,
onBlur: M,
plugins: V,
readOnly: E,
placeholder: H,
className: S,
overlayContainer: X
}
) });
});
}, k = K(
() => import("@mdxeditor/editor").then((o) => {
const e = se(o);
return e.displayName = "SimpleEditor", { default: e };
})
);
function ce({
form: o,
field: e,
hasError: t,
formReadOnly: r = !1,
formReadOnlyStyle: i = "value"
}) {
const a = Q(), m = `${e.key}_html`, p = e.options.readOnly ?? r, g = e.options.readOnlyStyle ?? i;
if (p) {
const l = o.getValues(e.key) ?? "";
return g === "disabled" ? /* @__PURE__ */ d(b, { children: [
/* @__PURE__ */ d(
"div",
{
className: x(
a.markdownEditor.editor,
a.markdownEditor.disabled,
t && a.markdownEditor.error
),
children: [
/* @__PURE__ */ n("div", { className: a.markdownEditor.toolbar, children: /* @__PURE__ */ n("span", { className: "text-sm text-gray-500", children: "Markdown Editor (Disabled)" }) }),
/* @__PURE__ */ n(
"div",
{
className: x(
a.markdownEditor.preview,
"opacity-50 min-h-[200px] p-4 font-mono text-sm whitespace-pre-wrap"
),
children: l ?? "—"
}
)
]
}
),
e.options.helpText && /* @__PURE__ */ n("div", { className: a.markdownEditor.helpText, children: e.options.helpText })
] }) : /* @__PURE__ */ d(b, { children: [
/* @__PURE__ */ n("div", { className: x(a.markdownEditor.readOnlyValue), children: /* @__PURE__ */ n(I, { fallback: /* @__PURE__ */ n(C, { height: 200 }), children: /* @__PURE__ */ n(
k,
{
value: l,
onChange: () => {
},
readOnly: !0,
className: "border-none bg-transparent prose prose-sm max-w-none [&_.mdxeditor-root-contenteditable]:list-decimal [&_.mdxeditor-root-contenteditable]:list-inside [&_.mdxeditor-root-contenteditable_ul]:list-disc [&_.mdxeditor-root-contenteditable_ol]:list-decimal",
enableImageUpload: e.options.enableImageUpload,
imageUploadHandler: e.options.imageUploadHandler,
maxImageSize: e.options.maxImageSize,
allowedImageTypes: e.options.allowedImageTypes,
imageUploadMode: e.options.imageUploadMode,
outputFormat: e.options.outputFormat,
onHtmlChange: e.options.onHtmlChange,
overlayContainer: e.options.overlayContainer,
popupZIndex: e.options.popupZIndex
}
) }) }),
e.options.helpText && /* @__PURE__ */ n("div", { className: a.markdownEditor.helpText, children: e.options.helpText })
] });
}
return /* @__PURE__ */ n(
Y,
{
control: o.control,
name: e.key,
defaultValue: e.options.defaultValue ?? "",
rules: {
required: e.options.required,
maxLength: e.options.maxLength ? {
value: e.options.maxLength,
message: `Content must be less than ${e.options.maxLength} characters`
} : void 0
},
render: ({ field: { onChange: l, onBlur: u, value: c, ref: h } }) => /* @__PURE__ */ d("div", { className: a.markdownEditor.wrapper, children: [
/* @__PURE__ */ n(I, { fallback: /* @__PURE__ */ n(C, { height: e.options.height ?? 300 }), children: /* @__PURE__ */ d(
"div",
{
className: x(
a.markdownEditor.editor,
t && a.markdownEditor.error,
e.options.disabled && a.markdownEditor.disabled
),
style: { minHeight: `${e.options.height ?? 300}px` },
children: [
/* @__PURE__ */ n(
k,
{
ref: h,
value: c ?? "",
onChange: (s) => {
e.options.maxLength && s.length > e.options.maxLength || l(s);
},
onBlur: u,
placeholder: e.options.placeholder,
readOnly: e.options.disabled,
className: "w-full prose prose-sm max-w-none [&_.mdxeditor-root-contenteditable]:list-decimal [&_.mdxeditor-root-contenteditable]:list-inside [&_.mdxeditor-root-contenteditable_ul]:list-disc [&_.mdxeditor-root-contenteditable_ol]:list-decimal",
enableImageUpload: e.options.enableImageUpload,
imageUploadHandler: e.options.imageUploadHandler,
maxImageSize: e.options.maxImageSize,
allowedImageTypes: e.options.allowedImageTypes,
imageUploadMode: e.options.imageUploadMode,
outputFormat: e.options.outputFormat,
overlayContainer: e.options.overlayContainer,
popupZIndex: e.options.popupZIndex,
onHtmlChange: (s) => {
e.options.outputFormat === "both" && o.setValue(m, s), e.options.onHtmlChange && e.options.onHtmlChange(s);
}
}
),
e.options.maxLength && /* @__PURE__ */ d("div", { className: "text-sm text-gray-500 mt-1 text-right", children: [
c?.length ?? 0,
"/",
e.options.maxLength
] })
]
}
) }),
e.options.helpText && /* @__PURE__ */ n("div", { className: a.markdownEditor.helpText, children: e.options.helpText })
] })
}
);
}
export {
ce as MarkdownEditor,
f as defaultImageUploadHandler,
ee as handleImageUpload,
oe as markdownToHtml,
te as toolbarContents
};