-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(react): add toast component #2279
Conversation
✅ Deploy Preview for vibrant-gates-22c214 canceled.
|
There is no change log for this pull request yet. |
What do you think of Chakra UI's custom component API, Radix's, or Sonner? @mihkeleidast, @FezVrasta any thoughts? One thing we should do is make sure we only provide functional styles and no other (decorative) styling. i.e. just the position/stacking, to be in line with the rest of how the library works. const toast = useToast();
return (
<button
onClick={() => {
toast({
placement: 'top',
render: () => <div>Hello</div>
});
}}
/>
);
Yep!
Don't worry about this for now
I'll try to review these parts in a sec |
Thanks @atomiks
I have used react-toast-notification's as a reference here.
I think this is correct, and a chakra-ui interface might be nice. |
I just realized an absolute flexbox column won't work with transitions to adjust toast positions (no layout animation, without
|
Depends, if you make the toast disappear by first making it invisible and then reducing its height until it reaches 0 you can use flexbox |
Thanks comment. <ul role="region" aria-live="polite">
<li role="status" aria-atomic="true">
Toast content
</li>
</ul> So I can't manipulate open, is this structure wrong? Should I manage |
if (placements[0] === 'top' || placements[0] === 'bottom') { | ||
return { | ||
margin: '0 auto', | ||
top: placements[0] === 'top' ? '20px' : undefined, | ||
bottom: placements[0] === 'bottom' ? '20px' : undefined, | ||
left: | ||
placements[1] === undefined | ||
? 0 | ||
: placements[1] === 'start' | ||
? '20px' | ||
: 'auto', | ||
right: | ||
placements[1] === undefined | ||
? 0 | ||
: placements[1] === 'end' | ||
? '20px' | ||
: 'auto', | ||
}; | ||
} |
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.
@atomiks
I implemented to get the position of toast.
This doesn't look very smart, is it best?
I would be happy to use the floating-ui feature to specify the position relative to the viewport, but I can't think of anything. Any suggestions?
Currently, this is how it behaves locally for me. I feel that the style is a bit forced and a11y is not guaranteed in some areas, but I feel that it is generally good. Screen.Recording.2023-04-10.at.18.59.44.mov@atomiks
|
I imagine this would be useful yes
The
For transition styles to work properly yes, however I'm not sure if pressing Some notes on the API design:
|
Thank you @atomiks !!! I have some more questions:
|
current location You can use placement to specify the position. You can specify <button
onClick={() => {
toast({
placement: 'top',
render: () => <div>Hello</div>
});
}}
/> Added deley to the <button
onClick={() => {
toast({
deley: 1000
render: () => <div>Hello</div>
});
}}
/> Next, I made the transition fully customizable. This allows you to pass the same properties that you can pass to <button
onClick={() => {
toast({
transition: {
duration: { open: 500, close: 1000 }
},
render: () => <div>Hello</div>
});
}}
/> The render function can specify an onClose callback, which can be used to close the toast at the implementer's timing. <button
onClick={() => {
toast({
render: (onClose) => (
<div style={{ display: 'flex' }}>
<div>hello</div>
<button onClick={onClose}>close</button>
</div>
)
});
}}
/> It would be useful to be able to specify these functions globally via Provider. I will work on that. |
properties can now be passed from the provider. export const Main = () => (
// This provider will specify the `top-center` placement for all toasts.
<ToastProvider placement="top-center">
<Component />
</ToastProvider>
);
const Component = () => {
const {toast} = useToast();
return (
<div>
<button
onClick={() =>
toast({
// This will be placed at `top` because the `placement` specified by the toast function has priority.
placement: 'top',
render: () => <div>Hello</div>,
})
}
>
Add Toast to top
</button>
<button
onClick={() =>
// This will specify the `top-center` specified by the provider,
// since `placement` is not specified in the toast function.
toast({
render: () => <div>Hello</div>,
})
}
>
Add Toast to top-center
</button>
</div>
);
}; |
Enabled I set up hooks for |
}); | ||
const ref = useMergeRefs([propRef, refs.setFloating]); | ||
const dismiss = useDismiss(context, { | ||
enabled: focus, |
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.
Enable this only during focus.
Failure to do so will cause an unintended toast to close when you press esc
.
order={['floating']} | ||
initialFocus={-1} |
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.
When new toast is displayed, the focus is on it by default. Then, when you press esc
, the newest toast will close automatically, and then the focus is removed so that no toast will close when you press esc
.
Therefore, the toast closes only when the focus is intentionally set to floating element.
The const Component = () => {
const {closeAll} = useToast();
return <Button onClick={closeAll}>Close All</Button>;
}; Next, the const Component = () => {
const {close} = useToast();
return (
<Button
onClick={() =>
toast({
render: (id, onClose) => (
<div className="w-[300px] bg-white p-4 mb-4 rounded-lg shadow-lg">
Hello
{/* same behavior */}
<button onClick={onClose}>close using onClose</button>
<button onClick={() => close(id)}>close using close function</button>
</div>
),
})
}
>
Add Toast
</Button>
}; |
Added <button
onClick={() => {
toast({
autoClose: false,
render: () => <div>Hello</div>
});
}}
/> |
@takurinton sorry for the delay looking into this and thank you so much for working on it. I will take a proper look and review soon |
I've had the chance to dive deeper into this, and I really appreciate the effort you've put into it. However, there are quite a few aspects that need to be adjusted to align better with the library's goals (and I'm personally not even sure how this will work — it needs some more exploration), but I believe your contribution has potential. I won't be able to merge it at the moment, but feel free to continue developing this as an external package for others to use in the meantime. Integrating it seamlessly with the other hooks and components in the library is challenging in terms of how it will be designed, and could take some time to figure out the best API, but I will work on it eventually. Thank you :)) |
@atomiks |
Currently closing old unmerged PRs :) |
#2192
@atomiks
supports
not supported
I agree with you. I was wanting a toast component that uses floating-ui.
I created the prototype as an experiment.
usage
Brief description of how it is used (how it is intended to be used)
(edited)
worries