/**
 * Copyright IBM Corp. 2020, 2026
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

const require_runtime = require("../../_virtual/_rolldown/runtime.js");
const require_index = require("../../node_modules/classnames/index.js");
const require_settings = require("../../settings.js");
const require_devtools = require("../../global/js/utils/devtools.js");
let react = require("react");
react = require_runtime.__toESM(react);
let prop_types = require("prop-types");
prop_types = require_runtime.__toESM(prop_types);
let _carbon_react = require("@carbon/react");
let _carbon_react_icons = require("@carbon/react/icons");
//#region src/components/EditInPlace/EditInPlace.tsx
/**
* Copyright IBM Corp. 2022, 2025
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
*/
var import_classnames = /* @__PURE__ */ require_runtime.__toESM(require_index.default);
const componentName = "EditInPlace";
const blockClass = `${require_settings.pkg.prefix}--edit-in-place`;
const defaults = {
	tooltipAlignment: "top",
	size: "sm"
};
const EditInPlace = (0, react.forwardRef)(({ cancelLabel, editAlwaysVisible, editLabel, id, inheritTypography, invalid, invalidLabel: deprecated_invalidLabel = " ", invalidText, labelText, onCancel, onChange, onSave, onBlur, readOnly, readOnlyLabel, readOnlyToggleTipText, saveLabel, size = "sm", toggleTipAlignment, tooltipAlignment, value, placeholder, ...rest }, ref) => {
	const [focused, setFocused] = (0, react.useState)(false);
	const [initialValue, setInitialValue] = (0, react.useState)(value);
	const [dirtyInput, setDirtyInput] = (0, react.useState)(false);
	const inputRef = (0, react.useRef)(null);
	const hasValueChanged = value.trim() !== initialValue.trim();
	const canSave = hasValueChanged && !invalid;
	const canCancel = hasValueChanged;
	const escaping = (0, react.useRef)(false);
	const clickingWithin = (0, react.useRef)(false);
	const carbonPrefix = (0, _carbon_react.usePrefix)();
	const tipAlignIsObject = typeof tooltipAlignment === "object";
	const tipAlignments = [
		"edit",
		"save",
		"cancel"
	].reduce((acc, tips) => {
		acc[tips] = (tipAlignIsObject ? tooltipAlignment[tips] : tooltipAlignment) ?? defaults.tooltipAlignment;
		return acc;
	}, {});
	const isTargetingChild = ({ currentTarget, relatedTarget }) => currentTarget.contains(relatedTarget);
	const onChangeHandler = ({ target }) => {
		if (!dirtyInput) setDirtyInput(true);
		onChange(target.value);
	};
	const onFocusHandler = (e) => {
		if (!isTargetingChild(e)) inputRef.current?.focus();
		setFocused(true);
	};
	const onSaveHandler = (exitEditMode = false) => {
		setInitialValue(value);
		setDirtyInput(false);
		onSave();
		if (exitEditMode) setFocused(false);
		else requestAnimationFrame(() => {
			inputRef.current?.focus();
		});
	};
	const onCancelHandler = (exitEditMode = false) => {
		setDirtyInput(false);
		onCancel(initialValue);
		if (exitEditMode) setFocused(false);
		else requestAnimationFrame(() => {
			if (inputRef.current) {
				inputRef.current.focus();
				const length = inputRef.current.value.length;
				inputRef.current.setSelectionRange(length, length);
			}
		});
	};
	const onBlurHandler = (e) => {
		const clickedWithin = clickingWithin.current;
		const targetingChild = isTargetingChild(e);
		if (clickedWithin && targetingChild) {
			clickingWithin.current = false;
			return;
		}
		if (clickedWithin && !targetingChild) clickingWithin.current = false;
		if (!clickedWithin && targetingChild) return;
		if (typeof onBlur === "function") {
			onBlur(initialValue);
			setFocused(false);
		} else {
			if (escaping.current) return;
			if (canSave) onSaveHandler(true);
			else {
				onCancelHandler(true);
				setFocused(false);
			}
		}
	};
	const returnHandler = () => {
		if (canSave) onSaveHandler();
	};
	const escapeHandler = () => {
		onCancelHandler();
	};
	const removeFocus = () => {
		inputRef.current?.blur();
		setFocused(false);
	};
	const handleToolbarMouseDown = (e) => {
		const element = e.target;
		let foundButton = null;
		let current = element;
		while (current && current !== e.currentTarget) {
			if (current.tagName === "BUTTON") {
				foundButton = current;
				break;
			}
			current = current.parentElement;
		}
		if (!foundButton) foundButton = element.querySelector("button");
		if (foundButton) {
			clickingWithin.current = true;
			if (foundButton.hasAttribute("disabled") || foundButton.getAttribute("aria-disabled") === "true") e.preventDefault();
		}
	};
	const onKeyHandler = (e) => {
		escaping.current = true;
		switch (e.key) {
			case "Escape":
				removeFocus();
				escapeHandler();
				break;
			case "Enter":
				removeFocus();
				returnHandler();
				break;
			default: break;
		}
		escaping.current = false;
	};
	const inputElement = /* @__PURE__ */ react.default.createElement("input", {
		id,
		className: (0, import_classnames.default)(`${blockClass}__text-input`, `${carbonPrefix}--text-input`, `${carbonPrefix}--text-input--${size}`),
		type: "text",
		placeholder,
		value,
		onChange: onChangeHandler,
		ref: inputRef,
		readOnly,
		onKeyDown: onKeyHandler,
		"aria-label": labelText,
		"aria-invalid": invalid
	});
	const inputContainer = /* @__PURE__ */ react.default.createElement("div", {
		className: (0, import_classnames.default)(blockClass, `${blockClass}--${size}`, {
			[`${blockClass}--focused`]: focused,
			[`${blockClass}--invalid`]: invalid,
			[`${blockClass}--inherit-type`]: inheritTypography,
			[`${blockClass}--overflows`]: inputRef.current && inputRef.current.scrollWidth > inputRef.current.offsetWidth,
			[`${blockClass}--readonly`]: readOnly
		}),
		onFocus: onFocusHandler,
		onBlur: onBlurHandler
	}, readOnly ? /* @__PURE__ */ react.default.createElement(_carbon_react.Toggletip, {
		align: toggleTipAlignment,
		className: `${blockClass}__toggletip-wrapper`
	}, /* @__PURE__ */ react.default.createElement(_carbon_react.ToggletipButton, { label: readOnlyLabel || "Edit off" }, inputElement), /* @__PURE__ */ react.default.createElement(_carbon_react.ToggletipContent, null, /* @__PURE__ */ react.default.createElement("p", null, readOnlyToggleTipText || "This field is read-only and cannot be edited"))) : inputElement, /* @__PURE__ */ react.default.createElement("div", {
		className: `${blockClass}__toolbar`,
		onMouseDown: handleToolbarMouseDown
	}, invalid && /* @__PURE__ */ react.default.createElement(_carbon_react_icons.WarningFilled, {
		size: 16,
		className: `${blockClass}__warning-icon`
	}), readOnly ? /* @__PURE__ */ react.default.createElement(_carbon_react.IconButton, {
		className: `${blockClass}__btn-readonly`,
		size,
		label: readOnlyLabel || "Edit off",
		kind: "ghost",
		key: "readonly",
		onClick: onFocusHandler
	}, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.EditOff, { size: 16 })) : focused ? /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement(_carbon_react.IconButton, {
		align: tipAlignments.cancel,
		size,
		label: cancelLabel,
		onClick: () => onCancelHandler(false),
		kind: "ghost",
		key: "cancel",
		className: `${blockClass}__btn ${blockClass}__btn-cancel`,
		disabled: !canCancel
	}, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.Close, { size: 16 })), /* @__PURE__ */ react.default.createElement(_carbon_react.IconButton, {
		align: tipAlignments.save,
		size,
		label: saveLabel,
		onClick: () => onSaveHandler(false),
		kind: "ghost",
		key: "save",
		className: `${blockClass}__btn ${blockClass}__btn-save`,
		disabled: !canSave
	}, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.Checkmark, { size: 16 }))) : /* @__PURE__ */ react.default.createElement(_carbon_react.IconButton, {
		align: tipAlignments.edit,
		className: (0, import_classnames.default)(`${blockClass}__btn`, `${blockClass}__btn-edit`, { [`${blockClass}__btn-edit--always-visible`]: editAlwaysVisible }),
		size,
		label: editLabel,
		onClick: onFocusHandler,
		kind: "ghost",
		key: "edit"
	}, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.Edit, { size: 16 }))));
	return /* @__PURE__ */ react.default.createElement("div", {
		...rest,
		ref,
		...require_devtools.getDevtoolsProps(componentName)
	}, inputContainer, invalid && /* @__PURE__ */ react.default.createElement("p", { className: `${blockClass}__warning-text` }, invalidText ?? deprecated_invalidLabel));
});
EditInPlace.displayName = componentName;
const deprecatedProps = { 
/**
* **Deprecated**
* invalidLabel was misnamed, using invalidText to match Carbon
*/
invalidText: prop_types.default.string };
const alignPropType = prop_types.default.oneOf([
	"top",
	"top-left",
	"top-right",
	"bottom",
	"bottom-left",
	"bottom-right",
	"left",
	"right"
]);
EditInPlace.propTypes = {
	/**
	* label for cancel button
	*/
	cancelLabel: prop_types.default.string.isRequired,
	/**
	* By default the edit icon is shown on hover only.
	*/
	editAlwaysVisible: prop_types.default.bool,
	/**
	* label for edit button
	*/
	editLabel: prop_types.default.string.isRequired,
	/**
	* Specify a custom id for the input
	*/
	id: prop_types.default.string.isRequired,
	/**
	* inheritTypography - causes the text entry field to inherit typography settings
	* assigned to the container. This is useful when editing titles for instance.
	*
	* NOTE: The size property limits the vertical size of the input element.
	* Inherited font's should be selected to fit within the size selected.
	*/
	inheritTypography: prop_types.default.bool,
	/**
	* determines if the input is invalid
	*/
	invalid: prop_types.default.bool,
	/**
	* text that is displayed if the input is invalid
	*/
	/**@ts-ignore*/
	invalidText: prop_types.default.string,
	/**
	* Provide the text that will be read by a screen reader when visiting this control
	*/
	labelText: prop_types.default.string.isRequired,
	/**
	* handler to add custom onBlur event
	*/
	onBlur: prop_types.default.func,
	/**
	* handler that is called when the cancel button is pressed or when the user removes focus from the input and there is no new value
	*/
	onCancel: prop_types.default.func.isRequired,
	/**
	* handler that is called when the input is updated
	*/
	onChange: prop_types.default.func.isRequired,
	/**
	* handler that is called when the save button is pressed or when the user removes focus from the input if it has a new value
	*/
	onSave: prop_types.default.func.isRequired,
	/**
	* Placeholder for text input
	*/
	placeholder: prop_types.default.string,
	/**
	* determines if the input is in readOnly mode
	*/
	readOnly: prop_types.default.bool,
	/**
	* label for the edit off button that displays when in read only mode
	*/
	readOnlyLabel: prop_types.default.string,
	/**
	* text for the toggletip that displays when in read only mode
	*/
	readOnlyToggleTipText: prop_types.default.string,
	/**
	* label for save button
	*/
	saveLabel: prop_types.default.string.isRequired,
	/**
	* vertical size of control
	*/
	size: prop_types.default.oneOf([
		"sm",
		"md",
		"lg"
	]),
	/**
	* alignment for the toggletip that displays when in read only mode
	*/
	toggleTipAlignment: alignPropType,
	/**
	* tooltipAlignment from the standard tooltip. Default center.
	*
	* Can be passed either as one of tooltip options or as an object specifying cancel, edit and save separately
	*/
	/**@ts-ignore*/
	tooltipAlignment: prop_types.default.oneOfType([alignPropType, prop_types.default.shape({
		cancel: alignPropType,
		edit: alignPropType,
		save: alignPropType
	})]),
	/**
	* current value of the input
	*/
	value: prop_types.default.string.isRequired,
	...deprecatedProps
};
//#endregion
exports.EditInPlace = EditInPlace;
