@yamada-ui/react
Version:
React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion
1 lines • 14.7 kB
Source Map (JSON)
{"version":3,"file":"use-editable.cjs","names":["createContext","useFieldProps","useCallbackRef","useControllableState","getRootProps: PropGetter","props","getPreviewProps: PropGetter<\"span\">","mergeRefs","getInputProps: PropGetter<\"input\">","getTextareaProps: PropGetter<\"textarea\">","getControlProps: PropGetter","getEditProps: PropGetter<\"button\">","getSubmitProps: PropGetter<\"button\">"],"sources":["../../../../src/components/editable/use-editable.ts"],"sourcesContent":["\"use client\"\n\nimport type { ChangeEvent, FocusEvent, KeyboardEvent } from \"react\"\nimport type { PropGetter } from \"../../core\"\nimport type { FieldProps } from \"../field\"\nimport { useCallback, useEffect, useRef, useState } from \"react\"\nimport { useControllableState } from \"../../hooks/use-controllable-state\"\nimport { useFocusOnPointerDown } from \"../../hooks/use-focus\"\nimport {\n contains,\n createContext,\n handlerAll,\n mergeRefs,\n useCallbackRef,\n useSafeLayoutEffect,\n useUpdateEffect,\n} from \"../../utils\"\nimport { useFieldProps } from \"../field\"\n\ninterface EditableContext\n extends Omit<\n UseEditableReturn,\n \"getRootProps\" | \"onCancel\" | \"onEdit\" | \"onSubmit\" | \"value\"\n > {}\n\nconst [EditableContext, useEditableContext] = createContext<EditableContext>({\n name: \"EditableContext\",\n})\n\nexport { EditableContext, useEditableContext }\n\nexport interface UseEditableProps extends FieldProps {\n /**\n * The initial value of the Editable in both edit & preview mode.\n */\n defaultValue?: string\n /**\n * The placeholder text when the value is empty.\n */\n placeholder?: string\n /**\n * If `true`, the read only view, has a `tabIndex` set to `0`\n * so it can receive focus via the keyboard or click.\n *\n * @default true\n */\n previewFocusable?: boolean\n /**\n * If `true`, the input's text will be highlighted on focus.\n *\n * @default true\n */\n selectAllOnFocus?: boolean\n /**\n * If `true`, the Editable will start with edit mode by default.\n */\n startWithEditView?: boolean\n /**\n * If `true`, it'll update the value onBlur and turn off the edit mode.\n *\n * @default true\n */\n submitOnBlur?: boolean\n /**\n * The value of the Editable in both edit & preview mode.\n */\n value?: string\n /**\n * Callback invoked when user cancels input with the `Esc` key.\n * It provides the last confirmed value as argument.\n */\n onCancel?: (preValue: string) => void\n /**\n * A callback invoked when user changes input.\n */\n onChange?: (value: string) => void\n /**\n * A callback invoked once the user enters edit mode.\n */\n onEdit?: () => void\n /**\n * A callback invoked when user confirms value with `enter` key or by blurring input.\n */\n onSubmit?: (value: string) => void\n}\n\nexport const useEditable = (props: UseEditableProps = {}) => {\n const {\n props: {\n id,\n defaultValue,\n disabled,\n placeholder,\n previewFocusable = true,\n readOnly,\n required,\n selectAllOnFocus = true,\n startWithEditView,\n submitOnBlur = true,\n value: valueProp,\n onCancel: onCancelProp,\n onChange: onChangeProp,\n onEdit: onEditProp,\n onSubmit: onSubmitProp,\n ...rest\n },\n ariaProps,\n dataProps,\n eventProps,\n } = useFieldProps(props)\n const onEditRef = useCallbackRef(onEditProp)\n const [editing, setEditing] = useState<boolean>(\n !!startWithEditView && !disabled,\n )\n const [value, setValue] = useControllableState({\n defaultValue: defaultValue || \"\",\n value: valueProp,\n onChange: onChangeProp,\n })\n const interactive = !editing && !disabled\n const emptyValue = value.length === 0\n const [prevValue, setPrevValue] = useState(value)\n const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null)\n const previewRef = useRef<HTMLElement>(null)\n const editRef = useRef<HTMLButtonElement>(null)\n const cancelRef = useRef<HTMLButtonElement>(null)\n const submitRef = useRef<HTMLButtonElement>(null)\n\n const onChange = useCallback(\n (ev: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) =>\n setValue(ev.currentTarget.value),\n [setValue],\n )\n\n const onUpdatePrevValue = useCallback(() => setPrevValue(value), [value])\n\n const onEdit = useCallback(() => {\n if (interactive) setEditing(true)\n }, [interactive])\n\n const onCancel = useCallback(() => {\n setEditing(false)\n setValue(prevValue)\n onCancelProp?.(prevValue)\n }, [prevValue, onCancelProp, setValue])\n\n const onSubmit = useCallback(() => {\n setEditing(false)\n setPrevValue(value)\n onSubmitProp?.(value)\n }, [onSubmitProp, value])\n\n const onKeyDown = useCallback(\n (ev: KeyboardEvent) => {\n if (ev.key !== \"Escape\" && ev.key !== \"Enter\") return\n\n ev.preventDefault()\n\n if (ev.key === \"Escape\") {\n onCancel()\n } else {\n const { metaKey, shiftKey } = ev\n\n if (!shiftKey && !metaKey) onSubmit()\n }\n },\n [onCancel, onSubmit],\n )\n\n const onKeyDownWithoutSubmit = useCallback(\n (ev: KeyboardEvent) => {\n if (ev.key !== \"Escape\") return\n\n ev.preventDefault()\n onCancel()\n },\n [onCancel],\n )\n\n const onBlur = useCallback(\n (ev: FocusEvent) => {\n if (!editing) return\n\n const ownerDocument = ev.currentTarget.ownerDocument\n const relatedTarget = (ev.relatedTarget ??\n ownerDocument.activeElement) as HTMLElement\n const targetIsCancel = contains(cancelRef.current, relatedTarget)\n const targetIsSubmit = contains(submitRef.current, relatedTarget)\n const validBlur = !targetIsCancel && !targetIsSubmit\n\n if (!validBlur) return\n\n if (submitOnBlur) {\n onSubmit()\n } else {\n onCancel()\n }\n },\n [editing, submitOnBlur, onSubmit, onCancel],\n )\n\n useFocusOnPointerDown({\n ref: inputRef,\n elements: [cancelRef, submitRef],\n enabled: editing,\n })\n\n useSafeLayoutEffect(() => {\n if (!editing) return\n\n inputRef.current?.focus()\n\n if (selectAllOnFocus) inputRef.current?.select()\n }, [])\n\n useUpdateEffect(() => {\n if (!editing) {\n editRef.current?.focus()\n\n return\n }\n\n inputRef.current?.focus()\n\n if (selectAllOnFocus) inputRef.current?.select()\n\n onEditRef()\n }, [editing, onEditRef, selectAllOnFocus])\n\n useEffect(() => {\n if (editing) return\n\n const el = inputRef.current\n const activeEl = el?.ownerDocument.activeElement\n\n if (activeEl === el) el?.blur()\n }, [editing])\n\n const getRootProps: PropGetter = useCallback(\n (props) => ({\n ...rest,\n ...dataProps,\n ...props,\n }),\n [rest, dataProps],\n )\n\n const getPreviewProps: PropGetter<\"span\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n ...dataProps,\n ...props,\n ref: mergeRefs(previewRef, ref),\n children: emptyValue ? placeholder : value,\n hidden: editing,\n tabIndex: interactive && previewFocusable ? 0 : undefined,\n onFocus: handlerAll(props.onFocus, onEdit, onUpdatePrevValue),\n }),\n [\n dataProps,\n editing,\n interactive,\n previewFocusable,\n emptyValue,\n onEdit,\n onUpdatePrevValue,\n placeholder,\n value,\n ],\n )\n\n const getInputProps: PropGetter<\"input\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n ...dataProps,\n ...ariaProps,\n ...props,\n id,\n ref: mergeRefs(inputRef, ref),\n disabled,\n hidden: !editing,\n placeholder,\n readOnly,\n required,\n value,\n onBlur: handlerAll(eventProps.onBlur, props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange),\n onFocus: handlerAll(eventProps.onFocus, props.onFocus, onUpdatePrevValue),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDown),\n }),\n [\n dataProps,\n ariaProps,\n id,\n disabled,\n editing,\n placeholder,\n readOnly,\n required,\n value,\n eventProps.onBlur,\n eventProps.onFocus,\n onBlur,\n onChange,\n onUpdatePrevValue,\n onKeyDown,\n ],\n )\n\n const getTextareaProps: PropGetter<\"textarea\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n ...dataProps,\n ...ariaProps,\n ...props,\n id,\n ref: mergeRefs(inputRef, ref),\n disabled,\n hidden: !editing,\n placeholder,\n readOnly,\n required,\n value,\n onBlur: handlerAll(eventProps.onBlur, props.onBlur, onBlur),\n onChange: handlerAll(props.onChange, onChange),\n onFocus: handlerAll(eventProps.onFocus, props.onFocus, onUpdatePrevValue),\n onKeyDown: handlerAll(props.onKeyDown, onKeyDownWithoutSubmit),\n }),\n [\n dataProps,\n ariaProps,\n id,\n disabled,\n editing,\n placeholder,\n readOnly,\n required,\n value,\n eventProps.onBlur,\n eventProps.onFocus,\n onBlur,\n onChange,\n onUpdatePrevValue,\n onKeyDownWithoutSubmit,\n ],\n )\n\n const getControlProps: PropGetter = useCallback(\n (props) => ({\n ...dataProps,\n role: \"group\",\n ...props,\n }),\n [dataProps],\n )\n\n const getEditProps: PropGetter<\"button\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n ...dataProps,\n ...props,\n ref: mergeRefs(editRef, ref),\n disabled,\n hidden: editing,\n onClick: handlerAll(props.onClick, onEdit),\n }),\n [dataProps, disabled, editing, onEdit],\n )\n\n const getSubmitProps: PropGetter<\"button\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n ...dataProps,\n ...props,\n ref: mergeRefs(submitRef, ref),\n disabled,\n hidden: !editing,\n onClick: handlerAll(props.onClick, onSubmit),\n }),\n [dataProps, disabled, editing, onSubmit],\n )\n\n const getCancelProps: PropGetter<\"button\"> = useCallback(\n ({ ref, ...props } = {}) => ({\n ...dataProps,\n ...props,\n ref: mergeRefs(cancelRef, ref),\n disabled,\n hidden: !editing,\n onClick: handlerAll(props.onClick, onCancel),\n }),\n [dataProps, disabled, editing, onCancel],\n )\n\n return {\n editing,\n value,\n getCancelProps,\n getControlProps,\n getEditProps,\n getInputProps,\n getPreviewProps,\n getRootProps,\n getSubmitProps,\n getTextareaProps,\n onCancel,\n onEdit,\n onSubmit,\n }\n}\n\nexport type UseEditableReturn = ReturnType<typeof useEditable>\n"],"mappings":"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"}