-
Notifications
You must be signed in to change notification settings - Fork 598
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Action Menu can have its open state be controlled externally (#1199)
* Action Menu can be a controlled component with open state * update docs for ActionMenu * Create pink-lions-suffer.md * Handle onAction for DropdownMenu Items (#1194) * useProvidedStateOrCreate * linter fixes * update hook doc comment * Update src/hooks/useProvidedStateOrCreate.ts Co-authored-by: Dusty Greif <dgreif@users.noreply.github.com> * useProvidedOrCreateState has better implementation for generics * useProvidedOrCreateState has better implementation for generics * make string type explicit Co-authored-by: Dusty Greif <dgreif@users.noreply.github.com>
- Loading branch information
1 parent
4c2e1a2
commit c9b4db7
Showing
6 changed files
with
133 additions
and
15 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,5 @@ | ||
--- | ||
"@primer/components": patch | ||
--- | ||
|
||
Action Menu can have its open state be controlled externally. |
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,39 @@ | ||
import {useProvidedStateOrCreate} from '../../hooks/useProvidedStateOrCreate' | ||
import {render} from '@testing-library/react' | ||
import React, {useState} from 'react' | ||
|
||
it('will use the provided state', () => { | ||
const Component = () => { | ||
const [state, setState] = useState('foo') | ||
const [combinedState] = useProvidedStateOrCreate(state, setState, 'bar') | ||
return <div>{combinedState}</div> | ||
} | ||
|
||
const doc = render(<Component />) | ||
expect(doc.baseElement.textContent).toEqual('foo') | ||
}) | ||
|
||
it('will set state correctly when provided a set state method', () => { | ||
const Component = () => { | ||
const [state, setState] = useState('foo') | ||
const [combinedState, setCombinedState] = useProvidedStateOrCreate(state, setState, 'bar') | ||
if (combinedState !== 'baz') setCombinedState('baz') | ||
return <div>{combinedState}</div> | ||
} | ||
|
||
const doc = render(<Component />) | ||
expect(doc.baseElement.textContent).toEqual('baz') | ||
}) | ||
|
||
it('if not provided a state, will use an internal state', () => { | ||
const Component = () => { | ||
const state = undefined | ||
const setState = undefined | ||
const [combinedState, setCombinedState] = useProvidedStateOrCreate(state, setState, '') | ||
if (combinedState !== 'bar') setCombinedState('bar') | ||
return <div>{combinedState}</div> | ||
} | ||
|
||
const doc = render(<Component />) | ||
expect(doc.baseElement.textContent).toEqual('bar') | ||
}) |
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,27 @@ | ||
import {useCallback, useState} from 'react' | ||
|
||
/** | ||
* There are some situations where we want to give users the option to control state externally with their own state handlers | ||
* or default to using internal state handlers. Because of the 'rules-of-hooks', we cannot conditionally make a call to `React.useState` | ||
* only in the situations where the state is not provided as a prop. | ||
* This hook aims to encapsulate that logic, so the consumer doesn't need to be concerned with violating `rules-of-hooks`. | ||
* @param externalState The state to use - if undefined, will use the state from a call to React.useState | ||
* @param setExternalState The setState to use - if undefined, will use the setState from a call to React.useState | ||
* @param defaultState The defaultState to use, if using internal state. | ||
*/ | ||
export function useProvidedStateOrCreate<T>( | ||
externalState: T | undefined, | ||
setExternalState: ((s: T) => void) | undefined, | ||
defaultState: T | ||
) { | ||
const [internalState, setInternalState] = useState<T>(defaultState) | ||
const state = externalState ?? internalState | ||
const setState = useCallback( | ||
(s: T) => { | ||
setInternalState(s) | ||
if (setExternalState) setExternalState(s) | ||
}, | ||
[setExternalState] | ||
) | ||
return [state, setState] as const | ||
} |
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
c9b4db7
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: