react-spectrum
react-spectrum copied to clipboard
Provide a way to control UI states
Provide a general summary of the feature here
When creating component documentation, e.g. using storybook, I want to create a story that show the component in various states.
For example, creating a story for a button, and showing how it looks like normally, when pressed, when hover, when focused, etc.
I couldn't do that write now because using css selector doesn't change the state object in:
<Button className={(state) => ...}/>
And the ButtonContext doesn't seem to work with UI states:
<ButtonContext.Provider value={{ isPressed: true, isDisabled: true }}>
<Button
className={(state) => {
console.log('state', state)
return ''
}}
>
Click me
</Button>
</ButtonContext.Provider>
It prints isDisabled: true but isPressed: false. Also it does not have other states (like isFocusVisible).
I can do it if I break it down to one story per component per state, and use user.event() to cause the state change.
But the number of stories will explode and it is very hard to navigate.
๐ค Expected Behavior?
Have a way to do that.
๐ฏ Current Behavior
No good way to do that statically.
๐ Possible Solution
Maybe provide a <UIStateContext.Provider/>
๐ฆ Context
Creating a nice documentation
๐ป Examples
No response
๐งข Your Company/Team
Palo Alto Networks
๐ท Tracking Issue
No response
Duplicate of https://github.com/adobe/react-spectrum/issues/6198
Argh, thanks. I tried to search for isPressed and focusVisible so couldn't find that issue.
btw I just think of a better alternative.
The key is to extract the className handler out and apply it early in the story:
export function MyButton(props: MyButtonProps) {
// ...
return <Button className={state => getMyButtonClassName(props, state)} .../>
}
export function getMyButtonClassName(props, state) { ... }
// my_button.stories.tsx
export const Showcase = {
render() {
return <MyButton className={getMyButtonClassName({ ... }, { isPressed: true })} ... />
}
}
Ah, that's a great approach. Thanks for sharing! And no worries. I'm in here all the time, much easier for me to find a duplicate.
Amend to the solution I have, some mocking function is needed to promote the mocked state classes to regular classes.
For example using Tailwind, hover:... needs to be promoted to ... and use tailwind-merge to enforce class order.
As I looked into these states, it seems like the <Link> component is missing the isVisited state, and isTargeted state is missing from components in general.
Reopening this for now to address the issues.
I noticed that my approach doesn't work with pseudo classes like :active and :hover.
Setting the data attribute data-hovered doesn't work either.
In comparison, it works with @headlessui/react.
it will be a huge save if we can get the same support here.