-
Notifications
You must be signed in to change notification settings - Fork 535
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make
FormControl
externally extensible (via hook) (#3632)
* Make `FormControl` extensible via context + hook * Create sweet-turtles-applaud.md * Dont call hook in `InlineAutocomplete` since it gets called farther down the tree * Don't call hook in `Autocomplete` * Add comments on imports * Remove old comment * Remove `id` override from `AutocompleteInput` * Change version bump to `minor` * Revert "Remove `id` override from `AutocompleteInput`" This reverts commit ebb0ba5. * Suppress warning when passed ID == context ID * Don't export `FormControlContext` directly * Don't export `FormControlContext` type * Revert component changes * Move warning & cloning logic back into `FormControl` :( * Allow calling `useForwardedProps` without passing a props object * Expose `useFormControlForwardedProps` directly * Add tests for `useFormControlForwardedProps` * Add story for `useFormControlForwardedProps` * Fix import * Update snapshot * Fix `InlineAutocomplete`
- Loading branch information
1 parent
01fa457
commit 3a8b841
Showing
13 changed files
with
207 additions
and
32 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@primer/react": minor | ||
--- | ||
|
||
Allow consumers to make components that are compatible with `FormControl` by reading forwarded props in from the `useFormControlForwardedProps` hook | ||
|
||
<!-- Changed components: FormControl --> |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import {createContext, useContext} from 'react' | ||
import {FormValidationStatus} from '../utils/types/FormValidationStatus' | ||
import {FormControlProps} from './FormControl' | ||
|
||
interface FormControlContext extends Pick<FormControlProps, 'disabled' | 'id' | 'required'> { | ||
captionId?: string | ||
validationMessageId?: string | ||
validationStatus?: FormValidationStatus | ||
} | ||
|
||
const FormControlContext = createContext<FormControlContext | null>(null) | ||
|
||
export const FormControlContextProvider = FormControlContext.Provider | ||
|
||
/** This is the private/internal interface for subcomponents of `FormControl`. */ | ||
export function useFormControlContext(): FormControlContext { | ||
return useContext(FormControlContext) ?? {} | ||
} | ||
|
||
interface FormControlForwardedProps extends Omit<FormControlContext, 'captionId' | 'validationMessageId'> { | ||
['aria-describedby']?: string | ||
} | ||
|
||
/** | ||
* Make any component compatible with `FormControl`'s automatic wiring up of accessibility attributes & validation by | ||
* reading the props from this hook and merging them with the passed-in props. If used outside of `FormControl`, this | ||
* hook has no effect. | ||
* | ||
* @param externalProps The external props passed to this component. If provided, these props will be merged with the | ||
* `FormControl` props, with external props taking priority. | ||
*/ | ||
export function useFormControlForwardedProps<P>(externalProps: P): P & FormControlForwardedProps | ||
/** | ||
* Make any component compatible with `FormControl`'s automatic wiring up of accessibility attributes & validation by | ||
* reading the props from this hook and handling them / assigning them to the underlying form control. If used outside | ||
* of `FormControl`, this hook has no effect. | ||
*/ | ||
export function useFormControlForwardedProps(): FormControlForwardedProps | ||
export function useFormControlForwardedProps(externalProps: FormControlForwardedProps = {}) { | ||
const context = useContext(FormControlContext) | ||
if (!context) return externalProps | ||
|
||
return { | ||
disabled: context.disabled, | ||
id: context.id, | ||
required: context.required, | ||
validationStatus: context.validationStatus, | ||
['aria-describedby']: [context.validationMessageId, context.captionId].filter(Boolean).join(' ') || undefined, | ||
...externalProps, | ||
} | ||
} |
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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export {useFormControlForwardedProps} from './_FormControlContext' | ||
export {default} from './FormControl' |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React from 'react' | ||
import {Meta} from '@storybook/react' | ||
import {BaseStyles, FormControl, ThemeProvider, theme, useFormControlForwardedProps} from '..' | ||
|
||
export default { | ||
title: 'Hooks/useFormControlForwardedProps', | ||
decorators: [ | ||
Story => { | ||
return ( | ||
<ThemeProvider theme={theme}> | ||
<BaseStyles> | ||
<Story /> | ||
</BaseStyles> | ||
</ThemeProvider> | ||
) | ||
}, | ||
], | ||
argTypes: { | ||
disabled: { | ||
type: 'boolean', | ||
}, | ||
required: { | ||
type: 'boolean', | ||
}, | ||
label: { | ||
type: 'string', | ||
}, | ||
caption: { | ||
type: 'string', | ||
}, | ||
type: { | ||
control: { | ||
type: 'select', | ||
description: "Type of the input, showing how the `type` prop can be forwarded to the input's props", | ||
}, | ||
options: ['text', 'number', 'password', 'email', 'search', 'tel', 'url'], | ||
}, | ||
}, | ||
} as Meta | ||
|
||
interface ArgTypes { | ||
disabled: boolean | ||
required: boolean | ||
label: string | ||
caption: string | ||
type: string | ||
} | ||
|
||
/** A custom input that is not a Primer `TextInput` but still supports autowiring with `FormControl`. */ | ||
const CustomInput = (externalProps: {type: string}) => { | ||
const props = useFormControlForwardedProps(externalProps) | ||
return <input {...props} /> | ||
} | ||
|
||
export const AutowiredCustomInput = ({ | ||
label = 'Custom input', | ||
caption = 'This is not a Primer input, but it still has `aria-describedby` and similar attributes applied automatically', | ||
required = false, | ||
disabled = false, | ||
type = 'text', | ||
}: ArgTypes) => ( | ||
<FormControl disabled={disabled} required={required}> | ||
<FormControl.Label>{label}</FormControl.Label> | ||
<CustomInput type={type} /> | ||
{caption && <FormControl.Caption>{caption}</FormControl.Caption>} | ||
</FormControl> | ||
) |
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
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
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
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