UNPKG

chakra-ui

Version:

Responsive and accessible React UI components built with React and Emotion

266 lines (224 loc) 7.37 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; /** @jsx jsx */ import { jsx } from "@emotion/core"; import propTypes from "prop-types"; import { createContext, useContext, useEffect, useRef, useState } from "react"; import PseudoBox from "../PseudoBox"; import Box from "../Box"; var EditableContext = createContext(); var Editable = function Editable(_ref) { var valueProp = _ref.value, defaultValue = _ref.defaultValue, isDisabled = _ref.isDisabled, onChange = _ref.onChange, isEditingProp = _ref.isEditing, onCancel = _ref.onCancel, onSubmit = _ref.onSubmit, _ref$selectAllOnFocus = _ref.selectAllOnFocus, selectAllOnFocus = _ref$selectAllOnFocus === void 0 ? true : _ref$selectAllOnFocus, submitOnBlur = _ref.submitOnBlur, isPreviewFocusable = _ref.isPreviewFocusable, _ref$placeholder = _ref.placeholder, placeholder = _ref$placeholder === void 0 ? "Click to edit..." : _ref$placeholder, children = _ref.children, rest = _objectWithoutProperties(_ref, ["value", "defaultValue", "isDisabled", "onChange", "isEditing", "onCancel", "onSubmit", "selectAllOnFocus", "submitOnBlur", "isPreviewFocusable", "placeholder", "children"]); var _useState = useState(isEditingProp && !isDisabled), _useState2 = _slicedToArray(_useState, 2), isEditing = _useState2[0], setIsEditing = _useState2[1]; var _useRef = useRef(valueProp != null), isControlled = _useRef.current; var _useState3 = useState(defaultValue || ""), _useState4 = _slicedToArray(_useState3, 2), value = _useState4[0], setValue = _useState4[1]; var _value = isControlled ? valueProp : value; var _useState5 = useState(_value), _useState6 = _slicedToArray(_useState5, 2), previousValue = _useState6[0], setPreviousValue = _useState6[1]; var inputRef = useRef(null); var onRequestEdit = function onRequestEdit(event) { if (!isDisabled) { setIsEditing(true); } }; useEffect(function () { if (isEditing && inputRef.current) { inputRef.current.focus(); selectAllOnFocus && inputRef.current.select(); } }, [isEditing, selectAllOnFocus]); var handleCancel = function handleCancel() { setIsEditing(false); setValue(previousValue); if (value !== previousValue) { onChange && onChange(previousValue); } onCancel && onCancel(previousValue); }; var handleSubmit = function handleSubmit() { setIsEditing(false); setPreviousValue(value); onSubmit && onSubmit(value); }; var handleChange = function handleChange(event) { var value = event.target.value; if (!isControlled) { setValue(value); } onChange && onChange(value); }; var handleKeyDown = function handleKeyDown(event) { var key = event.key; if (key === "Escape") { handleCancel(); return; } if (key === "Enter") { handleSubmit(); } }; var handleFocus = function handleFocus(event) { if (selectAllOnFocus) { inputRef.current.select(); } }; var childContext = { inputRef: inputRef, isEditing: isEditing, isDisabled: isDisabled, placeholder: placeholder, onRequestEdit: onRequestEdit, submitOnBlur: submitOnBlur, isPreviewFocusable: isPreviewFocusable, value: _value, onKeyDown: handleKeyDown, onChange: handleChange, onSubmit: handleSubmit, onCancel: handleCancel, onFocus: handleFocus }; return jsx(EditableContext.Provider, { value: childContext }, jsx(Box, rest, typeof children === "function" ? children({ isEditing: isEditing, onSubmit: handleSubmit, onCancel: handleCancel, onRequestEdit: onRequestEdit }) : children)); }; var sharedProps = { fontSize: "inherit", fontWeight: "inherit", textAlign: "inherit", bg: "transparent", transition: "all 0.2s", borderRadius: "md", px: "3px", mx: "-3px" }; export var EditablePreview = function EditablePreview(props) { var _useContext = useContext(EditableContext), isEditing = _useContext.isEditing, isDisabled = _useContext.isDisabled, value = _useContext.value, onRequestEdit = _useContext.onRequestEdit, placeholder = _useContext.placeholder, isPreviewFocusable = _useContext.isPreviewFocusable; var hasValue = value != null && value !== ""; var getTabIndex = function getTabIndex() { if ((!isEditing || !isDisabled) && isPreviewFocusable) { return 0; } return null; }; var styleProps = _extends({}, sharedProps, { cursor: "text", display: "inline-block", opacity: !hasValue ? 0.6 : undefined }); if (isEditing) { return null; } return jsx(PseudoBox, _extends({ as: "span", "aria-disabled": isDisabled, tabIndex: getTabIndex(), onFocus: onRequestEdit }, styleProps, props), hasValue ? value : placeholder); }; export var EditableInput = function EditableInput(props) { var _useContext2 = useContext(EditableContext), inputRef = _useContext2.inputRef, isEditing = _useContext2.isEditing, onChange = _useContext2.onChange, onKeyDown = _useContext2.onKeyDown, value = _useContext2.value, onSubmit = _useContext2.onSubmit, submitOnBlur = _useContext2.submitOnBlur, placeholder = _useContext2.placeholder; var styleProps = _extends({}, sharedProps, { width: "full", _placeholder: { opacity: "0.6" } }); if (!isEditing) { return null; } return jsx(PseudoBox, _extends({ as: "input", ref: inputRef, onBlur: function onBlur() { submitOnBlur && onSubmit(); }, value: value, placeholder: placeholder, onChange: onChange, onKeyDown: onKeyDown }, styleProps, props)); }; process.env.NODE_ENV !== "production" ? Editable.propTypes = { /** Text value of the controlled input */ value: propTypes.string, /** Default text value of uncontrolled input. */ defaultValue: propTypes.string, /** * Whether the text can be edited. * @default false */ isDisabled: propTypes.bool, /** * Whether the component should start with the edit mode active * If `true`, the input is shown by default. * @default false */ isEditing: propTypes.bool, /** Callback invoked when user changes input in any way. */ onChange: propTypes.func, /** Callback invoked when user cancels input with the `Esc` key. Receives last confirmed value. */ onCancel: propTypes.func, /** Callback invoked when user confirms value with `enter` key or by blurring input. */ onSubmit: propTypes.func, /** Callback invoked after the user enters edit mode. */ onEdit: propTypes.func, /** * If `true`, the input's text will be highlighted on focus. * @default false */ selectAllOnFocus: propTypes.bool, /** * Placeholder text when the value is empty. * @default "Click to Edit" */ placeholder: propTypes.string, /** The content of the Editable * Ideally only `EditablePreview` and `EditableInput` should * be the children (but you add other elements too) */ children: propTypes.node } : void 0; export default Editable;