Last active
July 23, 2021 14:31
-
-
Save muthhukumar/57ebc389b10f8ecab4f1cad0bf5d92b8 to your computer and use it in GitHub Desktop.
Chakra-ui editable textarea
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react' | |
import { | |
chakra, | |
forwardRef, | |
omitThemingProps, | |
StylesProvider, | |
SystemStyleObject, | |
ThemingProps, | |
useMultiStyleConfig, | |
useStyles, | |
HTMLChakraProps, | |
} from '@chakra-ui/system' | |
import { cx, runIfFn, __DEV__ } from '@chakra-ui/utils' | |
import { createContext, MaybeRenderProp } from '@chakra-ui/react-utils' | |
import { useEditable, UseEditableProps, UseEditableReturn } from '@chakra-ui/react' | |
type EditableContext = Omit<UseEditableReturn, 'htmlProps'> | |
const [EditableProvider, useEditableContext] = createContext<EditableContext>({ | |
name: 'EditableContext', | |
errorMessage: | |
'useEditableContext: context is undefined. Seems you forgot to wrap the editable components in `<Editable />`', | |
}) | |
type RenderProps = Pick<UseEditableReturn, 'isEditing' | 'onSubmit' | 'onCancel' | 'onEdit'> | |
interface BaseEditableProps | |
extends Omit<HTMLChakraProps<'div'>, 'onChange' | 'value' | 'defaultValue' | 'onSubmit'> {} | |
export interface EditableProps | |
extends UseEditableProps, | |
BaseEditableProps, | |
ThemingProps<'Editable'> { | |
children?: MaybeRenderProp<RenderProps> | |
} | |
/** | |
* Editable | |
* | |
* The wrapper that provides context and logic for all editable | |
* components. It renders a `div` | |
*/ | |
export const Editable = forwardRef<EditableProps, 'div'>((props, ref) => { | |
const styles = useMultiStyleConfig('Editable', props) | |
const ownProps = omitThemingProps(props) | |
const { htmlProps, ...context } = useEditable(ownProps) | |
const { isEditing, onSubmit, onCancel, onEdit } = context | |
const _className = cx('chakra-editable', props.className) | |
const children = runIfFn(props.children, { | |
isEditing, | |
onSubmit, | |
onCancel, | |
onEdit, | |
}) | |
return ( | |
<EditableProvider value={context}> | |
<StylesProvider value={styles}> | |
<chakra.div ref={ref} {...(htmlProps as HTMLChakraProps<'div'>)} className={_className}> | |
{children} | |
</chakra.div> | |
</StylesProvider> | |
</EditableProvider> | |
) | |
}) | |
if (__DEV__) { | |
Editable.displayName = 'Editable' | |
} | |
const commonStyles: SystemStyleObject = { | |
fontSize: 'inherit', | |
fontWeight: 'inherit', | |
textAlign: 'inherit', | |
bg: 'transparent', | |
} | |
export interface EditablePreviewProps extends HTMLChakraProps<'div'> {} | |
/** | |
* EditablePreview | |
* | |
* The `span` used to display the final value, in the `preview` mode | |
*/ | |
export const EditablePreview = forwardRef<EditablePreviewProps, 'span'>((props, ref) => { | |
const { getPreviewProps } = useEditableContext() | |
const styles = useStyles() | |
const previewProps = getPreviewProps(props, ref) as HTMLChakraProps<'span'> | |
const _className = cx('chakra-editable__preview', props.className) | |
return ( | |
<chakra.span | |
{...previewProps} | |
__css={{ | |
cursor: 'text', | |
display: 'inline-block', | |
...commonStyles, | |
...styles.preview, | |
}} | |
className={_className} | |
/> | |
) | |
}) | |
if (__DEV__) { | |
EditablePreview.displayName = 'EditablePreview' | |
} | |
export interface EditableTextareaProps extends HTMLChakraProps<'textarea'> {} | |
/** | |
* EditableTextarea | |
* | |
* The textarea used in the `edit` mode | |
*/ | |
export const EditableTextarea = forwardRef<EditableTextareaProps, 'textarea'>((props, ref) => { | |
const { getInputProps } = useEditableContext() | |
const styles = useStyles() | |
const textareaProps = getInputProps(props, ref) as HTMLChakraProps<'textarea'> | |
const _className = cx('chakra-editable__textarea', props.className) | |
return ( | |
<chakra.textarea | |
{...textareaProps} | |
__css={{ | |
outline: 0, | |
...commonStyles, | |
...styles.input, | |
}} | |
className={_className} | |
/> | |
) | |
}) | |
if (__DEV__) { | |
EditableTextarea.displayName = 'EditableTextarea' | |
} | |
/** | |
* React hook use to gain access to the editable state and actions. | |
*/ | |
export function useEditableState() { | |
const { isEditing, onSubmit, onCancel, onEdit, isDisabled } = useEditableContext() | |
return { | |
isEditing, | |
onSubmit, | |
onCancel, | |
onEdit, | |
isDisabled, | |
} | |
} | |
/** | |
* React hook use to create controls for the editable component | |
*/ | |
export function useEditableControls(): Pick< | |
EditableContext, | |
'isEditing' | 'getEditButtonProps' | 'getCancelButtonProps' | 'getSubmitButtonProps' | |
> { | |
const { isEditing, getEditButtonProps, getCancelButtonProps, getSubmitButtonProps } = | |
useEditableContext() | |
return { | |
isEditing, | |
getEditButtonProps, | |
getCancelButtonProps, | |
getSubmitButtonProps, | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment