@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
260 lines (256 loc) • 7.25 kB
JavaScript
"use client";
import { createContext as createContext$1 } from "../../utils/context.js";
import { useSafeLayoutEffect, useUpdateEffect } from "../../utils/effect.js";
import { mergeRefs, useCallbackRef } from "../../utils/ref.js";
import { utils_exports } from "../../utils/index.js";
import { useControllableState } from "../../hooks/use-controllable-state/index.js";
import { useFieldProps } from "../field/use-field-props.js";
import { useFocusOnPointerDown } from "../../hooks/use-focus/index.js";
import { useCallback, useEffect, useRef, useState } from "react";
//#region src/components/editable/use-editable.ts
const [EditableContext, useEditableContext] = createContext$1({ name: "EditableContext" });
const useEditable = (props = {}) => {
const { props: { id, defaultValue, disabled, placeholder, previewFocusable = true, readOnly, required, selectAllOnFocus = true, startWithEditView, submitOnBlur = true, value: valueProp, onCancel: onCancelProp, onChange: onChangeProp, onEdit: onEditProp, onSubmit: onSubmitProp,...rest }, ariaProps, dataProps, eventProps } = useFieldProps(props);
const onEditRef = useCallbackRef(onEditProp);
const [editing, setEditing] = useState(!!startWithEditView && !disabled);
const [value, setValue] = useControllableState({
defaultValue: defaultValue || "",
value: valueProp,
onChange: onChangeProp
});
const interactive = !editing && !disabled;
const emptyValue = value.length === 0;
const [prevValue, setPrevValue] = useState(value);
const inputRef = useRef(null);
const previewRef = useRef(null);
const editRef = useRef(null);
const cancelRef = useRef(null);
const submitRef = useRef(null);
const onChange = useCallback((ev) => setValue(ev.currentTarget.value), [setValue]);
const onUpdatePrevValue = useCallback(() => setPrevValue(value), [value]);
const onEdit = useCallback(() => {
if (interactive) setEditing(true);
}, [interactive]);
const onCancel = useCallback(() => {
setEditing(false);
setValue(prevValue);
onCancelProp?.(prevValue);
}, [
prevValue,
onCancelProp,
setValue
]);
const onSubmit = useCallback(() => {
setEditing(false);
setPrevValue(value);
onSubmitProp?.(value);
}, [onSubmitProp, value]);
const onKeyDown = useCallback((ev) => {
if (ev.key !== "Escape" && ev.key !== "Enter") return;
ev.preventDefault();
if (ev.key === "Escape") onCancel();
else {
const { metaKey, shiftKey } = ev;
if (!shiftKey && !metaKey) onSubmit();
}
}, [onCancel, onSubmit]);
const onKeyDownWithoutSubmit = useCallback((ev) => {
if (ev.key !== "Escape") return;
ev.preventDefault();
onCancel();
}, [onCancel]);
const onBlur = useCallback((ev) => {
if (!editing) return;
const ownerDocument = ev.currentTarget.ownerDocument;
const relatedTarget = ev.relatedTarget ?? ownerDocument.activeElement;
const targetIsCancel = (0, utils_exports.contains)(cancelRef.current, relatedTarget);
const targetIsSubmit = (0, utils_exports.contains)(submitRef.current, relatedTarget);
if (!(!targetIsCancel && !targetIsSubmit)) return;
if (submitOnBlur) onSubmit();
else onCancel();
}, [
editing,
submitOnBlur,
onSubmit,
onCancel
]);
useFocusOnPointerDown({
ref: inputRef,
elements: [cancelRef, submitRef],
enabled: editing
});
useSafeLayoutEffect(() => {
if (!editing) return;
inputRef.current?.focus();
if (selectAllOnFocus) inputRef.current?.select();
}, []);
useUpdateEffect(() => {
if (!editing) {
editRef.current?.focus();
return;
}
inputRef.current?.focus();
if (selectAllOnFocus) inputRef.current?.select();
onEditRef();
}, [
editing,
onEditRef,
selectAllOnFocus
]);
useEffect(() => {
if (editing) return;
const el = inputRef.current;
if (el?.ownerDocument.activeElement === el) el?.blur();
}, [editing]);
const getRootProps = useCallback((props$1) => ({
...rest,
...dataProps,
...props$1
}), [rest, dataProps]);
const getPreviewProps = useCallback(({ ref,...props$1 } = {}) => ({
...dataProps,
...props$1,
ref: mergeRefs(previewRef, ref),
children: emptyValue ? placeholder : value,
hidden: editing,
tabIndex: interactive && previewFocusable ? 0 : void 0,
onFocus: (0, utils_exports.handlerAll)(props$1.onFocus, onEdit, onUpdatePrevValue)
}), [
dataProps,
editing,
interactive,
previewFocusable,
emptyValue,
onEdit,
onUpdatePrevValue,
placeholder,
value
]);
const getInputProps = useCallback(({ ref,...props$1 } = {}) => ({
...dataProps,
...ariaProps,
...props$1,
id,
ref: mergeRefs(inputRef, ref),
disabled,
hidden: !editing,
placeholder,
readOnly,
required,
value,
onBlur: (0, utils_exports.handlerAll)(eventProps.onBlur, props$1.onBlur, onBlur),
onChange: (0, utils_exports.handlerAll)(props$1.onChange, onChange),
onFocus: (0, utils_exports.handlerAll)(eventProps.onFocus, props$1.onFocus, onUpdatePrevValue),
onKeyDown: (0, utils_exports.handlerAll)(props$1.onKeyDown, onKeyDown)
}), [
dataProps,
ariaProps,
id,
disabled,
editing,
placeholder,
readOnly,
required,
value,
eventProps.onBlur,
eventProps.onFocus,
onBlur,
onChange,
onUpdatePrevValue,
onKeyDown
]);
const getTextareaProps = useCallback(({ ref,...props$1 } = {}) => ({
...dataProps,
...ariaProps,
...props$1,
id,
ref: mergeRefs(inputRef, ref),
disabled,
hidden: !editing,
placeholder,
readOnly,
required,
value,
onBlur: (0, utils_exports.handlerAll)(eventProps.onBlur, props$1.onBlur, onBlur),
onChange: (0, utils_exports.handlerAll)(props$1.onChange, onChange),
onFocus: (0, utils_exports.handlerAll)(eventProps.onFocus, props$1.onFocus, onUpdatePrevValue),
onKeyDown: (0, utils_exports.handlerAll)(props$1.onKeyDown, onKeyDownWithoutSubmit)
}), [
dataProps,
ariaProps,
id,
disabled,
editing,
placeholder,
readOnly,
required,
value,
eventProps.onBlur,
eventProps.onFocus,
onBlur,
onChange,
onUpdatePrevValue,
onKeyDownWithoutSubmit
]);
const getControlProps = useCallback((props$1) => ({
...dataProps,
role: "group",
...props$1
}), [dataProps]);
const getEditProps = useCallback(({ ref,...props$1 } = {}) => ({
...dataProps,
...props$1,
ref: mergeRefs(editRef, ref),
disabled,
hidden: editing,
onClick: (0, utils_exports.handlerAll)(props$1.onClick, onEdit)
}), [
dataProps,
disabled,
editing,
onEdit
]);
const getSubmitProps = useCallback(({ ref,...props$1 } = {}) => ({
...dataProps,
...props$1,
ref: mergeRefs(submitRef, ref),
disabled,
hidden: !editing,
onClick: (0, utils_exports.handlerAll)(props$1.onClick, onSubmit)
}), [
dataProps,
disabled,
editing,
onSubmit
]);
return {
editing,
value,
getCancelProps: useCallback(({ ref,...props$1 } = {}) => ({
...dataProps,
...props$1,
ref: mergeRefs(cancelRef, ref),
disabled,
hidden: !editing,
onClick: (0, utils_exports.handlerAll)(props$1.onClick, onCancel)
}), [
dataProps,
disabled,
editing,
onCancel
]),
getControlProps,
getEditProps,
getInputProps,
getPreviewProps,
getRootProps,
getSubmitProps,
getTextareaProps,
onCancel,
onEdit,
onSubmit
};
};
//#endregion
export { EditableContext, useEditable, useEditableContext };
//# sourceMappingURL=use-editable.js.map