import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
import { FIELD_KEY_RE, FIELD_TYPES, createFieldTypeRegistry, evaluateConditionalLogic, parseFieldDefinition, parseFieldGroupDefinition } from "@platform-modules/fields";
import { Button, Input } from "@platform-modules/ui-primitives";
//#region src/provider.tsx
const FieldsContext = createContext(null);
function FieldsProvider({ client, children }) {
	return /* @__PURE__ */ jsx(FieldsContext.Provider, {
		value: client,
		children
	});
}
function useFieldsClient() {
	const ctx = useContext(FieldsContext);
	if (!ctx) throw new Error("useFieldsClient must be used within <FieldsProvider>");
	return ctx;
}
//#endregion
//#region src/hooks.ts
function toError(e) {
	return e instanceof Error ? e : new Error(String(e));
}
function useFieldValues(ref, opts = {}) {
	const client = useFieldsClient();
	const hasSeed = opts.initialData !== void 0;
	const [values, setValues] = useState(opts.initialData ?? {});
	const [loading, setLoading] = useState(!hasSeed);
	const [error, setError] = useState(null);
	const [reloadToken, setReloadToken] = useState(0);
	const clientRef = useRef(client);
	clientRef.current = client;
	const refKey = `${ref.entityType}:${ref.entityId}:${opts.subType ?? ""}`;
	const prevRefKey = useRef(refKey);
	const reload = useCallback(() => {
		setReloadToken((t) => t + 1);
	}, []);
	useEffect(() => {
		const refChanged = prevRefKey.current !== refKey;
		prevRefKey.current = refKey;
		if (hasSeed && reloadToken === 0 && !refChanged) return;
		let cancelled = false;
		setLoading(true);
		setError(null);
		clientRef.current.getEntityValues(ref, { subType: opts.subType }).then((next) => {
			if (!cancelled) {
				setValues(next);
				setLoading(false);
			}
		}).catch((e) => {
			if (!cancelled) {
				setError(toError(e));
				setLoading(false);
			}
		});
		return () => {
			cancelled = true;
		};
	}, [
		ref,
		refKey,
		opts.subType,
		hasSeed,
		reloadToken
	]);
	return {
		values,
		loading,
		error,
		reload
	};
}
function useEntityFields(ref, opts = {}) {
	const client = useFieldsClient();
	const { values, loading: valuesLoading, error: valuesError, reload: reloadValues } = useFieldValues(ref, opts);
	const [groups, setGroups] = useState([]);
	const [groupsLoading, setGroupsLoading] = useState(true);
	const [groupsError, setGroupsError] = useState(null);
	const [reloadToken, setReloadToken] = useState(0);
	const clientRef = useRef(client);
	clientRef.current = client;
	const refKey = `${ref.entityType}:${ref.entityId}:${opts.subType ?? ""}`;
	const reload = useCallback(() => {
		setReloadToken((t) => t + 1);
		reloadValues();
	}, [reloadValues]);
	useEffect(() => {
		let cancelled = false;
		setGroupsLoading(true);
		setGroupsError(null);
		clientRef.current.resolveGroups({
			entityType: ref.entityType,
			subType: opts.subType
		}).then((next) => {
			if (!cancelled) {
				setGroups(next);
				setGroupsLoading(false);
			}
		}).catch((e) => {
			if (!cancelled) {
				setGroupsError(toError(e));
				setGroupsLoading(false);
			}
		});
		return () => {
			cancelled = true;
		};
	}, [
		ref.entityType,
		refKey,
		opts.subType,
		reloadToken
	]);
	const save = useCallback(async (groupId, nextValues) => {
		await clientRef.current.setEntityValues({
			ref,
			groupId,
			values: nextValues
		});
		reloadValues();
	}, [ref, reloadValues]);
	return {
		values,
		groups,
		loading: valuesLoading || groupsLoading,
		error: valuesError ?? groupsError,
		save,
		reload
	};
}
function useFieldGroupBuilder(entityType, opts = {}) {
	const client = useFieldsClient();
	const [groups, setGroups] = useState([]);
	const [loading, setLoading] = useState(true);
	const [error, setError] = useState(null);
	const [reloadToken, setReloadToken] = useState(0);
	const clientRef = useRef(client);
	clientRef.current = client;
	const refresh = useCallback(async () => {
		const next = await clientRef.current.listGroups({
			entityType,
			subType: opts.subType
		});
		setGroups(next);
		return next;
	}, [entityType, opts.subType]);
	const reload = useCallback(() => {
		setReloadToken((t) => t + 1);
	}, []);
	useEffect(() => {
		let cancelled = false;
		setLoading(true);
		setError(null);
		clientRef.current.listGroups({
			entityType,
			subType: opts.subType
		}).then((next) => {
			if (!cancelled) {
				setGroups(next);
				setLoading(false);
			}
		}).catch((e) => {
			if (!cancelled) {
				setError(toError(e));
				setLoading(false);
			}
		});
		return () => {
			cancelled = true;
		};
	}, [
		entityType,
		opts.subType,
		reloadToken
	]);
	return {
		groups,
		loading,
		error,
		create: useCallback(async (group) => {
			await clientRef.current.createGroup(group);
			await refresh();
		}, [refresh]),
		update: useCallback(async (id, patch) => {
			await clientRef.current.updateGroup(id, patch);
			await refresh();
		}, [refresh]),
		remove: useCallback(async (id) => {
			await clientRef.current.deleteGroup(id);
			await refresh();
		}, [refresh]),
		reload
	};
}
//#endregion
//#region src/render.tsx
function Shell({ children }) {
	return /* @__PURE__ */ jsx("div", {
		style: { containerType: "inline-size" },
		children
	});
}
function TextInput({ field, value, onChange, disabled }) {
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "text",
		"aria-label": field.label,
		value: typeof value === "string" ? value : "",
		disabled,
		onChange: (e) => onChange(e.target.value || void 0)
	}) });
}
function TextAreaInput({ field, value, onChange, disabled }) {
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("textarea", {
		"aria-label": field.label,
		value: typeof value === "string" ? value : "",
		disabled,
		onChange: (e) => onChange(e.target.value || void 0)
	}) });
}
function NumberInput({ field, value, onChange, disabled }) {
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "number",
		"aria-label": field.label,
		value: typeof value === "number" ? value : "",
		disabled,
		onChange: (e) => {
			const raw = e.target.value;
			onChange(raw === "" ? void 0 : Number(raw));
		}
	}) });
}
function BooleanInput({ field, value, onChange, disabled }) {
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "checkbox",
		"aria-label": field.label,
		checked: value === true,
		disabled,
		onChange: (e) => onChange(e.target.checked)
	}) });
}
function SelectInput({ field, value, onChange, disabled }) {
	const options = field.type === "select" ? field.options : [];
	const multiple = field.type === "select" && field.multiple === true;
	const selected = multiple ? Array.isArray(value) ? value.map(String) : [] : typeof value === "string" ? value : "";
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsxs("select", {
		"aria-label": field.label,
		multiple,
		disabled,
		value: selected,
		onChange: (e) => {
			if (multiple) onChange(Array.from(e.target.selectedOptions, (o) => o.value));
			else onChange(e.target.value || void 0);
		},
		children: [!multiple ? /* @__PURE__ */ jsx("option", {
			value: "",
			children: "—"
		}) : null, options.map((o) => /* @__PURE__ */ jsx("option", {
			value: o.value,
			children: o.label
		}, o.value))]
	}) });
}
function DateInput({ field, value, onChange, disabled }) {
	const str = value instanceof Date ? value.toISOString().slice(0, 10) : typeof value === "string" ? value : "";
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "date",
		"aria-label": field.label,
		value: str,
		disabled,
		onChange: (e) => onChange(e.target.value ? new Date(e.target.value) : void 0)
	}) });
}
function ColorInput({ field, value, onChange, disabled }) {
	const hex = typeof value === "string" && value.startsWith("#") ? value.slice(0, 7) : "#000000";
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "color",
		"aria-label": field.label,
		value: hex,
		disabled,
		onChange: (e) => onChange(e.target.value)
	}) });
}
function UrlInput({ field, value, onChange, disabled }) {
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "url",
		"aria-label": field.label,
		value: typeof value === "string" ? value : "",
		disabled,
		onChange: (e) => onChange(e.target.value || void 0)
	}) });
}
function EmailInput({ field, value, onChange, disabled }) {
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "email",
		"aria-label": field.label,
		value: typeof value === "string" ? value : "",
		disabled,
		onChange: (e) => onChange(e.target.value || void 0)
	}) });
}
function MediaInput({ field, value, onChange, disabled }) {
	const media = !Array.isArray(value) && value && typeof value === "object" && "key" in value ? value : void 0;
	return /* @__PURE__ */ jsx(Shell, { children: /* @__PURE__ */ jsx("input", {
		type: "text",
		"aria-label": field.label,
		placeholder: "media key",
		value: media?.key ?? "",
		disabled,
		onChange: (e) => {
			const key = e.target.value;
			onChange(key ? {
				key,
				url: media?.url,
				mime: media?.mime,
				meta: media?.meta
			} : void 0);
		}
	}) });
}
function RelationshipInput({ field, value, onChange, disabled }) {
	const rel = !Array.isArray(value) && value && typeof value === "object" && "entityType" in value ? value : void 0;
	const emit = (entityType, entityId) => onChange(entityType || entityId ? {
		entityType,
		entityId
	} : void 0);
	return /* @__PURE__ */ jsxs(Shell, { children: [/* @__PURE__ */ jsx("input", {
		type: "text",
		"aria-label": `${field.label} entity type`,
		placeholder: "entityType",
		value: rel?.entityType ?? "",
		disabled,
		onChange: (e) => emit(e.target.value, rel?.entityId ?? "")
	}), /* @__PURE__ */ jsx("input", {
		type: "text",
		"aria-label": `${field.label} entity id`,
		placeholder: "entityId",
		value: rel?.entityId ?? "",
		disabled,
		onChange: (e) => emit(rel?.entityType ?? "", e.target.value)
	})] });
}
const referenceInputs = {
	text: TextInput,
	textarea: TextAreaInput,
	number: NumberInput,
	boolean: BooleanInput,
	select: SelectInput,
	date: DateInput,
	color: ColorInput,
	url: UrlInput,
	email: EmailInput,
	media: MediaInput,
	relationship: RelationshipInput
};
//#endregion
//#region src/values-form.tsx
function groupIdOf(group) {
	return group.id ?? group.key;
}
function seedValuesByGroup(groups, initialValues) {
	const seeded = {};
	for (const group of groups) {
		const id = groupIdOf(group);
		seeded[id] = { ...initialValues?.[id] ?? {} };
	}
	return seeded;
}
function FieldValuesForm({ groups, initialValues, onSubmit, disabled, errors }) {
	const [valuesByGroup, setValuesByGroup] = useState(() => seedValuesByGroup(groups, initialValues));
	const setFieldValue = useCallback((groupId, key, value) => {
		setValuesByGroup((prev) => ({
			...prev,
			[groupId]: {
				...prev[groupId],
				[key]: value
			}
		}));
	}, []);
	const handleSubmit = useCallback((e) => {
		e.preventDefault();
		onSubmit(groups.map((group) => {
			const groupId = groupIdOf(group);
			return {
				groupId,
				values: valuesByGroup[groupId] ?? {}
			};
		}));
	}, [
		onSubmit,
		valuesByGroup,
		groups
	]);
	return /* @__PURE__ */ jsx("div", {
		className: "fields-values-form",
		style: { containerType: "inline-size" },
		children: /* @__PURE__ */ jsxs("form", {
			onSubmit: handleSubmit,
			children: [groups.map((group) => {
				const groupId = groupIdOf(group);
				const groupValues = valuesByGroup[groupId] ?? {};
				return /* @__PURE__ */ jsxs("fieldset", {
					disabled,
					className: "fields-values-form__group",
					children: [group.label ? /* @__PURE__ */ jsx("legend", {
						className: "fields-values-form__legend",
						children: group.label
					}) : null, group.fields.map((field) => {
						const Input = referenceInputs[field.type];
						const fieldError = errors?.[groupId]?.[field.key];
						return /* @__PURE__ */ jsxs("div", {
							className: "fields-values-form__field",
							children: [/* @__PURE__ */ jsx(Input, {
								field,
								value: groupValues[field.key],
								onChange: (v) => setFieldValue(groupId, field.key, v),
								error: fieldError,
								disabled
							}), fieldError ? /* @__PURE__ */ jsx("div", {
								role: "alert",
								tabIndex: 0,
								className: "fields-values-form__error",
								children: fieldError
							}) : null]
						}, field.key);
					})]
				}, groupId);
			}), /* @__PURE__ */ jsx("button", {
				type: "submit",
				disabled,
				className: "fields-values-form__submit",
				children: "Save fields"
			})]
		})
	});
}
//#endregion
//#region src/group-editor.tsx
function defaultField$1() {
	return {
		key: "new_field",
		type: "text",
		label: "New field"
	};
}
function isValidKey(key) {
	return FIELD_KEY_RE.test(key);
}
function withTypeDefaults(field, type) {
	const base = {
		...field,
		type
	};
	if (type === "select" && field.type !== "select") return {
		...base,
		type: "select",
		options: [{
			value: "option_a",
			label: "Option A"
		}]
	};
	if (type === "relationship" && field.type !== "relationship") return {
		...base,
		type: "relationship",
		targetEntityType: "content"
	};
	return base;
}
function GroupEditorSection({ groupId, draft, onDraftChange, onSave, saving }) {
	const hasInvalidKeys = draft.fields.filter((f) => !isValidKey(f.key)).length > 0;
	const updateField = useCallback((index, patch) => {
		const fields = draft.fields.map((f, i) => i === index ? {
			...f,
			...patch
		} : f);
		onDraftChange({
			...draft,
			fields
		});
	}, [draft, onDraftChange]);
	const setFieldType = useCallback((index, type) => {
		const fields = draft.fields.map((f, i) => i === index ? withTypeDefaults(f, type) : f);
		onDraftChange({
			...draft,
			fields
		});
	}, [draft, onDraftChange]);
	const moveField = useCallback((index, direction) => {
		const target = index + direction;
		if (target < 0 || target >= draft.fields.length) return;
		const fields = [...draft.fields];
		const tmp = fields[index];
		fields[index] = fields[target];
		fields[target] = tmp;
		onDraftChange({
			...draft,
			fields
		});
	}, [draft, onDraftChange]);
	const removeField = useCallback((index) => {
		onDraftChange({
			...draft,
			fields: draft.fields.filter((_, i) => i !== index)
		});
	}, [draft, onDraftChange]);
	const addField = useCallback(() => {
		onDraftChange({
			...draft,
			fields: [...draft.fields, defaultField$1()]
		});
	}, [draft, onDraftChange]);
	const updateSelectOption = useCallback((fieldIndex, optionIndex, patch) => {
		const field = draft.fields[fieldIndex];
		if (!field || field.type !== "select") return;
		const options = field.options.map((o, i) => i === optionIndex ? {
			...o,
			...patch
		} : o);
		updateField(fieldIndex, {
			type: "select",
			options
		});
	}, [draft.fields, updateField]);
	const addSelectOption = useCallback((fieldIndex) => {
		const field = draft.fields[fieldIndex];
		if (!field || field.type !== "select") return;
		const n = field.options.length + 1;
		updateField(fieldIndex, {
			type: "select",
			options: [...field.options, {
				value: `option_${n}`,
				label: `Option ${n}`
			}]
		});
	}, [draft.fields, updateField]);
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-group-editor__group",
		"aria-label": draft.label,
		children: [
			/* @__PURE__ */ jsx("h3", {
				className: "fields-group-editor__heading",
				children: draft.label
			}),
			/* @__PURE__ */ jsx("ul", {
				className: "fields-group-editor__fields",
				children: draft.fields.map((field, index) => {
					const isNewRow = field.key === "new_field" && field.label === "New field";
					const keyInvalid = !isValidKey(field.key);
					return /* @__PURE__ */ jsxs("li", {
						className: "fields-group-editor__row",
						children: [
							/* @__PURE__ */ jsx("input", {
								type: "text",
								"aria-label": field.label,
								value: field.label,
								className: "fields-group-editor__label",
								onChange: (e) => updateField(index, { label: e.target.value })
							}),
							/* @__PURE__ */ jsx("input", {
								type: "text",
								id: `field-key-${field.key}`,
								"aria-label": "Field key",
								value: field.key,
								className: "fields-group-editor__key",
								onChange: (e) => updateField(index, { key: e.target.value })
							}),
							keyInvalid ? /* @__PURE__ */ jsx("div", {
								role: "alert",
								tabIndex: 0,
								className: "fields-group-editor__key-error",
								children: "Invalid field key — use lowercase letters, digits, and underscores; must start with a letter."
							}) : null,
							/* @__PURE__ */ jsxs("label", {
								className: "fields-group-editor__required",
								children: [/* @__PURE__ */ jsx("input", {
									type: "checkbox",
									"aria-label": `${field.label} required`,
									checked: field.required === true,
									onChange: (e) => updateField(index, { required: e.target.checked || void 0 })
								}), "Required"]
							}),
							/* @__PURE__ */ jsx("select", {
								name: isNewRow ? "field-type-new" : `field-type-${field.key}`,
								"aria-label": "Field type",
								value: field.type,
								className: "fields-group-editor__type",
								onChange: (e) => setFieldType(index, e.target.value),
								children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsx("option", {
									value: t,
									children: t
								}, t))
							}),
							field.type === "select" ? /* @__PURE__ */ jsxs("div", {
								className: "fields-group-editor__options",
								children: [field.options.map((opt, optIndex) => /* @__PURE__ */ jsxs("div", {
									className: "fields-group-editor__option",
									children: [/* @__PURE__ */ jsx("input", {
										type: "text",
										"aria-label": `${field.label} option value`,
										value: opt.value,
										onChange: (e) => updateSelectOption(index, optIndex, { value: e.target.value })
									}), /* @__PURE__ */ jsx("input", {
										type: "text",
										"aria-label": `${field.label} option label`,
										value: opt.label,
										onChange: (e) => updateSelectOption(index, optIndex, { label: e.target.value })
									})]
								}, optIndex)), /* @__PURE__ */ jsx("button", {
									type: "button",
									onClick: () => addSelectOption(index),
									children: "Add option"
								})]
							}) : null,
							/* @__PURE__ */ jsx("button", {
								type: "button",
								"aria-label": `Move ${field.label} up`,
								"aria-disabled": index === 0,
								onClick: () => moveField(index, -1),
								children: "Move up"
							}),
							/* @__PURE__ */ jsx("button", {
								type: "button",
								"aria-label": `Move ${field.label} down`,
								"aria-disabled": index === draft.fields.length - 1,
								onClick: () => moveField(index, 1),
								children: "Move down"
							}),
							/* @__PURE__ */ jsx("button", {
								type: "button",
								"aria-label": `Remove ${field.label}`,
								onClick: () => removeField(index),
								children: "Remove field"
							})
						]
					}, `${groupId ?? "new"}-${index}`);
				})
			}),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				className: "fields-group-editor__add-field",
				onClick: addField,
				children: "Add field"
			}),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				className: "fields-group-editor__save",
				disabled: hasInvalidKeys || saving,
				onClick: onSave,
				children: "Save group"
			})
		]
	});
}
function FieldGroupEditor({ entityType, subType }) {
	const { groups, loading, error, create, update } = useFieldGroupBuilder(entityType, { subType });
	const [drafts, setDrafts] = useState({});
	const [saving, setSaving] = useState(false);
	useEffect(() => {
		if (loading) return;
		setDrafts((prev) => {
			const next = { ...prev };
			for (const g of groups) {
				const id = g.id ?? g.key;
				if (!next[id]) next[id] = {
					key: g.key,
					label: g.label,
					location: g.location,
					fields: g.fields.map((f) => ({ ...f }))
				};
			}
			return next;
		});
	}, [groups, loading]);
	const handleSave = useCallback(async (groupId, draft) => {
		setSaving(true);
		try {
			const payload = {
				key: draft.key,
				label: draft.label,
				location: draft.location,
				fields: draft.fields
			};
			if (groupId) await update(groupId, payload);
			else await create(payload);
		} finally {
			setSaving(false);
		}
	}, [create, update]);
	const body = useMemo(() => {
		if (loading) return /* @__PURE__ */ jsx("p", {
			className: "fields-group-editor__loading",
			children: "Loading groups…"
		});
		if (groups.length === 0) return /* @__PURE__ */ jsx("p", {
			className: "fields-group-editor__empty",
			children: "No field groups."
		});
		return groups.map((g) => {
			const id = g.id ?? g.key;
			const draft = drafts[id];
			if (!draft) return null;
			return /* @__PURE__ */ jsx(GroupEditorSection, {
				groupId: g.id,
				draft,
				saving,
				onDraftChange: (next) => setDrafts((prev) => ({
					...prev,
					[id]: next
				})),
				onSave: () => {
					const current = drafts[id];
					if (current) handleSave(g.id, current);
				}
			}, id);
		});
	}, [
		drafts,
		groups,
		handleSave,
		loading,
		saving
	]);
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-group-editor",
		style: { containerType: "inline-size" },
		children: [error ? /* @__PURE__ */ jsx("div", {
			role: "alert",
			tabIndex: 0,
			className: "fields-group-editor__error",
			children: error.message
		}) : null, body]
	});
}
//#endregion
//#region src/async-options.tsx
function AsyncOptionSearch({ source, onChoose, selectedKeys = [], label, placeholder, pageSize = 25, minQueryLength = 0, disabled = false }) {
	const [query, setQuery] = useState(""), [items, setItems] = useState([]), [cursor, setCursor] = useState(null), [loading, setLoading] = useState(false), [error, setError] = useState(null), [announcement, setAnnouncement] = useState(""), [activeIndex, setActiveIndex] = useState(-1);
	const requestRef = useRef(null), requestSerial = useRef(0), resultsId = `${useId()}-results`;
	const run = useCallback(async (nextQuery, nextCursor, append) => {
		requestRef.current?.abort();
		const controller = new AbortController();
		requestRef.current = controller;
		const serial = ++requestSerial.current;
		if (nextQuery.length < minQueryLength) {
			setItems([]);
			setActiveIndex(-1);
			setCursor(null);
			setError(null);
			setLoading(false);
			setAnnouncement(`Enter at least ${minQueryLength} characters`);
			return;
		}
		setLoading(true);
		setError(null);
		try {
			const page = await source.search({
				query: nextQuery,
				cursor: nextCursor,
				limit: pageSize,
				signal: controller.signal
			});
			if (controller.signal.aborted || serial !== requestSerial.current) return;
			setItems((current) => append ? Object.freeze([...current, ...page.items]) : Object.freeze([...page.items]));
			if (!append) setActiveIndex(-1);
			setCursor(page.nextCursor);
			setAnnouncement(`${page.items.length} option${page.items.length === 1 ? "" : "s"} loaded${page.nextCursor ? " with more available" : ""}`);
		} catch (cause) {
			if (controller.signal.aborted) return;
			setError(cause instanceof Error ? cause.message : String(cause));
			setAnnouncement("Option search failed");
		} finally {
			if (!controller.signal.aborted && serial === requestSerial.current) setLoading(false);
		}
	}, [
		minQueryLength,
		pageSize,
		source
	]);
	useEffect(() => {
		run(query, null, false);
		return () => {
			requestRef.current?.abort();
		};
	}, [query, run]);
	const onKeyDown = (event) => {
		if (!items.length) return;
		if (event.key === "ArrowDown") {
			event.preventDefault();
			setActiveIndex((current) => Math.min(current + 1, items.length - 1));
			return;
		}
		if (event.key === "ArrowUp") {
			event.preventDefault();
			setActiveIndex((current) => current <= 0 ? 0 : current - 1);
			return;
		}
		if (event.key === "Home") {
			event.preventDefault();
			setActiveIndex(0);
			return;
		}
		if (event.key === "End") {
			event.preventDefault();
			setActiveIndex(items.length - 1);
			return;
		}
		if (event.key === "Escape") {
			setActiveIndex(-1);
			return;
		}
		if (event.key === "Enter" && activeIndex >= 0) {
			event.preventDefault();
			const option = items[activeIndex];
			if (option) onChoose(option);
		}
	};
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-async-options",
		style: {
			containerType: "inline-size",
			containerName: "fields-async-options"
		},
		"aria-label": `${label} option search`,
		children: [
			/* @__PURE__ */ jsx("style", { children: `.fields-async-options__results{display:grid;gap:.35rem;padding:0;list-style:none}.fields-async-options__option{display:grid;gap:.15rem;text-align:left;width:100%;cursor:pointer}.fields-async-options__option[data-active="true"]{outline:2px solid currentColor;outline-offset:2px}@container fields-async-options (max-width:30rem){.fields-async-options__option{min-height:2.75rem}}` }),
			/* @__PURE__ */ jsxs("label", { children: [label, /* @__PURE__ */ jsx(Input, {
				role: "combobox",
				"aria-expanded": items.length > 0,
				"aria-controls": resultsId,
				"aria-autocomplete": "list",
				"aria-activedescendant": activeIndex >= 0 ? `${resultsId}-option-${activeIndex}` : void 0,
				disabled,
				placeholder,
				value: query,
				onKeyDown,
				onChange: (event) => setQuery(event.currentTarget.value)
			})] }),
			/* @__PURE__ */ jsx("div", {
				role: "status",
				"aria-live": "polite",
				children: announcement
			}),
			error ? /* @__PURE__ */ jsx("div", {
				role: "alert",
				tabIndex: 0,
				children: error
			}) : null,
			/* @__PURE__ */ jsx("ul", {
				id: resultsId,
				role: "listbox",
				className: "fields-async-options__results",
				"aria-busy": loading || void 0,
				children: items.map((option, index) => /* @__PURE__ */ jsxs("li", {
					id: `${resultsId}-option-${index}`,
					role: "option",
					"aria-selected": selectedKeys.includes(option.key),
					"data-active": activeIndex === index || void 0,
					className: "fields-async-options__option",
					onMouseDown: (event) => event.preventDefault(),
					onClick: () => onChoose(option),
					children: [/* @__PURE__ */ jsx("span", { children: option.label }), option.description ? /* @__PURE__ */ jsx("small", { children: option.description }) : null]
				}, option.key))
			}),
			cursor ? /* @__PURE__ */ jsx(Button, {
				type: "button",
				tone: "surface",
				disabled: disabled || loading,
				"aria-busy": loading || void 0,
				onClick: () => void run(query, cursor, true),
				children: loading ? "Loading…" : "Load more"
			}) : null
		]
	});
}
//#endregion
//#region src/surface-registry.tsx
const CUSTOM_TYPE_RE = /^[a-z][a-z0-9-]*:[a-z][a-z0-9._-]*$/;
function registryVersion(adapters) {
	return `fields-react-v1:${adapters.map((adapter) => `${adapter.type}@${adapter.contractVersion}`).join("|")}`;
}
function createReactFieldSurfaceRegistry(input = {}) {
	const extensions = [...input.extensions ?? []].sort((a, b) => a.type.localeCompare(b.type)), seen = /* @__PURE__ */ new Set();
	for (const adapter of extensions) {
		if (!CUSTOM_TYPE_RE.test(adapter.type)) throw new TypeError(`React field surface type must be adopter-namespaced: ${adapter.type}`);
		if (!adapter.contractVersion.trim()) throw new TypeError(`React field surface ${adapter.type} requires contractVersion`);
		if (seen.has(adapter.type)) throw new TypeError(`Duplicate React field surface ${adapter.type}`);
		if (typeof adapter.editor !== "function" || typeof adapter.readOnlyDisplay !== "function" || typeof adapter.focusTarget !== "function") throw new TypeError(`React field surface ${adapter.type} is incomplete`);
		if (!adapter.a11y.description.trim()) throw new TypeError(`React field surface ${adapter.type} requires a11y description`);
		seen.add(adapter.type);
		Object.freeze(adapter.responsive);
		Object.freeze(adapter.a11y);
		Object.freeze(adapter);
	}
	const map = new Map(extensions.map((adapter) => [adapter.type, adapter]));
	return Object.freeze({
		version: registryVersion(extensions),
		types: Object.freeze(extensions.map((adapter) => adapter.type)),
		resolve(type) {
			const adapter = map.get(type);
			return adapter ? Object.freeze({
				kind: "supported",
				adapter
			}) : Object.freeze({
				kind: "unsupported",
				code: "unsupported-surface",
				type
			});
		}
	});
}
function CustomFieldSurface({ definition, value, onChange, path, errors, registry, inputId, disabled, readOnly }) {
	const resolution = registry?.resolve(definition.type) ?? {
		kind: "unsupported",
		code: "unsupported-surface",
		type: definition.type
	};
	if (resolution.kind === "unsupported") return /* @__PURE__ */ jsxs("div", {
		role: "alert",
		tabIndex: 0,
		"data-field-surface-error": resolution.code,
		children: ["Unsupported React surface for ", resolution.type]
	});
	const adapter = resolution.adapter, fieldErrors = errors.filter((issue) => JSON.stringify(issue.path) === JSON.stringify(path)), errorId = fieldErrors.length ? `${inputId}-error` : void 0, Editor = adapter.editor, ReadOnly = adapter.readOnlyDisplay;
	return /* @__PURE__ */ jsxs("div", {
		"data-custom-field-type": definition.type,
		"data-responsive-width": adapter.responsive.fullWidth ? "full" : "auto",
		style: { containerType: "inline-size" },
		children: [
			adapter.a11y.labelStrategy === "field" ? /* @__PURE__ */ jsxs("label", {
				htmlFor: inputId,
				children: [definition.label, definition.required ? " *" : ""]
			}) : null,
			readOnly ? /* @__PURE__ */ jsx(ReadOnly, {
				definition,
				value,
				path
			}) : /* @__PURE__ */ jsx(Editor, {
				definition,
				value,
				onChange,
				path,
				inputId,
				describedBy: errorId,
				invalid: fieldErrors.length > 0,
				disabled,
				readOnly
			}),
			fieldErrors.length ? /* @__PURE__ */ jsx("div", {
				id: errorId,
				role: "alert",
				tabIndex: 0,
				children: fieldErrors.map((issue) => /* @__PURE__ */ jsx("div", { children: issue.message }, `${issue.code ?? "validation"}:${issue.message}`))
			}) : null
		]
	});
}
//#endregion
//#region src/complete-editor.tsx
const BUILTIN_FIELD_TYPES = createFieldTypeRegistry().builtInTypes;
const RESPONSIVE_CSS = `
.fields-react-complete{container-type:inline-size;container-name:fields-react;display:grid;gap:1rem}
.fields-react-complete__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.75rem}
.fields-react-complete__field{min-width:0;display:grid;gap:.35rem;align-content:start}
.fields-react-complete__field[data-width="full"]{grid-column:1/-1}
.fields-react-complete__row{border:1px solid currentColor;border-radius:.35rem;padding:.75rem;display:grid;gap:.65rem}
.fields-react-complete__actions{display:flex;gap:.4rem;flex-wrap:wrap}
.fields-react-complete__choice{display:flex;gap:.5rem;align-items:center}
.fields-react-complete__error{font-size:.875rem}
.fields-react-complete__instructions{font-size:.875rem}
.fields-react-complete__list{display:grid;gap:.6rem}
.fields-react-complete input,.fields-react-complete textarea,.fields-react-complete select{max-width:100%;box-sizing:border-box}
@container fields-react (max-width:36rem){.fields-react-complete__grid{grid-template-columns:minmax(0,1fr)}.fields-react-complete__field{grid-column:1/-1}.fields-react-complete__actions>button{min-height:2.5rem}}
`;
function pathKey(path) {
	return JSON.stringify(path);
}
function pathId$1(prefix, path) {
	return `${prefix}-${path.map((segment) => String(segment).replace(/[^a-zA-Z0-9_-]/g, "_")).join("__") || "root"}`;
}
function issuesFor(errors, path) {
	const key = pathKey(path);
	return errors.filter((issue) => pathKey(issue.path) === key);
}
function childPath(path, segment) {
	return Object.freeze([...path, segment]);
}
function defaultRowId() {
	return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `row-${Date.now()}-${Math.random().toString(36).slice(2)}`;
}
function asObject(value) {
	return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
}
function asString(value) {
	return typeof value === "string" ? value : "";
}
function asNumber(value) {
	return typeof value === "number" && Number.isFinite(value) ? value : "";
}
function emitNumber(event, onChange) {
	const raw = event.currentTarget.value;
	onChange(raw === "" ? void 0 : Number(raw));
}
function choiceEntries(field) {
	if (![
		"select",
		"checkbox",
		"radio",
		"buttonGroup"
	].includes(field.type)) return [];
	return Object.entries(field.settings.choices);
}
function isCompositeField(field) {
	return [
		"checkbox",
		"radio",
		"buttonGroup",
		"group",
		"repeater",
		"flexible",
		"clone",
		"gallery",
		"relationship",
		"entity",
		"entityLink",
		"taxonomy",
		"user"
	].includes(field.type);
}
function FieldShell({ field, path, prefix, errors, children }) {
	const id = pathId$1(prefix, path);
	const fieldIssues = issuesFor(errors, path);
	const errorId = fieldIssues.length ? `${id}-error` : void 0;
	const instructionsId = field.instructions ? `${id}-instructions` : void 0;
	const describedBy = [instructionsId, errorId].filter(Boolean).join(" ") || void 0;
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-react-complete__field",
		"data-width": [
			"textarea",
			"richText",
			"message",
			"group",
			"repeater",
			"flexible",
			"clone"
		].includes(field.type) ? "full" : void 0,
		"data-field-path": pathKey(path),
		children: [
			![
				"message",
				"accordion",
				"tab"
			].includes(field.type) ? isCompositeField(field) ? /* @__PURE__ */ jsxs("div", {
				id: `${id}-label`,
				children: [field.label, field.required ? " *" : ""]
			}) : /* @__PURE__ */ jsxs("label", {
				htmlFor: id,
				children: [field.label, field.required ? " *" : ""]
			}) : null,
			field.instructions ? /* @__PURE__ */ jsx("div", {
				id: instructionsId,
				className: "fields-react-complete__instructions",
				children: field.instructions
			}) : null,
			/* @__PURE__ */ jsx("div", {
				"data-control-id": id,
				"data-described-by": describedBy,
				...isCompositeField(field) ? {
					role: "group",
					"aria-labelledby": `${id}-label`,
					"aria-describedby": describedBy,
					"aria-invalid": fieldIssues.length ? true : void 0
				} : {},
				children
			}),
			fieldIssues.length ? /* @__PURE__ */ jsx("div", {
				id: errorId,
				role: "alert",
				tabIndex: 0,
				className: "fields-react-complete__error",
				children: fieldIssues.map((issue) => /* @__PURE__ */ jsx("div", { children: issue.message }, `${issue.code ?? "validation"}:${issue.message}`))
			}) : null
		]
	});
}
function InputBase({ field, path, prefix, errors, value, onChange, disabled, readOnly, rootValues, adapters, announce }) {
	const id = pathId$1(prefix, path);
	const fieldIssues = issuesFor(errors, path);
	const describedBy = [field.instructions ? `${id}-instructions` : void 0, fieldIssues.length ? `${id}-error` : void 0].filter(Boolean).join(" ") || void 0;
	const ariaProps = {
		id,
		"aria-invalid": fieldIssues.length ? true : void 0,
		"aria-describedby": describedBy,
		disabled,
		readOnly
	};
	const settings = field.settings;
	const safeOnChange = (next) => {
		if (!disabled && !readOnly) onChange(next);
	};
	const updateObject = (key, next) => safeOnChange({
		...asObject(value),
		[key]: next
	});
	if (field.type === "message") return /* @__PURE__ */ jsx("div", {
		role: "note",
		children: String(settings.text ?? field.label)
	});
	if (field.type === "accordion") return /* @__PURE__ */ jsxs("details", {
		open: settings.open === true,
		children: [/* @__PURE__ */ jsx("summary", { children: field.label }), settings.text ? /* @__PURE__ */ jsx("p", { children: settings.text }) : null]
	});
	if (field.type === "tab") return /* @__PURE__ */ jsx("div", {
		role: "separator",
		"aria-label": field.label,
		children: settings.text
	});
	if (field.type === "text" || field.type === "email" || field.type === "url") return /* @__PURE__ */ jsx("input", {
		...ariaProps,
		type: field.type === "text" ? "text" : field.type,
		placeholder: settings.placeholder,
		maxLength: settings.maxLength,
		value: asString(value),
		onChange: (event) => safeOnChange(event.currentTarget.value || void 0)
	});
	if (field.type === "textarea" || field.type === "richText") return /* @__PURE__ */ jsx("textarea", {
		...ariaProps,
		rows: field.type === "textarea" ? settings.rows : 8,
		value: asString(value),
		onChange: (event) => safeOnChange(event.currentTarget.value)
	});
	if (field.type === "number" || field.type === "range") return /* @__PURE__ */ jsx("input", {
		...ariaProps,
		disabled: disabled || readOnly && field.type === "range",
		type: field.type === "range" ? "range" : "number",
		min: settings.min,
		max: settings.max,
		step: settings.step,
		value: asNumber(value),
		onChange: (event) => emitNumber(event, safeOnChange)
	});
	if (field.type === "boolean") return /* @__PURE__ */ jsxs("label", {
		className: "fields-react-complete__choice",
		children: [/* @__PURE__ */ jsx("input", {
			...ariaProps,
			type: "checkbox",
			disabled: disabled || readOnly,
			readOnly: void 0,
			checked: value === true,
			onChange: (event) => safeOnChange(event.currentTarget.checked)
		}), value === true ? settings.onLabel ?? "On" : settings.offLabel ?? "Off"]
	});
	if (field.type === "select") {
		const multiple = settings.multiple === true;
		const selected = multiple ? Array.isArray(value) ? value.map(String) : [] : value === null || value === void 0 ? "" : String(value);
		return /* @__PURE__ */ jsxs("select", {
			id,
			"aria-invalid": fieldIssues.length ? true : void 0,
			"aria-describedby": fieldIssues.length ? `${id}-error` : field.instructions ? `${id}-instructions` : void 0,
			disabled: disabled || readOnly,
			multiple,
			value: selected,
			onChange: (event) => {
				if (multiple) safeOnChange(Array.from(event.currentTarget.selectedOptions, (option) => option.value));
				else safeOnChange(event.currentTarget.value || (settings.allowNull ? null : void 0));
			},
			children: [!multiple ? /* @__PURE__ */ jsx("option", {
				value: "",
				children: "—"
			}) : null, choiceEntries(field).map(([choice, label]) => /* @__PURE__ */ jsx("option", {
				value: choice,
				children: label
			}, choice))]
		});
	}
	if (field.type === "checkbox") {
		const selected = new Set(Array.isArray(value) ? value.map(String) : []);
		return /* @__PURE__ */ jsxs("fieldset", {
			disabled: disabled || readOnly,
			children: [/* @__PURE__ */ jsx("legend", {
				className: "sr-only",
				children: field.label
			}), choiceEntries(field).map(([choice, label]) => /* @__PURE__ */ jsxs("label", {
				className: "fields-react-complete__choice",
				children: [/* @__PURE__ */ jsx("input", {
					type: "checkbox",
					checked: selected.has(choice),
					onChange: (event) => {
						const next = new Set(selected);
						if (event.currentTarget.checked) next.add(choice);
						else next.delete(choice);
						safeOnChange([...next]);
					}
				}), label]
			}, choice))]
		});
	}
	if (field.type === "radio" || field.type === "buttonGroup") {
		const current = value === null || value === void 0 ? "" : String(value);
		return /* @__PURE__ */ jsxs("fieldset", {
			disabled: disabled || readOnly,
			children: [/* @__PURE__ */ jsx("legend", {
				className: "sr-only",
				children: field.label
			}), choiceEntries(field).map(([choice, label]) => /* @__PURE__ */ jsxs("label", {
				className: "fields-react-complete__choice",
				children: [/* @__PURE__ */ jsx("input", {
					type: "radio",
					name: id,
					value: choice,
					checked: current === choice,
					onChange: () => safeOnChange(choice)
				}), label]
			}, choice))]
		});
	}
	if (field.type === "password") {
		const write = asObject(value);
		const read = asObject(value);
		const inputValue = write.operation === "set" && typeof write.value === "string" ? write.value : "";
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__list",
			children: [
				read.configured === true ? /* @__PURE__ */ jsx("span", { children: "Credential configured" }) : null,
				/* @__PURE__ */ jsx("input", {
					...ariaProps,
					type: "password",
					autoComplete: "new-password",
					value: inputValue,
					onChange: (event) => safeOnChange(event.currentTarget.value ? {
						operation: "set",
						value: event.currentTarget.value
					} : { operation: "unchanged" })
				}),
				/* @__PURE__ */ jsxs("div", {
					className: "fields-react-complete__actions",
					children: [/* @__PURE__ */ jsx("button", {
						type: "button",
						disabled: disabled || readOnly,
						onClick: () => safeOnChange({ operation: "unchanged" }),
						children: "Keep existing"
					}), /* @__PURE__ */ jsx("button", {
						type: "button",
						disabled: disabled || readOnly,
						onClick: () => safeOnChange({ operation: "clear" }),
						children: "Clear password"
					})]
				})
			]
		});
	}
	if (field.type === "oembed") {
		const current = asObject(value);
		return /* @__PURE__ */ jsx("input", {
			...ariaProps,
			type: "url",
			value: asString(current.url),
			onChange: (event) => safeOnChange({
				...current,
				url: event.currentTarget.value
			})
		});
	}
	if (field.type === "link") {
		const current = asObject(value);
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__grid",
			children: [
				/* @__PURE__ */ jsx("input", {
					...ariaProps,
					type: "url",
					"aria-label": `${field.label} URL`,
					value: current.url ?? "",
					onChange: (event) => updateObject("url", event.currentTarget.value)
				}),
				/* @__PURE__ */ jsx("input", {
					type: "text",
					"aria-label": `${field.label} title`,
					disabled,
					readOnly,
					value: current.title ?? "",
					onChange: (event) => updateObject("title", event.currentTarget.value)
				}),
				/* @__PURE__ */ jsx("select", {
					"aria-label": `${field.label} target`,
					disabled: disabled || readOnly,
					value: current.target ?? "_self",
					onChange: (event) => updateObject("target", event.currentTarget.value),
					children: (settings.targets ?? ["_self", "_blank"]).map((target) => /* @__PURE__ */ jsx("option", {
						value: target,
						children: target
					}, target))
				})
			]
		});
	}
	if (field.type === "image" || field.type === "file") {
		const current = asObject(value);
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__grid",
			children: [/* @__PURE__ */ jsx("input", {
				...ariaProps,
				type: "text",
				"aria-label": `${field.label} id`,
				placeholder: "media id",
				value: current.id ?? "",
				onChange: (event) => safeOnChange(event.currentTarget.value ? {
					id: event.currentTarget.value,
					kind: field.type,
					...current.mimeType ? { mimeType: current.mimeType } : {}
				} : null)
			}), /* @__PURE__ */ jsx("input", {
				type: "text",
				"aria-label": `${field.label} MIME type`,
				disabled,
				readOnly,
				value: current.mimeType ?? "",
				onChange: (event) => safeOnChange({
					id: current.id ?? "",
					kind: field.type,
					...event.currentTarget.value ? { mimeType: event.currentTarget.value } : {}
				})
			})]
		});
	}
	if (field.type === "gallery") return /* @__PURE__ */ jsx(StringObjectList, {
		field,
		path,
		prefix,
		items: Array.isArray(value) ? value : [],
		disabled: disabled || readOnly,
		announce,
		onChange: safeOnChange,
		kind: "media"
	});
	if (field.type === "entity" || field.type === "entityLink") {
		const current = asObject(value);
		return /* @__PURE__ */ jsx(EntityRefInputs, {
			label: field.label,
			value: current,
			disabled: disabled || readOnly,
			onChange: safeOnChange
		});
	}
	if (field.type === "relationship") return /* @__PURE__ */ jsx(StringObjectList, {
		field,
		path,
		prefix,
		items: Array.isArray(value) ? value : [],
		disabled: disabled || readOnly,
		announce,
		onChange: safeOnChange,
		kind: "entity"
	});
	if (field.type === "taxonomy") {
		if (settings.multiple === true) return /* @__PURE__ */ jsx(StringObjectList, {
			field,
			path,
			prefix,
			items: Array.isArray(value) ? value : [],
			disabled: disabled || readOnly,
			announce,
			onChange: safeOnChange,
			kind: "term"
		});
		const current = asObject(value);
		return /* @__PURE__ */ jsx(TermRefInputs, {
			label: field.label,
			value: current,
			disabled: disabled || readOnly,
			onChange: safeOnChange
		});
	}
	if (field.type === "user") {
		if (settings.multiple === true) return /* @__PURE__ */ jsx(StringObjectList, {
			field,
			path,
			prefix,
			items: Array.isArray(value) ? value : [],
			disabled: disabled || readOnly,
			announce,
			onChange: safeOnChange,
			kind: "user"
		});
		const current = asObject(value);
		return /* @__PURE__ */ jsx("input", {
			...ariaProps,
			type: "text",
			value: current.id ?? "",
			onChange: (event) => safeOnChange(event.currentTarget.value ? { id: event.currentTarget.value } : null)
		});
	}
	if (field.type === "date" || field.type === "time") return /* @__PURE__ */ jsx("input", {
		...ariaProps,
		type: field.type,
		value: asString(value),
		onChange: (event) => safeOnChange(event.currentTarget.value || null)
	});
	if (field.type === "dateTime") {
		const display = typeof value === "string" ? value.replace(/Z$/, "").slice(0, 16) : "";
		return /* @__PURE__ */ jsx("input", {
			...ariaProps,
			type: "datetime-local",
			value: display,
			onChange: (event) => safeOnChange(event.currentTarget.value ? new Date(event.currentTarget.value).toISOString() : null)
		});
	}
	if (field.type === "color") return /* @__PURE__ */ jsx("input", {
		...ariaProps,
		type: "text",
		inputMode: "text",
		placeholder: "#000000",
		value: asString(value),
		onChange: (event) => safeOnChange(event.currentTarget.value || null)
	});
	if (field.type === "icon") {
		const current = asObject(value);
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__grid",
			children: [/* @__PURE__ */ jsx("input", {
				...ariaProps,
				type: "text",
				"aria-label": `${field.label} set`,
				value: asString(current.set),
				onChange: (event) => updateObject("set", event.currentTarget.value)
			}), /* @__PURE__ */ jsx("input", {
				type: "text",
				"aria-label": `${field.label} name`,
				disabled,
				readOnly,
				value: asString(current.name),
				onChange: (event) => updateObject("name", event.currentTarget.value)
			})]
		});
	}
	if (field.type === "map") {
		const current = asObject(value);
		const numeric = (key, raw) => updateObject(key, raw === "" ? void 0 : Number(raw));
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__grid",
			children: [
				/* @__PURE__ */ jsx("input", {
					...ariaProps,
					type: "number",
					"aria-label": `${field.label} latitude`,
					step: "any",
					value: current.latitude ?? "",
					onChange: (event) => numeric("latitude", event.currentTarget.value)
				}),
				/* @__PURE__ */ jsx("input", {
					type: "number",
					"aria-label": `${field.label} longitude`,
					step: "any",
					disabled,
					readOnly,
					value: current.longitude ?? "",
					onChange: (event) => numeric("longitude", event.currentTarget.value)
				}),
				/* @__PURE__ */ jsx("input", {
					type: "text",
					"aria-label": `${field.label} address`,
					disabled,
					readOnly,
					value: current.address ?? "",
					onChange: (event) => updateObject("address", event.currentTarget.value || void 0)
				}),
				/* @__PURE__ */ jsx("input", {
					type: "number",
					"aria-label": `${field.label} zoom`,
					step: "any",
					disabled,
					readOnly,
					value: current.zoom ?? "",
					onChange: (event) => numeric("zoom", event.currentTarget.value)
				})
			]
		});
	}
	if (field.type === "group") {
		const fields = field.settings.fields;
		return /* @__PURE__ */ jsx(FieldsGrid, {
			fields,
			value: asObject(value),
			onChange: safeOnChange,
			errors,
			disabled,
			readOnly,
			adapters,
			path,
			prefix,
			rootValues,
			announce
		});
	}
	if (field.type === "repeater") {
		const rows = Array.isArray(value) ? value : [];
		const fields = field.settings.fields;
		const min = field.settings.min ?? 0;
		const max = field.settings.max ?? 100;
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__list",
			children: [rows.map((row, index) => {
				const rowPath = childPath(path, row.rowId);
				return /* @__PURE__ */ jsxs("div", {
					className: "fields-react-complete__row",
					"aria-label": `${field.label} row ${index + 1}`,
					children: [/* @__PURE__ */ jsx(FieldsGrid, {
						fields,
						value: row.values,
						onChange: (next) => safeOnChange(rows.map((candidate, candidateIndex) => candidateIndex === index ? {
							...candidate,
							values: next
						} : candidate)),
						errors,
						disabled,
						readOnly,
						adapters,
						path: rowPath,
						prefix,
						rootValues,
						announce
					}), /* @__PURE__ */ jsx(RowActions, {
						label: `${field.label} row ${index + 1}`,
						index,
						length: rows.length,
						disabled: disabled || readOnly,
						removeDisabled: rows.length <= min,
						onMove: (direction) => {
							const next = [...rows];
							const target = index + direction;
							if (target < 0 || target >= next.length) return;
							[next[index], next[target]] = [next[target], next[index]];
							safeOnChange(next);
							announce(`${field.label} row moved ${direction < 0 ? "up" : "down"}`);
						},
						onRemove: () => {
							if (rows.length <= min) return;
							safeOnChange(rows.filter((_, candidateIndex) => candidateIndex !== index));
							announce(`${field.label} row removed`);
						}
					})]
				}, row.rowId);
			}), /* @__PURE__ */ jsxs("button", {
				type: "button",
				disabled: disabled || readOnly || rows.length >= max,
				onClick: () => {
					const rowId = (adapters.createRowId ?? defaultRowId)();
					safeOnChange([...rows, {
						rowId,
						values: {}
					}]);
					announce(`${field.label} row added`);
				},
				children: [
					"Add ",
					field.label,
					" row"
				]
			})]
		});
	}
	if (field.type === "flexible") {
		const rows = Array.isArray(value) ? value : [];
		const layouts = field.settings.layouts;
		const min = field.settings.min ?? 0;
		const max = field.settings.max ?? 100;
		return /* @__PURE__ */ jsxs("div", {
			className: "fields-react-complete__list",
			children: [rows.map((row, index) => {
				const layout = layouts.find((candidate) => candidate.key === row.layoutKey);
				return /* @__PURE__ */ jsxs("div", {
					className: "fields-react-complete__row",
					"aria-label": `${field.label} ${layout?.label ?? row.layoutKey} row ${index + 1}`,
					children: [
						/* @__PURE__ */ jsx("strong", { children: layout?.label ?? row.layoutKey }),
						layout ? /* @__PURE__ */ jsx(FieldsGrid, {
							fields: layout.fields,
							value: row.values,
							onChange: (next) => safeOnChange(rows.map((candidate, candidateIndex) => candidateIndex === index ? {
								...candidate,
								values: next
							} : candidate)),
							errors,
							disabled,
							readOnly,
							adapters,
							path: childPath(childPath(path, row.rowId), row.layoutKey),
							prefix,
							rootValues,
							announce
						}) : /* @__PURE__ */ jsxs("div", {
							role: "alert",
							children: ["Unknown flexible layout ", row.layoutKey]
						}),
						/* @__PURE__ */ jsx(RowActions, {
							label: `${field.label} row ${index + 1}`,
							index,
							length: rows.length,
							disabled: disabled || readOnly,
							removeDisabled: rows.length <= min,
							onMove: (direction) => {
								const next = [...rows];
								const target = index + direction;
								if (target < 0 || target >= next.length) return;
								[next[index], next[target]] = [next[target], next[index]];
								safeOnChange(next);
								announce(`${field.label} row moved ${direction < 0 ? "up" : "down"}`);
							},
							onRemove: () => {
								safeOnChange(rows.filter((_, candidateIndex) => candidateIndex !== index));
								announce(`${field.label} row removed`);
							}
						})
					]
				}, row.rowId);
			}), /* @__PURE__ */ jsx("div", {
				className: "fields-react-complete__actions",
				children: layouts.map((layout) => /* @__PURE__ */ jsxs("button", {
					type: "button",
					disabled: disabled || readOnly || rows.length >= max,
					onClick: () => {
						const rowId = (adapters.createRowId ?? defaultRowId)();
						safeOnChange([...rows, {
							rowId,
							layoutKey: layout.key,
							values: {}
						}]);
						announce(`${layout.label} layout added`);
					},
					children: ["Add ", layout.label]
				}, layout.key))
			})]
		});
	}
	if (field.type === "clone") {
		const resolver = adapters.resolveCloneFields;
		if (!resolver) return /* @__PURE__ */ jsx("div", {
			role: "alert",
			children: "Clone fields require an adopter-supplied clone resolver."
		});
		const fields = resolver(field);
		return /* @__PURE__ */ jsx(FieldsGrid, {
			fields,
			value: asObject(value),
			onChange: safeOnChange,
			errors,
			disabled,
			readOnly,
			adapters,
			path,
			prefix,
			rootValues,
			announce
		});
	}
	return /* @__PURE__ */ jsxs("div", {
		role: "alert",
		children: ["Unsupported field type ", field.type]
	});
}
function RowActions({ label, index, length, disabled, removeDisabled = false, onMove, onRemove }) {
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-react-complete__actions",
		children: [
			/* @__PURE__ */ jsx("button", {
				type: "button",
				"aria-label": `Move ${label} up`,
				"aria-disabled": index === 0 || disabled,
				disabled,
				onClick: () => {
					if (index > 0) onMove(-1);
				},
				children: "Move up"
			}),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				"aria-label": `Move ${label} down`,
				"aria-disabled": index === length - 1 || disabled,
				disabled,
				onClick: () => {
					if (index < length - 1) onMove(1);
				},
				children: "Move down"
			}),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				"aria-label": `Remove ${label}`,
				"aria-disabled": disabled || removeDisabled,
				disabled: disabled || removeDisabled,
				onClick: onRemove,
				children: "Remove"
			})
		]
	});
}
function EntityRefInputs({ label, value, disabled, onChange }) {
	const emit = (entityType, id) => onChange(entityType || id ? {
		entityType,
		id
	} : null);
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-react-complete__grid",
		children: [/* @__PURE__ */ jsx("input", {
			type: "text",
			"aria-label": `${label} entity type`,
			disabled,
			value: value.entityType ?? "",
			onChange: (event) => emit(event.currentTarget.value, value.id ?? "")
		}), /* @__PURE__ */ jsx("input", {
			type: "text",
			"aria-label": `${label} entity id`,
			disabled,
			value: value.id ?? "",
			onChange: (event) => emit(value.entityType ?? "", event.currentTarget.value)
		})]
	});
}
function TermRefInputs({ label, value, disabled, onChange }) {
	const emit = (taxonomy, id) => onChange(taxonomy || id ? {
		taxonomy,
		id
	} : null);
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-react-complete__grid",
		children: [/* @__PURE__ */ jsx("input", {
			type: "text",
			"aria-label": `${label} taxonomy`,
			disabled,
			value: value.taxonomy ?? "",
			onChange: (event) => emit(event.currentTarget.value, value.id ?? "")
		}), /* @__PURE__ */ jsx("input", {
			type: "text",
			"aria-label": `${label} term id`,
			disabled,
			value: value.id ?? "",
			onChange: (event) => emit(value.taxonomy ?? "", event.currentTarget.value)
		})]
	});
}
function StringObjectList({ field, items, disabled, onChange, kind, announce }) {
	const create = () => kind === "media" ? {
		id: "",
		kind: "image"
	} : kind === "entity" ? {
		entityType: "",
		id: ""
	} : kind === "term" ? {
		taxonomy: "",
		id: ""
	} : { id: "" };
	const settings = field.settings, min = settings.min ?? 0, max = settings.max ?? 100;
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-react-complete__list",
		children: [items.map((item, index) => {
			const current = asObject(item);
			const update = (patch) => onChange(items.map((candidate, candidateIndex) => candidateIndex === index ? {
				...asObject(candidate),
				...patch
			} : candidate));
			return /* @__PURE__ */ jsxs("div", {
				className: "fields-react-complete__row",
				children: [kind === "entity" ? /* @__PURE__ */ jsx(EntityRefInputs, {
					label: `${field.label} item ${index + 1}`,
					value: current,
					disabled,
					onChange: (next) => onChange(items.map((candidate, candidateIndex) => candidateIndex === index ? next : candidate))
				}) : kind === "term" ? /* @__PURE__ */ jsx(TermRefInputs, {
					label: `${field.label} item ${index + 1}`,
					value: current,
					disabled,
					onChange: (next) => onChange(items.map((candidate, candidateIndex) => candidateIndex === index ? next : candidate))
				}) : /* @__PURE__ */ jsx("input", {
					type: "text",
					"aria-label": `${field.label} item ${index + 1} id`,
					disabled,
					value: asString(current.id),
					onChange: (event) => update({ id: event.currentTarget.value })
				}), /* @__PURE__ */ jsx(RowActions, {
					label: `${field.label} item ${index + 1}`,
					index,
					length: items.length,
					disabled,
					removeDisabled: items.length <= min,
					onMove: (direction) => {
						const next = [...items];
						const target = index + direction;
						if (target < 0 || target >= next.length) return;
						[next[index], next[target]] = [next[target], next[index]];
						onChange(next);
						announce(`${field.label} item moved ${direction < 0 ? "up" : "down"}`);
					},
					onRemove: () => {
						onChange(items.filter((_, candidateIndex) => candidateIndex !== index));
						announce(`${field.label} item removed`);
					}
				})]
			}, `${index}:${String(current.id ?? "")}`);
		}), /* @__PURE__ */ jsxs("button", {
			type: "button",
			disabled: disabled || items.length >= max,
			onClick: () => {
				onChange([...items, create()]);
				announce(`${field.label} item added`);
			},
			children: [
				"Add ",
				field.label,
				" item"
			]
		})]
	});
}
function FieldsGrid({ fields, value, onChange, errors, disabled, readOnly, adapters, path, prefix, rootValues, announce }) {
	const setField = useCallback((key, next) => {
		const current = { ...value };
		if (next === void 0) delete current[key];
		else current[key] = next;
		onChange(current);
	}, [onChange, value]);
	return /* @__PURE__ */ jsx("div", {
		className: "fields-react-complete__grid",
		children: fields.map((definition) => {
			const nextPath = childPath(path, definition.key);
			if (!BUILTIN_FIELD_TYPES.has(definition.type)) return /* @__PURE__ */ jsx("div", {
				className: "fields-react-complete__field",
				"data-width": "full",
				children: /* @__PURE__ */ jsx(CustomFieldSurface, {
					definition,
					value: value[definition.key],
					onChange: (next) => setField(definition.key, next),
					path: nextPath,
					errors,
					registry: adapters.surfaceRegistry,
					inputId: pathId$1(prefix, nextPath),
					disabled,
					readOnly: readOnly || definition.readOnly === true
				})
			}, definition.key);
			const field = definition;
			if (field.disabled === true) return null;
			if (!evaluateConditionalLogic(field.conditionalLogic, rootValues)) return null;
			return /* @__PURE__ */ jsx(FieldShell, {
				field,
				path: nextPath,
				prefix,
				errors,
				children: /* @__PURE__ */ jsx(InputBase, {
					field,
					path: nextPath,
					prefix,
					errors,
					value: value[field.key],
					onChange: (next) => setField(field.key, next),
					disabled,
					readOnly: readOnly || field.readOnly === true,
					rootValues,
					adapters,
					announce
				})
			}, field.key);
		})
	});
}
function CompleteFieldValuesEditor({ fields, value, onChange, errors = [], disabled = false, readOnly = false, adapters = {}, legend, path = [], idPrefix = "fields-react" }) {
	const [announcement, setAnnouncement] = useState("");
	const stableAdapters = useMemo(() => adapters, [adapters]);
	const body = /* @__PURE__ */ jsx(FieldsGrid, {
		fields,
		value,
		onChange,
		errors,
		disabled,
		readOnly,
		adapters: stableAdapters,
		path,
		prefix: idPrefix,
		rootValues: value,
		announce: setAnnouncement
	});
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-react-complete",
		children: [
			/* @__PURE__ */ jsx("style", { children: RESPONSIVE_CSS }),
			/* @__PURE__ */ jsx("div", {
				role: "status",
				"aria-live": "polite",
				"aria-atomic": "true",
				style: {
					position: "absolute",
					width: 1,
					height: 1,
					overflow: "hidden",
					clip: "rect(0 0 0 0)"
				},
				children: announcement
			}),
			legend ? /* @__PURE__ */ jsxs("fieldset", {
				disabled,
				children: [/* @__PURE__ */ jsx("legend", { children: legend }), body]
			}) : body
		]
	});
}
//#endregion
//#region src/definition-builder.tsx
const COMPLETE_FIELD_TYPES = Object.freeze([...createFieldTypeRegistry().builtInTypes]);
function defaultSettings(type) {
	if (type === "textarea") return { newline: "preserve" };
	if (type === "url" || type === "link") return { schemes: [] };
	if (type === "password") return { hasherKey: "" };
	if ([
		"select",
		"checkbox",
		"radio",
		"buttonGroup"
	].includes(type)) return { choices: {} };
	if (type === "image" || type === "file" || type === "gallery") return { return: "ref" };
	if (type === "entity" || type === "entityLink" || type === "relationship") return { return: "ref" };
	if (type === "taxonomy") return {
		taxonomies: [],
		return: "ref"
	};
	if (type === "user") return { return: "ref" };
	if (type === "date") return {
		inputFormat: "",
		displayFormat: "",
		returnFormat: ""
	};
	if (type === "dateTime") return {
		inputFormat: "",
		displayFormat: "",
		returnFormat: "",
		timezone: "utc"
	};
	if (type === "time") return {
		inputFormat: "",
		displayFormat: "",
		returnFormat: ""
	};
	if (type === "map") return { providerKey: "" };
	if (type === "group" || type === "repeater") return { fields: [] };
	if (type === "flexible") return { layouts: [] };
	if (type === "clone") return { sourceFieldKeys: [] };
	return {};
}
function defaultField(index = 0) {
	const suffix = index + 1;
	return {
		key: `field_${suffix}`,
		name: `field_${suffix}`,
		label: `Field ${suffix}`,
		type: "text",
		settings: {}
	};
}
function parsePath(input) {
	const trimmed = input.trim();
	if (!trimmed) return Object.freeze(["field"]);
	return Object.freeze(trimmed.split(".").filter(Boolean).map((segment) => /^\d+$/.test(segment) ? Number(segment) : segment));
}
function formatPath(path) {
	return path.join(".");
}
function JsonObjectEditor({ label, value, onChange, disabled }) {
	const serialized = useMemo(() => JSON.stringify(value ?? {}, null, 2), [value]);
	const [draft, setDraft] = useState(serialized);
	const [error, setError] = useState(null);
	useEffect(() => setDraft(serialized), [serialized]);
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-definition-builder__json",
		children: [/* @__PURE__ */ jsxs("label", { children: [label, /* @__PURE__ */ jsx("textarea", {
			rows: 7,
			value: draft,
			disabled,
			onChange: (event) => {
				const next = event.currentTarget.value;
				setDraft(next);
				try {
					const parsed = JSON.parse(next);
					if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error("Settings must be a JSON object");
					setError(null);
					onChange(parsed);
				} catch (cause) {
					setError(cause instanceof Error ? cause.message : String(cause));
				}
			}
		})] }), error ? /* @__PURE__ */ jsx("div", {
			role: "alert",
			tabIndex: 0,
			children: error
		}) : null]
	});
}
function ConditionalLogicBuilder({ value, onChange, disabled }) {
	const groups = value ? value.map((group) => [...group]) : [];
	const replace = (next) => onChange(next.length ? Object.freeze(next.map((group) => Object.freeze(group))) : void 0);
	const updateRule = (groupIndex, ruleIndex, patch) => {
		const next = groups.map((group) => [...group]);
		const current = next[groupIndex]?.[ruleIndex];
		if (!current) return;
		next[groupIndex][ruleIndex] = {
			...current,
			...patch
		};
		replace(next);
	};
	const addRule = (groupIndex) => {
		const next = groups.map((group) => [...group]);
		next[groupIndex] = [...next[groupIndex] ?? [], {
			fieldPath: ["field"],
			operator: "eq",
			value: ""
		}];
		replace(next);
	};
	return /* @__PURE__ */ jsxs("fieldset", {
		className: "fields-definition-builder__conditions",
		disabled,
		children: [
			/* @__PURE__ */ jsx("legend", { children: "Conditional logic" }),
			groups.map((group, groupIndex) => /* @__PURE__ */ jsxs("div", {
				className: "fields-definition-builder__condition-group",
				"aria-label": `Conditional OR group ${groupIndex + 1}`,
				children: [
					/* @__PURE__ */ jsx("strong", { children: groupIndex === 0 ? "Show when" : "OR" }),
					group.map((rule, ruleIndex) => /* @__PURE__ */ jsxs("div", {
						className: "fields-definition-builder__condition-rule",
						children: [
							/* @__PURE__ */ jsx("input", {
								"aria-label": `Condition ${groupIndex + 1}.${ruleIndex + 1} field path`,
								value: formatPath(rule.fieldPath),
								onChange: (event) => updateRule(groupIndex, ruleIndex, { fieldPath: parsePath(event.currentTarget.value) })
							}),
							/* @__PURE__ */ jsx("select", {
								"aria-label": `Condition ${groupIndex + 1}.${ruleIndex + 1} operator`,
								value: rule.operator,
								onChange: (event) => {
									const operator = event.currentTarget.value;
									const next = ["empty", "notEmpty"].includes(operator) ? {
										fieldPath: rule.fieldPath,
										operator,
										...rule.quantifier ? { quantifier: rule.quantifier } : {}
									} : operator === "matches" ? {
										fieldPath: rule.fieldPath,
										operator,
										value: { source: "" },
										...rule.quantifier ? { quantifier: rule.quantifier } : {}
									} : {
										fieldPath: rule.fieldPath,
										operator,
										value: "",
										...rule.quantifier ? { quantifier: rule.quantifier } : {}
									};
									updateRule(groupIndex, ruleIndex, next);
								},
								children: [
									"eq",
									"neq",
									"contains",
									"notContains",
									"gt",
									"gte",
									"lt",
									"lte",
									"empty",
									"notEmpty",
									"matches"
								].map((operator) => /* @__PURE__ */ jsx("option", {
									value: operator,
									children: operator
								}, operator))
							}),
							!["empty", "notEmpty"].includes(rule.operator) ? /* @__PURE__ */ jsx("input", {
								"aria-label": `Condition ${groupIndex + 1}.${ruleIndex + 1} value`,
								type: [
									"gt",
									"gte",
									"lt",
									"lte"
								].includes(rule.operator) ? "number" : "text",
								value: "value" in rule ? rule.operator === "matches" ? rule.value.source : String(rule.value ?? "") : "",
								onChange: (event) => {
									if (rule.operator === "matches") updateRule(groupIndex, ruleIndex, { value: { source: event.currentTarget.value } });
									else if ([
										"gt",
										"gte",
										"lt",
										"lte"
									].includes(rule.operator)) updateRule(groupIndex, ruleIndex, { value: Number(event.currentTarget.value) });
									else updateRule(groupIndex, ruleIndex, { value: event.currentTarget.value });
								}
							}) : null,
							/* @__PURE__ */ jsxs("select", {
								"aria-label": `Condition ${groupIndex + 1}.${ruleIndex + 1} quantifier`,
								value: rule.quantifier ?? "any",
								onChange: (event) => updateRule(groupIndex, ruleIndex, { quantifier: event.currentTarget.value }),
								children: [/* @__PURE__ */ jsx("option", {
									value: "any",
									children: "any"
								}), /* @__PURE__ */ jsx("option", {
									value: "all",
									children: "all"
								})]
							}),
							/* @__PURE__ */ jsx("button", {
								type: "button",
								onClick: () => {
									const next = groups.map((candidate) => [...candidate]);
									next[groupIndex] = next[groupIndex].filter((_, index) => index !== ruleIndex);
									replace(next.filter((candidate) => candidate.length));
								},
								children: "Remove condition"
							})
						]
					}, ruleIndex)),
					/* @__PURE__ */ jsx("button", {
						type: "button",
						onClick: () => addRule(groupIndex),
						children: "Add AND condition"
					})
				]
			}, groupIndex)),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				onClick: () => replace([...groups, [{
					fieldPath: ["field"],
					operator: "eq",
					value: ""
				}]]),
				children: "Add OR group"
			})
		]
	});
}
function LocationRulesBuilder({ value, onChange, disabled }) {
	const groups = value.map((group) => [...group]);
	const replace = (next) => onChange(Object.freeze(next.map((group) => Object.freeze(group))));
	const update = (groupIndex, ruleIndex, patch) => {
		const next = groups.map((group) => [...group]);
		next[groupIndex][ruleIndex] = {
			...next[groupIndex][ruleIndex],
			...patch
		};
		replace(next);
	};
	return /* @__PURE__ */ jsxs("fieldset", {
		disabled,
		children: [
			/* @__PURE__ */ jsx("legend", { children: "Location rules" }),
			groups.map((group, groupIndex) => /* @__PURE__ */ jsxs("div", {
				"aria-label": `Location OR group ${groupIndex + 1}`,
				children: [
					/* @__PURE__ */ jsx("strong", { children: groupIndex === 0 ? "Match" : "OR" }),
					group.map((rule, ruleIndex) => /* @__PURE__ */ jsxs("div", { children: [
						/* @__PURE__ */ jsx("input", {
							"aria-label": `Location ${groupIndex + 1}.${ruleIndex + 1} parameter`,
							value: rule.parameter,
							onChange: (event) => update(groupIndex, ruleIndex, { parameter: event.currentTarget.value })
						}),
						/* @__PURE__ */ jsx("select", {
							"aria-label": `Location ${groupIndex + 1}.${ruleIndex + 1} operator`,
							value: rule.operator,
							onChange: (event) => update(groupIndex, ruleIndex, { operator: event.currentTarget.value }),
							children: [
								"eq",
								"neq",
								"in",
								"notIn",
								"contains"
							].map((operator) => /* @__PURE__ */ jsx("option", {
								value: operator,
								children: operator
							}, operator))
						}),
						/* @__PURE__ */ jsx("input", {
							"aria-label": `Location ${groupIndex + 1}.${ruleIndex + 1} value`,
							value: Array.isArray(rule.value) ? rule.value.join(",") : String(rule.value),
							onChange: (event) => update(groupIndex, ruleIndex, { value: rule.operator === "in" || rule.operator === "notIn" ? event.currentTarget.value.split(",").map((item) => item.trim()).filter(Boolean) : event.currentTarget.value })
						}),
						/* @__PURE__ */ jsx("button", {
							type: "button",
							onClick: () => {
								const next = groups.map((candidate) => [...candidate]);
								next[groupIndex] = next[groupIndex].filter((_, index) => index !== ruleIndex);
								replace(next.filter((candidate) => candidate.length));
							},
							children: "Remove location rule"
						})
					] }, ruleIndex)),
					/* @__PURE__ */ jsx("button", {
						type: "button",
						onClick: () => {
							const next = groups.map((candidate) => [...candidate]);
							next[groupIndex] = [...next[groupIndex] ?? [], {
								parameter: "entityType",
								operator: "eq",
								value: "content"
							}];
							replace(next);
						},
						children: "Add AND location rule"
					})
				]
			}, groupIndex)),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				onClick: () => replace([...groups, [{
					parameter: "entityType",
					operator: "eq",
					value: "content"
				}]]),
				children: "Add OR location group"
			})
		]
	});
}
function FieldDefinitionRow({ value, onChange, onMove, onRemove, index, length, disabled }) {
	let validationError = null;
	try {
		parseFieldDefinition(value);
	} catch (cause) {
		validationError = cause instanceof Error ? cause.message : String(cause);
	}
	const updateBase = (patch) => onChange({
		...value,
		...patch
	});
	const setType = (type) => onChange({
		...value,
		type,
		settings: defaultSettings(type),
		...type === "password" || type === "message" || type === "accordion" || type === "tab" ? { defaultValue: void 0 } : {}
	});
	const settings = value.settings;
	const nestedFields = value.type === "group" || value.type === "repeater" ? settings.fields ?? [] : null;
	const layouts = value.type === "flexible" ? settings.layouts ?? [] : null;
	return /* @__PURE__ */ jsx("li", {
		className: "fields-definition-builder__field-row",
		style: { containerType: "inline-size" },
		children: /* @__PURE__ */ jsxs("fieldset", {
			disabled,
			children: [
				/* @__PURE__ */ jsx("legend", { children: value.label || value.key || `Field ${index + 1}` }),
				/* @__PURE__ */ jsxs("div", {
					className: "fields-definition-builder__grid",
					children: [
						/* @__PURE__ */ jsxs("label", { children: ["Label", /* @__PURE__ */ jsx("input", {
							"aria-label": `Field ${index + 1} label`,
							value: value.label,
							onChange: (event) => updateBase({ label: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Key", /* @__PURE__ */ jsx("input", {
							"aria-label": `Field ${index + 1} key`,
							value: value.key,
							onChange: (event) => updateBase({ key: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Name", /* @__PURE__ */ jsx("input", {
							"aria-label": `Field ${index + 1} name`,
							value: value.name,
							onChange: (event) => updateBase({ name: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Type", /* @__PURE__ */ jsx("select", {
							"aria-label": `Field ${index + 1} type`,
							value: value.type,
							onChange: (event) => setType(event.currentTarget.value),
							children: COMPLETE_FIELD_TYPES.map((type) => /* @__PURE__ */ jsx("option", {
								value: type,
								children: type
							}, type))
						})] }),
						/* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
							type: "checkbox",
							checked: value.required === true,
							onChange: (event) => updateBase({ required: event.currentTarget.checked || void 0 })
						}), " Required"] }),
						/* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
							type: "checkbox",
							checked: value.readOnly === true,
							onChange: (event) => updateBase({ readOnly: event.currentTarget.checked || void 0 })
						}), " Read-only"] }),
						/* @__PURE__ */ jsxs("label", {
							className: "fields-definition-builder__wide",
							children: ["Instructions", /* @__PURE__ */ jsx("textarea", {
								"aria-label": `Field ${index + 1} instructions`,
								value: value.instructions ?? "",
								onChange: (event) => updateBase({ instructions: event.currentTarget.value || void 0 })
							})]
						})
					]
				}),
				/* @__PURE__ */ jsx(JsonObjectEditor, {
					label: "Settings JSON",
					value: value.settings,
					disabled,
					onChange: (next) => updateBase({ settings: next })
				}),
				nestedFields ? /* @__PURE__ */ jsx(FieldDefinitionListBuilder, {
					value: nestedFields,
					onChange: (fields) => updateBase({ settings: {
						...settings,
						fields
					} }),
					disabled,
					label: `${value.label} child fields`
				}) : null,
				layouts ? /* @__PURE__ */ jsxs("div", {
					className: "fields-definition-builder__layouts",
					children: [
						/* @__PURE__ */ jsx("h4", { children: "Flexible layouts" }),
						layouts.map((layout, layoutIndex) => /* @__PURE__ */ jsxs("fieldset", { children: [
							/* @__PURE__ */ jsx("legend", { children: layout.label }),
							/* @__PURE__ */ jsx("input", {
								"aria-label": `Layout ${layoutIndex + 1} key`,
								value: layout.key,
								onChange: (event) => {
									const next = layouts.map((candidate, candidateIndex) => candidateIndex === layoutIndex ? {
										...candidate,
										key: event.currentTarget.value
									} : candidate);
									updateBase({ settings: {
										...settings,
										layouts: next
									} });
								}
							}),
							/* @__PURE__ */ jsx("input", {
								"aria-label": `Layout ${layoutIndex + 1} name`,
								value: layout.name,
								onChange: (event) => {
									const next = layouts.map((candidate, candidateIndex) => candidateIndex === layoutIndex ? {
										...candidate,
										name: event.currentTarget.value
									} : candidate);
									updateBase({ settings: {
										...settings,
										layouts: next
									} });
								}
							}),
							/* @__PURE__ */ jsx("input", {
								"aria-label": `Layout ${layoutIndex + 1} label`,
								value: layout.label,
								onChange: (event) => {
									const next = layouts.map((candidate, candidateIndex) => candidateIndex === layoutIndex ? {
										...candidate,
										label: event.currentTarget.value
									} : candidate);
									updateBase({ settings: {
										...settings,
										layouts: next
									} });
								}
							}),
							/* @__PURE__ */ jsx(FieldDefinitionListBuilder, {
								value: layout.fields,
								onChange: (fields) => {
									const next = layouts.map((candidate, candidateIndex) => candidateIndex === layoutIndex ? {
										...candidate,
										fields
									} : candidate);
									updateBase({ settings: {
										...settings,
										layouts: next
									} });
								},
								disabled,
								label: `${layout.label} fields`
							}),
							/* @__PURE__ */ jsx("button", {
								type: "button",
								onClick: () => updateBase({ settings: {
									...settings,
									layouts: layouts.filter((_, candidateIndex) => candidateIndex !== layoutIndex)
								} }),
								children: "Remove layout"
							})
						] }, layoutIndex)),
						/* @__PURE__ */ jsx("button", {
							type: "button",
							onClick: () => {
								const suffix = layouts.length + 1;
								updateBase({ settings: {
									...settings,
									layouts: [...layouts, {
										key: `layout_${suffix}`,
										name: `layout_${suffix}`,
										label: `Layout ${suffix}`,
										fields: []
									}]
								} });
							},
							children: "Add layout"
						})
					]
				}) : null,
				/* @__PURE__ */ jsx(ConditionalLogicBuilder, {
					value: value.conditionalLogic,
					onChange: (conditionalLogic) => updateBase({ conditionalLogic }),
					disabled
				}),
				validationError ? /* @__PURE__ */ jsx("div", {
					role: "alert",
					tabIndex: 0,
					children: validationError
				}) : null,
				/* @__PURE__ */ jsxs("div", {
					className: "fields-definition-builder__actions",
					children: [
						/* @__PURE__ */ jsx("button", {
							type: "button",
							"aria-label": `Move ${value.label} up`,
							"aria-disabled": index === 0,
							onClick: () => {
								if (index > 0) onMove(-1);
							},
							children: "Move up"
						}),
						/* @__PURE__ */ jsx("button", {
							type: "button",
							"aria-label": `Move ${value.label} down`,
							"aria-disabled": index === length - 1,
							onClick: () => {
								if (index < length - 1) onMove(1);
							},
							children: "Move down"
						}),
						/* @__PURE__ */ jsx("button", {
							type: "button",
							"aria-label": `Remove ${value.label}`,
							onClick: onRemove,
							children: "Remove field"
						})
					]
				})
			]
		})
	});
}
function FieldDefinitionListBuilder({ value, onChange, disabled, label = "Fields" }) {
	const listId = useId(), idsRef = useRef([]), serialRef = useRef(0);
	while (idsRef.current.length < value.length) idsRef.current.push(`${listId}-field-${serialRef.current++}`);
	if (idsRef.current.length > value.length) idsRef.current.length = value.length;
	const replace = (index, next) => onChange(value.map((field, candidateIndex) => candidateIndex === index ? next : field));
	const move = (index, direction) => {
		const target = index + direction;
		if (target < 0 || target >= value.length) return;
		const next = [...value];
		[next[index], next[target]] = [next[target], next[index]];
		[idsRef.current[index], idsRef.current[target]] = [idsRef.current[target], idsRef.current[index]];
		onChange(next);
	};
	const remove = (index) => {
		idsRef.current.splice(index, 1);
		onChange(value.filter((_, candidateIndex) => candidateIndex !== index));
	};
	const add = () => {
		idsRef.current.push(`${listId}-field-${serialRef.current++}`);
		onChange([...value, defaultField(value.length)]);
	};
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-definition-builder__list",
		"aria-label": label,
		style: { containerType: "inline-size" },
		children: [/* @__PURE__ */ jsx("ol", { children: value.map((field, index) => /* @__PURE__ */ jsx(FieldDefinitionRow, {
			value: field,
			index,
			length: value.length,
			disabled,
			onChange: (next) => replace(index, next),
			onMove: (direction) => move(index, direction),
			onRemove: () => remove(index)
		}, idsRef.current[index])) }), /* @__PURE__ */ jsx("button", {
			type: "button",
			disabled,
			onClick: add,
			children: "Add field"
		})]
	});
}
function FieldGroupDefinitionBuilder({ value, onChange, disabled }) {
	let validationError = null;
	try {
		parseFieldGroupDefinition(value);
	} catch (cause) {
		validationError = cause instanceof Error ? cause.message : String(cause);
	}
	const update = (patch) => onChange({
		...value,
		...patch
	});
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-definition-builder",
		style: {
			containerType: "inline-size",
			containerName: "fields-definition-builder"
		},
		"aria-label": `Field group ${value.title}`,
		children: [/* @__PURE__ */ jsx("style", { children: `.fields-definition-builder__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem}.fields-definition-builder__wide{grid-column:1/-1}.fields-definition-builder__field-row{display:grid;gap:.5rem}.fields-definition-builder__actions{display:flex;gap:.4rem;flex-wrap:wrap}@container fields-definition-builder (max-width:36rem){.fields-definition-builder__grid{grid-template-columns:minmax(0,1fr)}.fields-definition-builder__wide{grid-column:1}}` }), /* @__PURE__ */ jsxs("fieldset", {
			disabled,
			children: [
				/* @__PURE__ */ jsx("legend", { children: "Group definition" }),
				/* @__PURE__ */ jsxs("div", {
					className: "fields-definition-builder__grid",
					children: [
						/* @__PURE__ */ jsxs("label", { children: ["Title", /* @__PURE__ */ jsx("input", {
							"aria-label": "Group title",
							value: value.title,
							onChange: (event) => update({ title: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Key", /* @__PURE__ */ jsx("input", {
							"aria-label": "Group key",
							value: value.key,
							onChange: (event) => update({ key: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Position", /* @__PURE__ */ jsxs("select", {
							"aria-label": "Group position",
							value: value.position ?? "normal",
							onChange: (event) => update({ position: event.currentTarget.value }),
							children: [
								/* @__PURE__ */ jsx("option", {
									value: "normal",
									children: "normal"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "side",
									children: "side"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "afterTitle",
									children: "afterTitle"
								})
							]
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Style", /* @__PURE__ */ jsxs("select", {
							"aria-label": "Group style",
							value: value.style ?? "default",
							onChange: (event) => update({ style: event.currentTarget.value }),
							children: [/* @__PURE__ */ jsx("option", {
								value: "default",
								children: "default"
							}), /* @__PURE__ */ jsx("option", {
								value: "seamless",
								children: "seamless"
							})]
						})] }),
						/* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
							type: "checkbox",
							checked: value.active,
							onChange: (event) => update({ active: event.currentTarget.checked })
						}), " Active"] }),
						/* @__PURE__ */ jsxs("label", { children: ["Order", /* @__PURE__ */ jsx("input", {
							"aria-label": "Group order",
							type: "number",
							value: value.order ?? "",
							onChange: (event) => update({ order: event.currentTarget.value === "" ? void 0 : Number(event.currentTarget.value) })
						})] }),
						/* @__PURE__ */ jsxs("label", {
							className: "fields-definition-builder__wide",
							children: ["Description", /* @__PURE__ */ jsx("textarea", {
								"aria-label": "Group description",
								value: value.description ?? "",
								onChange: (event) => update({ description: event.currentTarget.value || void 0 })
							})]
						})
					]
				}),
				/* @__PURE__ */ jsx(LocationRulesBuilder, {
					value: value.location,
					onChange: (location) => update({ location }),
					disabled
				}),
				/* @__PURE__ */ jsx(FieldDefinitionListBuilder, {
					value: value.fields,
					onChange: (fields) => update({ fields }),
					disabled
				}),
				validationError ? /* @__PURE__ */ jsx("div", {
					role: "alert",
					tabIndex: 0,
					children: validationError
				}) : null
			]
		})]
	});
}
//#endregion
//#region src/options-editor.tsx
function OptionsPageDefinitionEditor({ value, onChange, availableParents = [], disabled }) {
	const update = (patch) => onChange({
		...value,
		...patch
	});
	const issues = [];
	if (!/^[a-z][a-z0-9_-]*$/.test(value.key)) issues.push("Key must be normalized");
	if (!value.title.trim()) issues.push("Title is required");
	for (const [label, capability] of [
		["Read capability", value.readCapability],
		["Write capability", value.writeCapability],
		["Manage capability", value.manageCapability]
	]) if (!capability.trim()) issues.push(`${label} is required`);
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-options-editor",
		style: {
			containerType: "inline-size",
			containerName: "fields-options"
		},
		"aria-label": `Options Page ${value.title || value.key}`,
		children: [/* @__PURE__ */ jsx("style", { children: `.fields-options-editor__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem}.fields-options-editor__wide{grid-column:1/-1}@container fields-options (max-width:36rem){.fields-options-editor__grid{grid-template-columns:minmax(0,1fr)}.fields-options-editor__wide{grid-column:1}}` }), /* @__PURE__ */ jsxs("fieldset", {
			disabled,
			children: [
				/* @__PURE__ */ jsx("legend", { children: "Options Page definition" }),
				/* @__PURE__ */ jsxs("div", {
					className: "fields-options-editor__grid",
					children: [
						/* @__PURE__ */ jsxs("label", { children: ["Title", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page title",
							value: value.title,
							onChange: (event) => update({ title: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Key", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page key",
							value: value.key,
							onChange: (event) => update({ key: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Menu title", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page menu title",
							value: value.menuTitle ?? "",
							onChange: (event) => update({ menuTitle: event.currentTarget.value || void 0 })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Parent", /* @__PURE__ */ jsxs("select", {
							"aria-label": "Options Page parent",
							value: value.parentKey ?? "",
							onChange: (event) => update({ parentKey: event.currentTarget.value || void 0 }),
							children: [/* @__PURE__ */ jsx("option", {
								value: "",
								children: "—"
							}), availableParents.filter((page) => page.key !== value.key).map((page) => /* @__PURE__ */ jsx("option", {
								value: page.key,
								children: page.title
							}, page.key))]
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Read capability", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page read capability",
							value: value.readCapability,
							onChange: (event) => update({ readCapability: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Write capability", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page write capability",
							value: value.writeCapability,
							onChange: (event) => update({ writeCapability: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Manage capability", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page manage capability",
							value: value.manageCapability,
							onChange: (event) => update({ manageCapability: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Position", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page position",
							type: "number",
							value: value.position ?? "",
							onChange: (event) => update({ position: event.currentTarget.value === "" ? void 0 : Number(event.currentTarget.value) })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Icon", /* @__PURE__ */ jsx("input", {
							"aria-label": "Options Page icon",
							value: value.icon ?? "",
							onChange: (event) => update({ icon: event.currentTarget.value || void 0 })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
							type: "checkbox",
							checked: value.redirectToFirstChild === true,
							onChange: (event) => update({ redirectToFirstChild: event.currentTarget.checked || void 0 })
						}), " Redirect to first child"] }),
						/* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
							type: "checkbox",
							checked: value.autoload === true,
							onChange: (event) => update({ autoload: event.currentTarget.checked || void 0 })
						}), " Autoload"] })
					]
				}),
				issues.length ? /* @__PURE__ */ jsx("div", {
					role: "alert",
					tabIndex: 0,
					children: issues.join(". ")
				}) : null
			]
		})]
	});
}
function OptionsPageValuesEditor({ page, groups, value, onChange, errors = {}, disabled, readOnly, adapters }) {
	return /* @__PURE__ */ jsx("section", {
		className: "fields-options-values",
		style: { containerType: "inline-size" },
		"aria-label": `${page.title} values`,
		children: groups.map((group) => /* @__PURE__ */ jsxs("fieldset", {
			disabled,
			children: [/* @__PURE__ */ jsx("legend", { children: group.title }), /* @__PURE__ */ jsx(CompleteFieldValuesEditor, {
				fields: group.fields,
				value: value[group.key] ?? {},
				onChange: (next) => onChange({
					...value,
					[group.key]: next
				}),
				errors: errors[group.key] ?? [],
				disabled,
				readOnly,
				adapters,
				path: [group.key],
				idPrefix: `options-${page.key}-${group.key}`
			})]
		}, group.key))
	});
}
//#endregion
//#region src/block-editor.tsx
const ALIGNMENTS = [
	"left",
	"center",
	"right",
	"wide",
	"full"
];
const SUPPORT_KEYS = [
	"anchor",
	"className",
	"multiple",
	"reusable",
	"innerBlocks",
	"jsx"
];
function uniqueList(raw) {
	return Object.freeze([...new Set(raw.split(",").map((item) => item.trim()).filter(Boolean))]);
}
function JsonEditor({ label, value, onChange, disabled }) {
	const serialized = useMemo(() => JSON.stringify(value ?? {}, null, 2), [value]), [draft, setDraft] = useState(serialized), [error, setError] = useState(null);
	useEffect(() => setDraft(serialized), [serialized]);
	return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("label", { children: [label, /* @__PURE__ */ jsx("textarea", {
		rows: 6,
		value: draft,
		disabled,
		onChange: (event) => {
			const next = event.currentTarget.value;
			setDraft(next);
			try {
				const parsed = JSON.parse(next);
				setError(null);
				onChange(parsed);
			} catch (cause) {
				setError(cause instanceof Error ? cause.message : String(cause));
			}
		}
	})] }), error ? /* @__PURE__ */ jsx("div", {
		role: "alert",
		tabIndex: 0,
		children: error
	}) : null] });
}
function FieldBlockDefinitionEditor({ value, onChange, availableGroupKeys = [], availableBlockKeys = [], disabled }) {
	const update = (patch) => onChange({
		...value,
		...patch
	});
	const support = value.supports ?? {};
	const issues = [];
	if (!/^[a-z][a-z0-9_-]*$/.test(value.key)) issues.push("Block key must be normalized");
	if (!value.title.trim()) issues.push("Block title is required");
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-block-definition",
		style: {
			containerType: "inline-size",
			containerName: "fields-block-definition"
		},
		"aria-label": `Block ${value.title || value.key}`,
		children: [/* @__PURE__ */ jsx("style", { children: `.fields-block-definition__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem}.fields-block-definition__wide{grid-column:1/-1}.fields-block-definition__checks{display:flex;gap:.7rem;flex-wrap:wrap}@container fields-block-definition (max-width:36rem){.fields-block-definition__grid{grid-template-columns:minmax(0,1fr)}.fields-block-definition__wide{grid-column:1}}` }), /* @__PURE__ */ jsxs("fieldset", {
			disabled,
			children: [
				/* @__PURE__ */ jsx("legend", { children: "Block definition" }),
				/* @__PURE__ */ jsxs("div", {
					className: "fields-block-definition__grid",
					children: [
						/* @__PURE__ */ jsxs("label", { children: ["Title", /* @__PURE__ */ jsx("input", {
							"aria-label": "Block title",
							value: value.title,
							onChange: (event) => update({ title: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Key", /* @__PURE__ */ jsx("input", {
							"aria-label": "Block key",
							value: value.key,
							onChange: (event) => update({ key: event.currentTarget.value })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Category", /* @__PURE__ */ jsx("input", {
							"aria-label": "Block category",
							value: value.category ?? "",
							onChange: (event) => update({ category: event.currentTarget.value || void 0 })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Icon", /* @__PURE__ */ jsx("input", {
							"aria-label": "Block icon",
							value: value.icon ?? "",
							onChange: (event) => update({ icon: event.currentTarget.value || void 0 })
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Mode", /* @__PURE__ */ jsxs("select", {
							"aria-label": "Block mode",
							value: value.mode ?? "auto",
							onChange: (event) => update({ mode: event.currentTarget.value }),
							children: [
								/* @__PURE__ */ jsx("option", {
									value: "auto",
									children: "auto"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "preview",
									children: "preview"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "edit",
									children: "edit"
								})
							]
						})] }),
						/* @__PURE__ */ jsxs("label", { children: ["Template lock", /* @__PURE__ */ jsxs("select", {
							"aria-label": "Block template lock",
							value: value.templateLock === false ? "false" : value.templateLock ?? "false",
							onChange: (event) => update({ templateLock: event.currentTarget.value === "false" ? false : event.currentTarget.value }),
							children: [
								/* @__PURE__ */ jsx("option", {
									value: "false",
									children: "unlocked"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "insert",
									children: "insert"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "all",
									children: "all"
								}),
								/* @__PURE__ */ jsx("option", {
									value: "contentOnly",
									children: "contentOnly"
								})
							]
						})] }),
						/* @__PURE__ */ jsxs("label", {
							className: "fields-block-definition__wide",
							children: ["Description", /* @__PURE__ */ jsx("textarea", {
								"aria-label": "Block description",
								value: value.description ?? "",
								onChange: (event) => update({ description: event.currentTarget.value || void 0 })
							})]
						}),
						/* @__PURE__ */ jsxs("label", {
							className: "fields-block-definition__wide",
							children: ["Keywords", /* @__PURE__ */ jsx("input", {
								"aria-label": "Block keywords",
								value: (value.keywords ?? []).join(", "),
								onChange: (event) => update({ keywords: uniqueList(event.currentTarget.value) })
							})]
						}),
						/* @__PURE__ */ jsxs("label", {
							className: "fields-block-definition__wide",
							children: ["Parent blocks", /* @__PURE__ */ jsx("input", {
								"aria-label": "Block parents",
								value: (value.parent ?? []).join(", "),
								onChange: (event) => update({ parent: uniqueList(event.currentTarget.value) })
							})]
						}),
						/* @__PURE__ */ jsxs("label", {
							className: "fields-block-definition__wide",
							children: ["Ancestor blocks", /* @__PURE__ */ jsx("input", {
								"aria-label": "Block ancestors",
								value: (value.ancestor ?? []).join(", "),
								onChange: (event) => update({ ancestor: uniqueList(event.currentTarget.value) })
							})]
						})
					]
				}),
				/* @__PURE__ */ jsxs("fieldset", { children: [/* @__PURE__ */ jsx("legend", { children: "Field groups" }), /* @__PURE__ */ jsx("div", {
					className: "fields-block-definition__checks",
					children: availableGroupKeys.map((key) => /* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
						type: "checkbox",
						checked: value.fieldGroupKeys.includes(key),
						onChange: (event) => update({ fieldGroupKeys: event.currentTarget.checked ? [...value.fieldGroupKeys, key] : value.fieldGroupKeys.filter((candidate) => candidate !== key) })
					}), key] }, key))
				})] }),
				/* @__PURE__ */ jsxs("fieldset", { children: [/* @__PURE__ */ jsx("legend", { children: "Alignment" }), /* @__PURE__ */ jsx("div", {
					className: "fields-block-definition__checks",
					children: ALIGNMENTS.map((align) => /* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
						type: "checkbox",
						checked: (value.align ?? []).includes(align),
						onChange: (event) => update({ align: event.currentTarget.checked ? [...value.align ?? [], align] : (value.align ?? []).filter((candidate) => candidate !== align) })
					}), align] }, align))
				})] }),
				/* @__PURE__ */ jsxs("fieldset", { children: [/* @__PURE__ */ jsx("legend", { children: "Supports" }), /* @__PURE__ */ jsx("div", {
					className: "fields-block-definition__checks",
					children: SUPPORT_KEYS.map((key) => /* @__PURE__ */ jsxs("label", { children: [/* @__PURE__ */ jsx("input", {
						type: "checkbox",
						checked: support[key] === true,
						onChange: (event) => update({ supports: {
							...support,
							[key]: event.currentTarget.checked || void 0
						} })
					}), key] }, key))
				})] }),
				availableBlockKeys.length ? /* @__PURE__ */ jsxs("div", {
					role: "note",
					children: ["Available block keys: ", availableBlockKeys.join(", ")]
				}) : null,
				/* @__PURE__ */ jsx(JsonEditor, {
					label: "Template JSON",
					value: value.template ?? [],
					disabled,
					onChange: (template) => update({ template: Array.isArray(template) ? template : void 0 })
				}),
				issues.length ? /* @__PURE__ */ jsx("div", {
					role: "alert",
					tabIndex: 0,
					children: issues.join(". ")
				}) : null
			]
		})]
	});
}
function createId() {
	return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `block-${Date.now()}-${Math.random().toString(36).slice(2)}`;
}
function latestGroupBinding(bindings, key) {
	return bindings.filter((binding) => binding.group.key === key).sort((a, b) => b.revision - a.revision)[0];
}
function exactGroupBinding(bindings, key, revision) {
	return bindings.find((binding) => binding.group.key === key && binding.revision === revision);
}
function latestBlockBinding(bindings, key) {
	return bindings.filter((binding) => binding.block.key === key).sort((a, b) => b.revision - a.revision)[0];
}
function exactBlockBinding(bindings, key, revision) {
	return bindings.find((binding) => binding.block.key === key && binding.revision === revision);
}
function latestBlockBindings(bindings) {
	const keys = [...new Set(bindings.map((binding) => binding.block.key))];
	return Object.freeze(keys.map((key) => latestBlockBinding(bindings, key)).filter(Boolean));
}
function canCreateInline(binding, groups) {
	return binding.block.fieldGroupKeys.every((key) => latestGroupBinding(groups, key) !== void 0);
}
function newInline(binding, groups, id) {
	return {
		kind: "inline",
		id,
		type: binding.block.key,
		blockDefinitionRevision: binding.revision,
		fieldGroups: binding.block.fieldGroupKeys.map((key) => {
			const group = latestGroupBinding(groups, key);
			if (!group) throw new Error(`Missing field group binding ${key}`);
			return {
				groupKey: key,
				definitionRevision: group.revision,
				values: {}
			};
		})
	};
}
function BlockNodeList({ nodes, onChange, blocks, groups, errors, disabled, readOnly, adapters, path, announce, scopeLabel }) {
	const locked = disabled || readOnly;
	const replace = (index, node) => onChange(nodes.map((candidate, candidateIndex) => candidateIndex === index ? node : candidate));
	const move = (index, direction) => {
		const target = index + direction;
		if (target < 0 || target >= nodes.length) return;
		const next = [...nodes];
		[next[index], next[target]] = [next[target], next[index]];
		onChange(next);
		announce(`Block moved ${direction < 0 ? "up" : "down"}`);
	};
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-block-document__list",
		children: [nodes.map((node, index) => /* @__PURE__ */ jsxs("article", {
			className: "fields-block-document__node",
			"aria-label": `Block ${index + 1}`,
			children: [node.kind === "reusable" ? /* @__PURE__ */ jsxs("div", {
				className: "fields-block-document__grid",
				children: [/* @__PURE__ */ jsx("strong", { children: "Reusable block" }), /* @__PURE__ */ jsxs("label", { children: ["Reusable ID", /* @__PURE__ */ jsx("input", {
					"aria-label": `Block ${index + 1} reusable id`,
					disabled: locked,
					value: node.reusableId,
					onChange: (event) => replace(index, {
						...node,
						reusableId: event.currentTarget.value
					})
				})] })]
			}) : /* @__PURE__ */ jsx(InlineNodeEditor, {
				node,
				onChange: (next) => replace(index, next),
				blocks,
				groups,
				errors,
				disabled,
				readOnly,
				adapters,
				path: [...path, node.id],
				announce
			}), /* @__PURE__ */ jsxs("div", {
				className: "fields-block-document__actions",
				children: [
					/* @__PURE__ */ jsx("button", {
						type: "button",
						"aria-label": `Move block ${index + 1} up`,
						"aria-disabled": index === 0 || locked,
						disabled: locked,
						onClick: () => {
							if (index > 0) move(index, -1);
						},
						children: "Move up"
					}),
					/* @__PURE__ */ jsx("button", {
						type: "button",
						"aria-label": `Move block ${index + 1} down`,
						"aria-disabled": index === nodes.length - 1 || locked,
						disabled: locked,
						onClick: () => {
							if (index < nodes.length - 1) move(index, 1);
						},
						children: "Move down"
					}),
					/* @__PURE__ */ jsx("button", {
						type: "button",
						"aria-label": `Remove block ${index + 1}`,
						disabled: locked,
						onClick: () => {
							onChange(nodes.filter((_, candidateIndex) => candidateIndex !== index));
							announce("Block removed");
						},
						children: "Remove"
					})
				]
			})]
		}, node.id)), /* @__PURE__ */ jsxs("div", {
			className: "fields-block-document__actions",
			children: [latestBlockBindings(blocks).map((binding) => {
				const missingGroups = binding.block.fieldGroupKeys.filter((key) => !latestGroupBinding(groups, key));
				return /* @__PURE__ */ jsxs("span", { children: [missingGroups.length ? /* @__PURE__ */ jsxs("span", {
					role: "alert",
					className: "sr-only",
					children: [
						"Cannot add ",
						binding.block.title,
						": missing field groups ",
						missingGroups.join(", ")
					]
				}) : null, /* @__PURE__ */ jsxs("button", {
					type: "button",
					"aria-label": `Add ${binding.block.title} to ${scopeLabel}`,
					disabled: locked || missingGroups.length > 0,
					onClick: () => {
						if (missingGroups.length) return;
						onChange([...nodes, newInline(binding, groups, (adapters.createNodeId ?? createId)())]);
						announce(`${binding.block.title} block added`);
					},
					children: ["Add ", binding.block.title]
				})] }, binding.block.key);
			}), /* @__PURE__ */ jsx("button", {
				type: "button",
				"aria-label": `Add reusable block to ${scopeLabel}`,
				disabled: locked,
				onClick: () => {
					onChange([...nodes, {
						kind: "reusable",
						id: (adapters.createNodeId ?? createId)(),
						reusableId: ""
					}]);
					announce("Reusable block added");
				},
				children: "Add reusable block"
			})]
		})]
	});
}
function InlineNodeEditor({ node, onChange, blocks, groups, errors, disabled, readOnly, adapters, path, announce }) {
	const definition = exactBlockBinding(blocks, node.type, node.blockDefinitionRevision)?.block, locked = disabled || readOnly;
	const fieldGroups = new Map(node.fieldGroups.map((group) => [group.groupKey, group]));
	const updateGroup = (groupKey, next) => {
		const nextGroups = (definition?.fieldGroupKeys ?? []).map((key) => {
			const existing = fieldGroups.get(key), group = existing ? exactGroupBinding(groups, key, existing.definitionRevision) : latestGroupBinding(groups, key);
			if (!group) throw new Error(`Missing field group binding ${key}${existing ? `@${existing.definitionRevision}` : ""}`);
			return {
				groupKey: key,
				definitionRevision: existing?.definitionRevision ?? group.revision,
				values: key === groupKey ? next : existing?.values ?? {}
			};
		});
		onChange({
			...node,
			fieldGroups: nextGroups
		});
	};
	const changeType = (key) => {
		const nextBinding = latestBlockBinding(blocks, key);
		if (!nextBinding || !canCreateInline(nextBinding, groups)) return;
		onChange({
			...newInline(nextBinding, groups, node.id),
			...node.attributes ? { attributes: node.attributes } : {},
			...node.children ? { children: node.children } : {}
		});
	};
	return /* @__PURE__ */ jsxs("div", {
		className: "fields-block-document__inline",
		children: [
			/* @__PURE__ */ jsxs("div", {
				className: "fields-block-document__grid",
				children: [/* @__PURE__ */ jsxs("label", { children: ["Block type", /* @__PURE__ */ jsx("select", {
					"aria-label": `Block ${node.id} type`,
					disabled: locked,
					value: node.type,
					onChange: (event) => changeType(event.currentTarget.value),
					children: latestBlockBindings(blocks).map((candidate) => /* @__PURE__ */ jsx("option", {
						value: candidate.block.key,
						disabled: !canCreateInline(candidate, groups),
						children: candidate.block.title
					}, candidate.block.key))
				})] }), /* @__PURE__ */ jsxs("span", { children: ["Revision ", node.blockDefinitionRevision] })]
			}),
			!definition ? /* @__PURE__ */ jsxs("div", {
				role: "alert",
				tabIndex: 0,
				children: [
					"Unavailable block definition ",
					node.type,
					"@",
					node.blockDefinitionRevision
				]
			}) : definition.fieldGroupKeys.map((key) => {
				const current = fieldGroups.get(key), group = current ? exactGroupBinding(groups, key, current.definitionRevision) : latestGroupBinding(groups, key);
				return /* @__PURE__ */ jsxs("fieldset", {
					disabled,
					children: [/* @__PURE__ */ jsx("legend", { children: group?.group.title ?? key }), group ? /* @__PURE__ */ jsx(CompleteFieldValuesEditor, {
						fields: group.group.fields,
						value: current?.values ?? {},
						onChange: (next) => updateGroup(key, next),
						errors: errors[`${node.id}:${key}`] ?? [],
						disabled,
						readOnly,
						adapters,
						path: [...path, key],
						idPrefix: `block-${node.id}-${key}`
					}) : /* @__PURE__ */ jsxs("div", {
						role: "alert",
						tabIndex: 0,
						children: [
							"Unavailable field group ",
							key,
							current ? `@${current.definitionRevision}` : ""
						]
					})]
				}, key);
			}),
			/* @__PURE__ */ jsx(JsonEditor, {
				label: "Block attributes JSON",
				value: node.attributes ?? {},
				disabled: locked,
				onChange: (attributes) => onChange({
					...node,
					attributes: attributes && typeof attributes === "object" && !Array.isArray(attributes) ? attributes : void 0
				})
			}),
			definition?.supports?.innerBlocks ? /* @__PURE__ */ jsxs("fieldset", {
				disabled,
				children: [/* @__PURE__ */ jsx("legend", { children: "Inner blocks" }), /* @__PURE__ */ jsx(BlockNodeList, {
					nodes: node.children ?? [],
					onChange: (children) => onChange({
						...node,
						children
					}),
					blocks,
					groups,
					errors,
					disabled,
					readOnly,
					adapters,
					path: [...path, "children"],
					announce,
					scopeLabel: `inner blocks of ${node.id}`
				})]
			}) : null
		]
	});
}
function BlockDocumentEditor({ value, onChange, blocks, groups, errors = {}, disabled = false, readOnly = false, adapters = {} }) {
	const [announcement, setAnnouncement] = useState("");
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-block-document",
		style: {
			containerType: "inline-size",
			containerName: "fields-block-document"
		},
		"aria-label": "Block document editor",
		children: [
			/* @__PURE__ */ jsx("style", { children: `.fields-block-document__list{display:grid;gap:.8rem}.fields-block-document__node{border:1px solid currentColor;border-radius:.35rem;padding:.75rem;display:grid;gap:.6rem}.fields-block-document__grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.65rem}.fields-block-document__actions{display:flex;gap:.4rem;flex-wrap:wrap}@container fields-block-document (max-width:36rem){.fields-block-document__grid{grid-template-columns:minmax(0,1fr)}}` }),
			/* @__PURE__ */ jsx("div", {
				role: "status",
				"aria-label": "Block document status",
				"aria-live": "polite",
				"aria-atomic": "true",
				style: {
					position: "absolute",
					width: 1,
					height: 1,
					overflow: "hidden",
					clip: "rect(0 0 0 0)"
				},
				children: announcement
			}),
			/* @__PURE__ */ jsx(BlockNodeList, {
				nodes: value.roots,
				onChange: (roots) => onChange({
					version: 1,
					roots
				}),
				blocks,
				groups,
				errors,
				disabled,
				readOnly,
				adapters,
				path: ["roots"],
				announce: setAnnouncement,
				scopeLabel: "document"
			})
		]
	});
}
function PreviewNodes({ nodes, blocks, adapter }) {
	return /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node) => {
		if (node.kind === "reusable") return /* @__PURE__ */ jsx("div", {
			"data-preview-node": node.id,
			children: adapter.renderReusable({ node })
		}, node.id);
		const binding = exactBlockBinding(blocks, node.type, node.blockDefinitionRevision);
		if (!binding || binding.revision !== node.blockDefinitionRevision) return /* @__PURE__ */ jsxs("div", {
			role: "alert",
			tabIndex: 0,
			children: [
				"Unavailable block definition ",
				node.type,
				"@",
				node.blockDefinitionRevision
			]
		}, node.id);
		const children = /* @__PURE__ */ jsx(PreviewNodes, {
			nodes: node.children ?? [],
			blocks,
			adapter
		});
		return /* @__PURE__ */ jsx("div", {
			"data-preview-node": node.id,
			children: adapter.renderInline({
				node,
				binding,
				children
			})
		}, node.id);
	}) });
}
function BlockDocumentPreview({ document, blocks, adapter }) {
	return /* @__PURE__ */ jsx("section", {
		className: "fields-block-preview",
		style: { containerType: "inline-size" },
		"aria-label": "Block document preview",
		children: /* @__PURE__ */ jsx(PreviewNodes, {
			nodes: document.roots,
			blocks,
			adapter
		})
	});
}
//#endregion
//#region src/revision-ui.tsx
function displayPath(path) {
	return path.map(String).join(" › ");
}
function pathId(prefix, path) {
	return `${prefix}-${path.map((segment) => String(segment).replace(/[^a-zA-Z0-9_-]/g, "_")).join("__") || "root"}`;
}
function FieldValidationSummary({ issues, idPrefix = "fields-react", title = "Fix validation errors" }) {
	if (!issues.length) return null;
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-validation-summary",
		role: "alert",
		"aria-labelledby": `${idPrefix}-validation-title`,
		tabIndex: -1,
		children: [/* @__PURE__ */ jsx("h2", {
			id: `${idPrefix}-validation-title`,
			children: title
		}), /* @__PURE__ */ jsx("ul", { children: issues.map((issue, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs("a", {
			href: `#${pathId(idPrefix, issue.path)}`,
			children: [
				displayPath(issue.path) || "Form",
				": ",
				issue.message
			]
		}) }, `${index}:${displayPath(issue.path)}`)) })]
	});
}
function FieldsRevisionDiffView({ diff, leftLabel = "Earlier revision", rightLabel = "Later revision" }) {
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-revision-diff",
		"aria-label": `${leftLabel} compared with ${rightLabel}`,
		style: { containerType: "inline-size" },
		children: [
			/* @__PURE__ */ jsx("h3", { children: "Field changes" }),
			diff.valuePaths.length ? /* @__PURE__ */ jsx("ul", { children: diff.valuePaths.map((change, index) => /* @__PURE__ */ jsxs("li", { children: [
				/* @__PURE__ */ jsx("strong", { children: change.kind }),
				" ",
				/* @__PURE__ */ jsx("code", { children: displayPath(change.path) })
			] }, `${index}:${displayPath(change.path)}`)) }) : /* @__PURE__ */ jsx("p", { children: "No field value changes." }),
			/* @__PURE__ */ jsx("h3", { children: "Block changes" }),
			diff.blockNodes.length ? /* @__PURE__ */ jsx("ul", { children: diff.blockNodes.map((change) => /* @__PURE__ */ jsxs("li", { children: [
				/* @__PURE__ */ jsx("strong", { children: change.kind }),
				" block ",
				/* @__PURE__ */ jsx("code", { children: change.nodeId })
			] }, `${change.nodeId}:${change.kind}`)) }) : /* @__PURE__ */ jsx("p", { children: "No block changes." })
		]
	});
}
function FieldsRevisionRestorePanel({ revision, diff, onRestore, disabled = false, confirmationLabel = "I understand this writes a new current snapshot" }) {
	const [confirmed, setConfirmed] = useState(false), [busy, setBusy] = useState(false), [status, setStatus] = useState(""), [error, setError] = useState(null);
	const restore = async () => {
		if (!confirmed || busy || disabled) return;
		setBusy(true);
		setError(null);
		try {
			await onRestore(revision);
			setStatus(`Revision from ${revision.createdAt.toLocaleString()} restored`);
			setConfirmed(false);
		} catch (cause) {
			setError(cause instanceof Error ? cause.message : String(cause));
		} finally {
			setBusy(false);
		}
	};
	return /* @__PURE__ */ jsxs("section", {
		className: "fields-revision-restore",
		style: { containerType: "inline-size" },
		"aria-label": "Restore field revision",
		children: [
			/* @__PURE__ */ jsx("div", {
				role: "status",
				"aria-live": "polite",
				children: status
			}),
			error ? /* @__PURE__ */ jsx("div", {
				role: "alert",
				tabIndex: 0,
				children: error
			}) : null,
			/* @__PURE__ */ jsxs("dl", { children: [
				/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Created" }), /* @__PURE__ */ jsx("dd", { children: revision.createdAt.toLocaleString() })] }),
				/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Created by" }), /* @__PURE__ */ jsx("dd", { children: revision.createdBy })] }),
				/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Kind" }), /* @__PURE__ */ jsx("dd", { children: revision.kind })] }),
				/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("dt", { children: "Source version" }), /* @__PURE__ */ jsx("dd", { children: revision.sourceVersion })] })
			] }),
			diff ? /* @__PURE__ */ jsx(FieldsRevisionDiffView, { diff }) : null,
			/* @__PURE__ */ jsx("p", {
				role: "note",
				children: "Password credentials are not restored from revisions; only their configured marker is retained in revision data."
			}),
			/* @__PURE__ */ jsxs("label", { children: [
				/* @__PURE__ */ jsx("input", {
					type: "checkbox",
					checked: confirmed,
					disabled: disabled || busy,
					onChange: (event) => setConfirmed(event.currentTarget.checked)
				}),
				" ",
				confirmationLabel
			] }),
			/* @__PURE__ */ jsx("button", {
				type: "button",
				disabled: disabled || busy || !confirmed,
				onClick: () => void restore(),
				children: busy ? "Restoring…" : "Restore revision"
			})
		]
	});
}
//#endregion
export { AsyncOptionSearch, BlockDocumentEditor, BlockDocumentPreview, COMPLETE_FIELD_TYPES, CompleteFieldValuesEditor, CustomFieldSurface, FieldBlockDefinitionEditor, FieldDefinitionListBuilder, FieldGroupDefinitionBuilder, FieldGroupEditor, FieldValidationSummary, FieldValuesForm, FieldsProvider, FieldsRevisionDiffView, FieldsRevisionRestorePanel, OptionsPageDefinitionEditor, OptionsPageValuesEditor, createReactFieldSurfaceRegistry, referenceInputs, useEntityFields, useFieldGroupBuilder, useFieldValues, useFieldsClient };
