import { ColorSchemeProvider, FootnoteDefinitionsProvider, LinkFavicon, NestedContentRendererProvider, RendererConfigProvider, RendererWrapper, RubyRenderer, allNodes, detailsClassNames, detailsStyles, editorTheme, getTagBgColor, getVariantClass, gridClassNames, gridStyles, normalizeSerializedEditorState, semanticClassNames, sharedStyles, useOptionalNestedContentRenderer } from "@haklex/rich-editor/static";
import { Fragment, Suspense, cloneElement, createElement, isValidElement, lazy, memo, useCallback, useEffect, useMemo, useRef } from "react";
import { PortalThemeProvider } from "@haklex/rich-style-token";
import { createHeadlessEditor } from "@lexical/headless";
import { $getRoot } from "lexical";
import { Link } from "lucide-react";
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
//#region src/static-renderer/components/HtmlComment.tsx
function HtmlComment({ text }) {
	const anchorRef = useRef(null);
	const commentRef = useRef(null);
	useEffect(() => {
		const anchor = anchorRef.current;
		if (!anchor) return;
		const parent = anchor.parentNode;
		if (!parent) return;
		let comment = commentRef.current;
		if (!comment || comment.parentNode !== parent) {
			comment = document.createComment(text);
			parent.insertBefore(comment, anchor);
			commentRef.current = comment;
		} else if (comment.data !== text) comment.data = text;
		return () => {
			if (commentRef.current?.parentNode) commentRef.current.parentNode.removeChild(commentRef.current);
			commentRef.current = null;
		};
	}, [text]);
	return /* @__PURE__ */ jsx("template", {
		suppressHydrationWarning: true,
		"data-rich-comment-anchor": "",
		ref: anchorRef
	});
}
//#endregion
//#region src/static-renderer/table.css.ts
var tableWrapper = "icqzyn0";
var table = "icqzyn1";
var tableHead = "icqzyn2";
var tableCell = "icqzyn3";
//#endregion
//#region src/static-renderer/engine/renderBuiltinNode.tsx
var shared$1 = (key) => `${semanticClassNames[key]} ${sharedStyles[key]}`;
var headingClassNames = {
	h1: shared$1("headingH1"),
	h2: shared$1("headingH2"),
	h3: shared$1("headingH3"),
	h4: shared$1("headingH4"),
	h5: shared$1("headingH5"),
	h6: shared$1("headingH6")
};
function textToSlug(text) {
	return text.toLowerCase().trim().replaceAll(/[^\s\w\u3000-\u9FFF\uAC00-\uD7AF\uFF00-\uFFEF-]/g, "").replaceAll(/[\s_]+/g, "-").replaceAll(/^-+|-+$/g, "");
}
function extractText(node) {
	if (node.type === "comment") return "";
	if (node.text) return node.text;
	if (node.children) return node.children.map(extractText).join("");
	return "";
}
var OPEN_QUOTE_RE = /^["'«‘“‹「『＂＇]/;
var CLOSE_QUOTE_RE = /["'»’”›」』＂＇]$/;
function renderBuiltinNode(node, key, children, headingSlugs, textContent) {
	switch (node.type) {
		case "root": return /* @__PURE__ */ jsx(Fragment$1, { children });
		case "paragraph": {
			const align = node.format ? { textAlign: node.format } : void 0;
			return /* @__PURE__ */ jsx("p", {
				className: shared$1("paragraph"),
				style: align,
				children
			}, key);
		}
		case "heading": {
			const Tag = node.tag;
			const baseSlug = textToSlug(textContent || extractText(node));
			let slug = baseSlug;
			if (baseSlug) {
				const count = headingSlugs.get(baseSlug);
				if (count !== void 0) {
					slug = `${baseSlug}-${count}`;
					headingSlugs.set(baseSlug, count + 1);
				} else headingSlugs.set(baseSlug, 1);
			}
			return /* @__PURE__ */ jsxs(Tag, {
				className: headingClassNames[Tag],
				id: slug || void 0,
				children: [slug && /* @__PURE__ */ jsx("a", {
					className: shared$1("headingAnchor"),
					href: `#${slug}`,
					tabIndex: 0,
					children: /* @__PURE__ */ jsx(Link, {
						"aria-hidden": true,
						size: 14,
						strokeWidth: 2
					})
				}), children]
			}, key);
		}
		case "rich-quote":
		case "quote": {
			const quoteText = (textContent || extractText(node)).trim();
			const hasOpenQuote = OPEN_QUOTE_RE.test(quoteText);
			const hasCloseQuote = CLOSE_QUOTE_RE.test(quoteText);
			const attribution = node.attribution;
			return /* @__PURE__ */ jsxs("blockquote", {
				className: shared$1("quote"),
				"data-no-close-quote": hasCloseQuote ? "" : void 0,
				"data-no-open-quote": hasOpenQuote ? "" : void 0,
				children: [children, attribution && /* @__PURE__ */ jsxs("footer", {
					className: shared$1("quoteAttribution"),
					children: ["— ", attribution]
				})]
			}, key);
		}
		case "list": return /* @__PURE__ */ jsx(node.listType === "number" ? "ol" : "ul", {
			className: node.listType === "number" ? shared$1("listOl") : node.listType === "check" ? `${shared$1("checklist")} ${shared$1("listUl")}` : shared$1("listUl"),
			start: node.start !== 1 ? node.start : void 0,
			children
		}, key);
		case "listitem": {
			const isChecklist = node.checked !== void 0;
			const hasNestedList = node.children?.some((c) => c.type === "list");
			const value = typeof node.value === "number" && node.value > 1 ? node.value : void 0;
			let cls;
			if (hasNestedList) cls = shared$1("listNestedItem");
			else if (isChecklist) cls = node.checked ? `${shared$1("listItem")} ${shared$1("listItemChecked")}` : `${shared$1("listItem")} ${shared$1("listItemUnchecked")}`;
			else cls = shared$1("listItem");
			return /* @__PURE__ */ jsx("li", {
				className: cls,
				value,
				children
			}, key);
		}
		case "link": return /* @__PURE__ */ jsxs("a", {
			className: shared$1("link"),
			href: node.url,
			rel: node.rel || "noopener",
			target: node.target || "_blank",
			children: [/* @__PURE__ */ jsx(LinkFavicon, { href: node.url }), children]
		}, key);
		case "autolink": return /* @__PURE__ */ jsxs("a", {
			className: shared$1("link"),
			href: node.url,
			rel: "noopener",
			target: "_blank",
			children: [/* @__PURE__ */ jsx(LinkFavicon, { href: node.url }), children]
		}, key);
		case "horizontalrule": return /* @__PURE__ */ jsx("hr", { className: shared$1("hr") }, key);
		case "table": return /* @__PURE__ */ jsx("div", {
			className: tableWrapper,
			children: /* @__PURE__ */ jsx("table", {
				className: table,
				children
			})
		}, key);
		case "tablerow": return /* @__PURE__ */ jsx("tr", { children }, key);
		case "tablecell": return /* @__PURE__ */ jsx(node.headerState ? "th" : "td", {
			className: node.headerState ? tableHead : tableCell,
			colSpan: node.colSpan > 1 ? node.colSpan : void 0,
			children
		}, key);
		case "details": {
			const summary = node.summary || "";
			return /* @__PURE__ */ jsxs("details", {
				className: `${detailsClassNames.details} ${detailsStyles.details}`,
				open: node.open || void 0,
				children: [/* @__PURE__ */ jsxs("summary", {
					className: `${detailsClassNames.summary} ${detailsStyles.summary}`,
					children: [/* @__PURE__ */ jsx("span", {
						"aria-hidden": "true",
						className: `${detailsClassNames.chevron} ${detailsStyles.chevron}`,
						children: /* @__PURE__ */ jsx("svg", {
							fill: "none",
							height: "20",
							stroke: "currentColor",
							strokeLinecap: "round",
							strokeLinejoin: "round",
							strokeWidth: "1.5",
							viewBox: "0 0 20 20",
							width: "20",
							children: /* @__PURE__ */ jsx("path", { d: "M8 6L12 10L8 14" })
						})
					}), /* @__PURE__ */ jsx("span", {
						className: `${detailsClassNames.summaryText} ${detailsStyles.summaryText}`,
						children: summary
					})]
				}), /* @__PURE__ */ jsx("div", {
					className: `${detailsClassNames.content} ${detailsStyles.content}`,
					children
				})]
			}, key);
		}
		case "spoiler": return /* @__PURE__ */ jsx("span", {
			className: shared$1("spoiler"),
			role: "button",
			tabIndex: 0,
			children
		}, key);
		case "tag": return /* @__PURE__ */ jsx("span", {
			className: shared$1("tag"),
			style: { backgroundColor: getTagBgColor(node.text) },
			children: node.text
		}, key);
		case "comment": return /* @__PURE__ */ jsx(HtmlComment, { text: node.text ?? "" }, key);
		case "ruby": return createElement(RendererWrapper, {
			key,
			rendererKey: "Ruby",
			defaultRenderer: RubyRenderer,
			props: {
				reading: node.reading ?? "",
				children
			}
		});
		case "code": return /* @__PURE__ */ jsx("pre", {
			className: "rich-code-block",
			children: /* @__PURE__ */ jsx("code", { children })
		}, key);
		case "code-highlight": return /* @__PURE__ */ jsx("span", { children: node.text }, key);
		case "linebreak": return /* @__PURE__ */ jsx("br", {}, key);
		case "tab": return /* @__PURE__ */ jsx("span", { children: "  " }, key);
		default: return null;
	}
}
//#endregion
//#region src/static-renderer/engine/renderTextNode.tsx
var shared = (key) => `${semanticClassNames[key]} ${sharedStyles[key]}`;
var FORMAT_FLAGS = [
	[1, "textBold"],
	[2, "textItalic"],
	[4, "textStrikethrough"],
	[8, "textUnderline"],
	[16, "textCode"],
	[32, "textSubscript"],
	[64, "textSuperscript"],
	[128, "textHighlight"]
];
function parseCSSText(cssText) {
	const style = {};
	for (const part of cssText.split(";")) {
		const colonIndex = part.indexOf(":");
		if (colonIndex === -1) continue;
		const prop = part.slice(0, colonIndex).trim();
		const value = part.slice(colonIndex + 1).trim();
		if (!prop || !value) continue;
		const camelProp = prop.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
		style[camelProp] = value;
	}
	return style;
}
function renderTextNode(node, key) {
	let element = node.text;
	const format = node.format || 0;
	for (const [flag, styleKey] of FORMAT_FLAGS) if (format & flag) element = /* @__PURE__ */ jsx("span", {
		className: shared(styleKey),
		children: element
	}, `${key}-${flag}`);
	if (node.style) element = /* @__PURE__ */ jsx("span", {
		style: parseCSSText(node.style),
		children: element
	}, key);
	return element;
}
//#endregion
//#region src/static-renderer/preprocess/footnote.ts
function preprocessFootnotes(state) {
	const definitions = {};
	const seen = /* @__PURE__ */ new Set();
	const displayNumberMap = {};
	let counter = 1;
	function walk(node) {
		if (node.type === "footnote" && node.identifier) {
			const id = node.identifier;
			if (!seen.has(id)) {
				seen.add(id);
				displayNumberMap[id] = counter++;
			}
		}
		if (node.type === "footnote-section" && node.definitions) Object.assign(definitions, node.definitions);
		if (node.children) for (const child of node.children) walk(child);
		if (node.root) walk(node.root);
		if (node.content && typeof node.content === "object" && node.content.root) walk(node.content);
		if (node.cells && Array.isArray(node.cells)) {
			for (const cell of node.cells) if (cell && cell.root) walk(cell);
		}
	}
	walk(state);
	for (const id of seen) if (!(id in definitions)) definitions[id] = "";
	return {
		definitions,
		displayNumberMap
	};
}
//#endregion
//#region src/static-renderer/RichRenderer.tsx
var alertClassName = (type) => `${semanticClassNames.alert} ${sharedStyles.alert} rich-alert-${type}`;
function wrapDecoration(serialized, key, decoration) {
	switch (serialized.type) {
		case "alert-quote": return createElement("div", {
			key,
			className: alertClassName(serialized.alertType)
		}, decoration);
		case "banner": return createElement("div", {
			key,
			className: `rich-banner rich-banner-${serialized.bannerType}`
		}, decoration);
		case "grid-container": return createElement("div", {
			key,
			className: `${gridClassNames.container} ${gridStyles.container}`
		}, decoration);
		default:
			if (isValidElement(decoration)) return cloneElement(decoration, { key });
			return decoration;
	}
}
function applyBlockId(element, blockId, nodeKey) {
	if (!blockId) return element;
	if (isValidElement(element) && typeof element.type === "string") return cloneElement(element, { "data-block-id": blockId });
	return /* @__PURE__ */ jsx("div", {
		className: "rich-block-anchor",
		"data-block-id": blockId,
		children: element
	}, `${nodeKey}-block-anchor`);
}
function renderTree(node, editor, editorConfig, headingSlugs, key, blockId, builtinNodeOverrides) {
	const nodeKey = node.getKey ? node.getKey() : key;
	if (typeof node.decorate === "function") try {
		const decoration = node.decorate(editor, editorConfig);
		if (decoration != null) return applyBlockId(wrapDecoration(node.exportJSON ? node.exportJSON() : {}, nodeKey, decoration), blockId, nodeKey);
	} catch {}
	const serialized = node.exportJSON ? node.exportJSON() : {};
	if (serialized.type === "text") return renderTextNode(serialized, nodeKey);
	const childNodes = typeof node.getChildren === "function" ? node.getChildren() : [];
	if (Array.isArray(serialized.children) && serialized.children.length === 0 && childNodes.length > 0) serialized.children = childNodes.map((c) => ({ type: typeof c.getType === "function" ? c.getType() : c.__type }));
	let children = null;
	if (childNodes.length > 0) children = childNodes.map((child, i) => renderTree(child, editor, editorConfig, headingSlugs, `${nodeKey}-${i}`, void 0, builtinNodeOverrides));
	const textContent = node.getTextContent ? node.getTextContent() : void 0;
	const override = builtinNodeOverrides?.[serialized.type];
	if (override) {
		const defaultRenderer = () => renderBuiltinNode(serialized, nodeKey, children, headingSlugs, textContent);
		return applyBlockId(override(serialized, nodeKey, children, defaultRenderer), blockId, nodeKey);
	}
	return applyBlockId(renderBuiltinNode(serialized, nodeKey, children, headingSlugs, textContent), blockId, nodeKey);
}
function renderEditorToReact(value, nodes, builtinNodeOverrides) {
	const editor = createHeadlessEditor({
		nodes,
		theme: editorTheme,
		editable: false,
		onError: (error) => {
			console.error("[RichRenderer]", error);
		}
	});
	const editorConfig = {
		namespace: "ssr",
		theme: editorTheme
	};
	const normalizedValue = normalizeSerializedEditorState(value);
	const editorState = editor.parseEditorState(normalizedValue);
	editor.setEditorState(editorState);
	const footnoteData = preprocessFootnotes(normalizedValue);
	const rawRootChildren = normalizedValue.root?.children;
	let content = null;
	editorState.read(() => {
		const root = $getRoot();
		const headingSlugs = /* @__PURE__ */ new Map();
		content = /* @__PURE__ */ jsx(Fragment$1, { children: root.getChildren().map((child, i) => renderTree(child, editor, editorConfig, headingSlugs, `ssr-${i}`, rawRootChildren?.[i]?.$?.blockId, builtinNodeOverrides)) });
	});
	const renderNestedContent = (state) => {
		const nestedEditor = createHeadlessEditor({
			nodes,
			theme: editorTheme,
			editable: false,
			onError: (error) => {
				console.error("[RichRenderer:nested]", error);
			}
		});
		const nestedEditorConfig = {
			namespace: "ssr-nested",
			theme: editorTheme
		};
		const normalizedState = normalizeSerializedEditorState(state);
		const nestedState = nestedEditor.parseEditorState(normalizedState);
		nestedEditor.setEditorState(nestedState);
		let nested = null;
		const nestedRawChildren = normalizedState.root?.children;
		nestedState.read(() => {
			const root = $getRoot();
			const headingSlugs = /* @__PURE__ */ new Map();
			nested = /* @__PURE__ */ jsx(Fragment$1, { children: root.getChildren().map((child, i) => renderTree(child, nestedEditor, nestedEditorConfig, headingSlugs, `nested-${i}`, nestedRawChildren?.[i]?.$?.blockId, builtinNodeOverrides)) });
		});
		return nested;
	};
	return {
		content,
		footnoteData,
		renderNestedContent
	};
}
function RichRenderer({ value, variant = "article", theme = "light", className, style, as: Component = "div", nested = false, rendererConfig, extraNodes, builtinNodeOverrides }) {
	const variantClass = getVariantClass(variant);
	const outerRenderNestedContent = useOptionalNestedContentRenderer();
	const { content, footnoteData, renderNestedContent } = useMemo(() => {
		return renderEditorToReact(value, extraNodes ? [...allNodes, ...extraNodes] : allNodes, builtinNodeOverrides);
	}, [
		builtinNodeOverrides,
		extraNodes,
		value
	]);
	const classes = [
		"rich-content",
		variantClass,
		className
	].filter(Boolean).join(" ");
	return /* @__PURE__ */ jsx(PortalThemeProvider, {
		className: variantClass,
		theme,
		children: /* @__PURE__ */ jsx(ColorSchemeProvider, {
			colorScheme: theme,
			children: /* @__PURE__ */ jsx(RendererConfigProvider, {
				config: rendererConfig,
				mode: "renderer",
				variant,
				children: /* @__PURE__ */ jsx(FootnoteDefinitionsProvider, {
					definitions: footnoteData.definitions,
					displayNumberMap: footnoteData.displayNumberMap,
					children: /* @__PURE__ */ jsx(NestedContentRendererProvider, {
						value: outerRenderNestedContent ?? renderNestedContent,
						children: /* @__PURE__ */ jsx(Component, {
							suppressHydrationWarning: true,
							className: classes,
							"data-rich-nested": nested ? "true" : void 0,
							"data-theme": theme,
							style,
							children: content
						})
					})
				})
			})
		})
	});
}
//#endregion
//#region src/core/dedup.ts
/**
* Merge preset and modules, deduplicating by:
*   1. Same module reference → skip silently (idempotent)
*   2. Same module.name → replace previous module entirely; warn in dev
*   3. Else → append
*/
function mergeModules(preset, modules) {
	const all = [...preset ?? [], ...modules ?? []];
	const refSeen = /* @__PURE__ */ new Set();
	const byName = /* @__PURE__ */ new Map();
	const result = [];
	for (const m of all) {
		if (refSeen.has(m)) continue;
		refSeen.add(m);
		const existingIdx = byName.get(m.name);
		if (existingIdx !== void 0) {
			console.warn(`[rich-compose] module name collision: "${m.name}" — replacing previous registration. Pass the same module reference to silence this warning.`);
			result[existingIdx] = m;
			continue;
		}
		byName.set(m.name, result.length);
		result.push(m);
	}
	return result;
}
/**
* Dedup by class reference. When two Klasses share the same `getType()`,
* a subclass relationship (edit Klass extends base Klass) auto-resolves:
* the subclass replaces its parent. Unrelated collisions throw — `instanceof`
* would break across module boundaries.
*/
function dedupNodes(nodes) {
	const seen = /* @__PURE__ */ new Set();
	const byType = /* @__PURE__ */ new Map();
	const result = [];
	for (const Node of nodes) {
		if (seen.has(Node)) continue;
		seen.add(Node);
		const type = typeof Node.getType === "function" ? Node.getType() : void 0;
		if (type === void 0) {
			result.push(Node);
			continue;
		}
		const prevIdx = byType.get(type);
		if (prevIdx === void 0) {
			byType.set(type, result.length);
			result.push(Node);
			continue;
		}
		const prev = result[prevIdx];
		if (Node === prev) continue;
		if (Node.prototype instanceof prev) {
			result[prevIdx] = Node;
			continue;
		}
		if (prev.prototype instanceof Node) continue;
		throw new Error(`[rich-compose] node type collision on "${type}": two distinct Klass references registered. This breaks \`instanceof\` checks. Ensure peerDeps/lexical version are pinned and a single module exports each type.`);
	}
	return result;
}
//#endregion
//#region src/core/lazy.tsx
/**
* Build sync wrappers around `React.lazy(loader)` factories.
*
* Each factory is created exactly **once** at compose time, not per render.
* Recreating the factory on every render would force React to refetch the
* chunk and replay the Suspense fallback, causing flicker.
*/
function wrapLazy(modules) {
	const result = {};
	for (const m of modules) {
		if (!m.lazyRenderers) continue;
		for (const key of Object.keys(m.lazyRenderers)) {
			const loader = m.lazyRenderers[key];
			if (!loader) continue;
			const fallback = m.ssrFallback?.[key] ?? null;
			const LazyInner = lazy(loader);
			const Wrapped = (props) => /* @__PURE__ */ jsx(Suspense, {
				fallback,
				children: /* @__PURE__ */ jsx(LazyInner, { ...props })
			});
			Wrapped.displayName = `Lazy(${m.name}.${String(key)})`;
			result[key] = Wrapped;
		}
	}
	return result;
}
//#endregion
//#region src/core/compose.tsx
function flattenNodes(modules) {
	return dedupNodes(modules.flatMap((m) => m.nodes ?? []));
}
function mergeSyncRenderers(modules) {
	const out = {};
	for (const m of modules) {
		if (!m.renderers) continue;
		Object.assign(out, m.renderers);
	}
	return out;
}
function composeProviders(modules) {
	const providers = modules.map((m) => m.Provider).filter((P) => Boolean(P));
	if (providers.length === 0) return Fragment;
	const ComposedProviders = ({ children }) => {
		let acc = children;
		for (let i = providers.length - 1; i >= 0; i--) {
			const P = providers[i];
			acc = /* @__PURE__ */ jsx(P, { children: acc });
		}
		return /* @__PURE__ */ jsx(Fragment$1, { children: acc });
	};
	ComposedProviders.displayName = "ComposedProviders";
	return ComposedProviders;
}
function composeRenderer(opts) {
	const merged = mergeModules(opts.preset, opts.modules);
	const allNodes = flattenNodes(merged);
	const syncMap = mergeSyncRenderers(merged);
	const lazyMap = wrapLazy(merged);
	const finalConfig = {
		...syncMap,
		...lazyMap,
		...opts.overrides
	};
	const ComposedProviders = composeProviders(merged);
	const builtinNodeOverrides = opts.builtinNodeOverrides;
	function ComposedRenderer(props) {
		const { theme, variant } = props;
		return /* @__PURE__ */ jsx(NestedContentRendererProvider, {
			value: useCallback((value, overrideVariant) => /* @__PURE__ */ jsx(ComposedRenderer, {
				nested: true,
				theme,
				value,
				variant: overrideVariant ?? variant
			}), [theme, variant]),
			children: /* @__PURE__ */ jsx(ComposedProviders, { children: /* @__PURE__ */ jsx(RichRenderer, {
				as: props.as,
				builtinNodeOverrides,
				className: props.className,
				extraNodes: allNodes,
				nested: props.nested,
				rendererConfig: finalConfig,
				style: props.style,
				theme,
				value: props.value,
				variant
			}) })
		});
	}
	return memo(ComposedRenderer);
}
//#endregion
export { RichRenderer as a, mergeModules as i, wrapLazy as n, dedupNodes as r, composeRenderer as t };
