@brizy/ui
Version:
React elements in Brizy style
98 lines (97 loc) • 4.72 kB
JavaScript
import React, { useEffect, useRef, useCallback } from "react";
import { classNames } from "../classNamesFn";
import { Icon } from "../Icon";
import { CmsIconEditFields, Enter } from "../icons";
import { Tooltip } from "../Tooltip";
import { attachClick, detachClick } from "./utils";
import { uuid } from "../utils";
import { Loading } from "../Loading";
import { BRZ_PREFIX } from "../constants";
export const Editable = ({ value, edit, onEdit, onClick, onChange, onConfirm, onEscape, color = "gray-lightest", type = "hover", placeholder, tooltipTitle = "", tooltipPlacement, tooltipColor, iconColor, iconHoverColor, size, loading, isAllTextSelectedOnEdit, }) => {
const containerRef = useRef(null);
const buttonRef = useRef(null);
const inputRef = useRef(null);
const uidRef = useRef("");
const className = classNames()("editable", `editable--${color}`, {
editable__edit: edit,
editable__click: type === "click",
});
const _onChange = useCallback((e) => {
onChange(e.target.value);
}, [onChange]);
useEffect(() => {
const uid = uuid();
uidRef.current = uid;
const node = containerRef.current;
return () => {
detachClick(uid, node);
};
}, []);
const handleWindow = useCallback((e) => {
const target = e.target;
const node = containerRef.current;
const input = inputRef.current;
const buttonTarget = buttonRef.current;
switch (type) {
case "hover":
if (node === null || node === void 0 ? void 0 : node.contains(target)) {
if (!edit && onEdit) {
onEdit(true);
}
}
else {
if (edit && onEdit) {
onEdit(false);
}
}
break;
case "click":
if ((buttonTarget === null || buttonTarget === void 0 ? void 0 : buttonTarget.contains(target)) || (input === null || input === void 0 ? void 0 : input.contains(target))) {
if (!edit && onEdit) {
onEdit(true);
}
}
else {
if (edit && onEdit) {
onEdit(false);
}
}
break;
}
}, [edit, onEdit, type]);
const handleKeyDown = useCallback((e) => {
switch (e.key) {
case "Escape": {
onEscape === null || onEscape === void 0 ? void 0 : onEscape();
break;
}
case "Enter":
case "NumpadEnter": {
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm();
}
}
}, [onConfirm, onEscape]);
useEffect(() => {
attachClick(uidRef.current, containerRef.current, handleWindow);
}, [handleWindow]);
useEffect(() => {
const input = inputRef.current;
if (edit && input) {
input.focus();
if (isAllTextSelectedOnEdit)
input.select();
}
}, [edit, isAllTextSelectedOnEdit]);
const editableContent = (React.createElement(React.Fragment, null,
edit ? (React.createElement("div", { className: `${BRZ_PREFIX}-editable__input` },
React.createElement("input", { onChange: _onChange, value: value, placeholder: placeholder, ref: inputRef, onKeyDown: handleKeyDown }),
!!value.trim().length && React.createElement(Icon, { source: Enter, onClick: onConfirm }))) : (React.createElement("span", { className: `${BRZ_PREFIX}-editable__text`, onClick: onClick }, value.length ? value : placeholder)),
!edit && type === "hover" && onEdit && (React.createElement(Icon, { source: CmsIconEditFields, color: iconColor, hoverColor: iconHoverColor, size: size === "small" ? "12px" : "16px" })),
!edit &&
type === "click" &&
onEdit &&
(loading ? (React.createElement("button", null,
React.createElement(Loading, { size: size === "small" ? "12px" : "16px" }))) : (React.createElement("button", { ref: buttonRef },
React.createElement(Icon, { source: CmsIconEditFields, color: iconColor, hoverColor: iconHoverColor !== null && iconHoverColor !== void 0 ? iconHoverColor : "dark", size: size === "small" ? "12px" : "16px" }))))));
return (React.createElement("div", { className: className, ref: containerRef }, tooltipTitle ? (React.createElement(Tooltip, { title: tooltipTitle, placement: tooltipPlacement, color: tooltipColor }, editableContent)) : (editableContent)));
};