Created
March 23, 2022 11:27
-
-
Save sebald/afd6d2f3c3252e65b2e632109e0cb2ed to your computer and use it in GitHub Desktop.
Trying to make the compound component pattern work for forms
This file contains 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 React, { useCallback, useContext, useRef, useState } from 'react'; | |
import { useField as useAriaField } from '@react-aria/label'; | |
import { useTextField } from '@react-aria/textfield'; | |
const FieldContext = React.createContext<any>({}); | |
const useFieldProvider = (props: any) => { | |
const [hasDescription, setHasDescription] = useState(false); | |
const field = useAriaField({ label: true, description: hasDescription }); | |
const getLabelProps = useCallback( | |
(props = {}) => ({ | |
...props, | |
...field.labelProps, | |
}), | |
[field.labelProps] | |
); | |
const getFieldProps = useCallback( | |
(props = {}) => ({ | |
...props, | |
...field.fieldProps, | |
}), | |
[field.fieldProps] | |
); | |
const getDescriptionProps = useCallback( | |
(props = {}) => ({ | |
...props, | |
...field.descriptionProps, | |
ref: (node: any) => { | |
if (!node) { | |
return; | |
} | |
setHasDescription(true); | |
}, | |
}), | |
[field.descriptionProps] | |
); | |
return { | |
...field, | |
hasDescription, | |
getLabelProps, | |
getFieldProps, | |
getDescriptionProps, | |
}; | |
}; | |
const Field: React.FC<any> = ({ children, ...ownProps }) => { | |
const ctx = useFieldProvider(ownProps); | |
console.log(ctx); // check if react-aria generated the props for us! \o/ | |
return <FieldContext.Provider value={ctx}>{children}</FieldContext.Provider>; | |
}; | |
const Label: React.FC<any> = (props) => { | |
const ctx = useContext(FieldContext); | |
return <label {...ctx.getLabelProps(props)} />; | |
}; | |
const Input = (props: any) => { | |
const ctx = useContext(FieldContext); | |
const ref = useRef(null); | |
const r = useTextField(ctx.getFieldProps(props), ref); | |
return <input {...r.inputProps} />; | |
}; | |
const FieldDescription = React.forwardRef((props: any, ref: any) => { | |
const ctx = useContext(FieldContext); | |
return <div {...ctx.getDescriptionProps(props, ref)} />; | |
}); | |
const App = () => ( | |
<Field> | |
<Label>THE LABEL!</Label> | |
<Input /> | |
<FieldDescription>Helpful text</FieldDescription> | |
</Field> | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment