-
Notifications
You must be signed in to change notification settings - Fork 176
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(ODD): add snackbars and toasts #12378
Conversation
Codecov Report
@@ Coverage Diff @@
## edge #12378 +/- ##
==========================================
- Coverage 73.81% 73.79% -0.03%
==========================================
Files 2206 2229 +23
Lines 60935 61732 +797
Branches 6219 6436 +217
==========================================
+ Hits 44981 45554 +573
- Misses 14478 14671 +193
- Partials 1476 1507 +31
Flags with carried forward coverage won't be shown. Click here to find out more.
|
eec5bbc
to
9a6a74a
Compare
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.
wondering if we should name ToasterOven
something more generic now that it can render toasts + snacks.
thought for a moment about having them be two different providers, but i think we want them to be shared by the same "oven" so they dont stomp on each other.
app/src/atoms/Toast/index.tsx
Outdated
@@ -34,9 +36,10 @@ export type ToastType = | |||
export interface ToastProps extends StyleProps { | |||
id: string | |||
message: string | |||
secondaryMessage?: string |
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.
is secondaryMessage being used anywhere?
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.
Yes. It's used throughout the ODD designs to pass protocol names where needed.
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.
same comment as above re: sharing types. as far as i see the desktop toast doesn't use secondaryMessage
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.
It doesn't yet but the design spec in Figma says "Note in the future: Toast and inline toast are the same component in desktop DS" which I interpreted to mean she would like the component to be shared between apps, using new design and props. I was trying to lay the groundwork for that by sharing as much as possible now so only the HTML will have to be swapped out later. I can totally make them two separate things though and someone later can put them together.
also, getting an error when hitting this storybook link: https://s3-us-west-2.amazonaws.com/opentrons-components/RAUT-379-odd-snackbar/index.html?path=/story/odd-atoms-snackbar--quick-snack |
That's from the button import looking in the wrong place after that recent component work. I pushed a fix to my branch yesterday but maybe storybook didn't get rebuilt? I'll look at that. It works locally for me. |
Open to name suggestions. I thought about changing it to something boring like NotificationProvider or something like that but then realized ToasterOven is an even better name than it was before, because now it can both make toast and bake snacks :) |
82a9bb4
to
7448e6a
Compare
}, | ||
} | ||
|
||
export function Toast(props: ToastProps): JSX.Element { |
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.
to avoid confusion, i think this component should be explicitly named ODDToast
or similar
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.
Ok. We're not doing that for the other components (see buttons, etc.) where we made ODD versions to replace desktop components. I am importing it into the ToasterOven with the ODD prefix to make it clear there:
import { Toast as ODDToast } from '../../atoms/Toast/OnDeviceDisplay/Toast'
I can just rename it though.
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.
to clarify, my concern is not the ODD prefix, but confusion over different components with exactly the same name
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.
let's talk this through in the app & ui channel (ill start a message), i have thoughts but want other folks to be part of this discussion
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.
It was easy to rename it and separate out the props and such so the two are totally separate entities. The ToasterOven is able to deal with whichever type comes through it. I did that work before seeing this, and can adapt it to however that discussion turns out.
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.
|
||
type MakeSnackbar = (message: string, options?: MakeSnackbarOptions) => void | ||
|
||
type EatSnackbar = () => void |
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.
what's the use case for eatSnackbar
? is the snackbar ever intended to close based on something other than a timeout? eatToast
exist to programmatically close based on some event that happens asynchronously
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.
I'm not using it anywhere yet, but really the only use case is forcing a snackbar to close prematurely so another one could take its place -- there is a limit of one snackbar displayed at a time.
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.
I took it out. It's premature optimization and one less thing to mock in tests that want to use the ToasterOven but don't care about snacks.
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.
Noting for posterity that it was actually essential for removing the snackbar from the HTML page when used by the ToasterOven, so this will be making a return in a future PR. In isolation, it closes itself (in tests and storybook) but when placed on a page by the app, it has to be removed by force via an eat method.
54713d0
to
447d612
Compare
Moving this back into Draft while I apply the design refactoring that better combines Desktop and ODD toasts into a single skinnable component. |
Ok! I've incorporated the new design and re-unified the props and component. You'll see I cheated just a little because we do want to unit test and storybook the two differently, so the toast component exports two versions that can be imported into test files and storybook stories separately. |
Pulling back into draft mode to implement some design tweaks hashed out with Shlok, Mel, and Koji. |
@shlokamin @koji @mmencarelli I've applied the changes we discussed and reduced the two components down to a single Toast (with one additional abstraction only to account for the useSelector call that we can't do inside storybook). |
@ewagoner |
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.
this is great, and gets us much much closer to the desired architecture i described in the comment below. thank you!
I scheduled time for us to talk with mel about a naming system to be able to move forward with the proposed architecture.
Two things:
- take a look at the storybook guidelines i wrote on Friday afternoon (very new). mel wants us to have one single story with configurable props
- there is one place in the toast component where we swap a whole JSX element rather than just swapping styles. we'll need to refactor that (assuming that is possible...) in order to make the proposed design token architecture work
im fine with this merging and addressing the things above in a follow up, whatever works best for you!
app/src/atoms/Toast/index.tsx
Outdated
// I really, really wanted to get this done in a single component, but the useSelector | ||
// is a huuuuge pain to try to get to work in storybook. I couldn't mock it, I couldn't | ||
// ignore it, and I couldn't get storybook to work in isolation with it there. So... I | ||
// confined it to the Toast omponent the rest of the app sees and have it determine what | ||
// display it is using at runtime. Storybook then can use the RawToast and just pass in | ||
// what display it wants to see. |
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.
that is very annoying. i think a good path forward to get around this is to leverage some sort of theme provider like this that we'd make on our own.
we could define it and pull it in at the top level of our app like we do for redux + react router + react query + i18n: https://github.com/Opentrons/opentrons/blob/edge/app/src/index.tsx
then inside of our tests, we can have our renderwithProviders util take in an additional option flag that tells our testing environ,ent which theme provider to use (we can default to desktop app). okay... that takes care of the testing hurdle.
as for storybook, its kinda similar. inside of our stories we can render each ODD component inside of the ODD theme provider like this:
const MediumButtonTemplate: Story<
React.ComponentProps<typeof MediumButton>
> = args => <ThemeProvider theme="ODD" ><MediumButton {...args} /><ThemeProvider theme="ODD" >
okay... but here come's the hard part. what do with all of the ternaries?? we have to come up with some sort of semantic variable that describes a color that is shared across platforms. ex.
backgroundColor: `${
showODDStyle ? COLORS.yellow_four : COLORS.errorBackgroundLight
}`,
// would need to become
backgroundColor: `${COLORS. errorYellow}`,
and COLORS.errorYellow
would be provided by the theme provider depending on which platform we're on.
that means we have to come up with a strict mapping of platform to colors, and name them something semantically meaningful. this will be difficult and require close collaboration with @mmencarelli
how does that sound?
@shlokamin Those guidelines say |
in Toast.stories.tsx i see 8 stories: export const Success = TemplateWithTimeout.bind({})
Success.args = {
message: 'Success Toast message',
type: 'success',
}
export const Warning = TemplateWithTimeout.bind({})
Warning.args = {
message: 'Warning Toast message',
type: 'warning',
}
export const Error = TemplateWithTimeout.bind({})
Error.args = {
message: 'Error Toast message',
type: 'error',
}
export const Info = TemplateWithTimeout.bind({})
Info.args = {
message: 'Info Toast message',
type: 'info',
}
export const SuccessWithoutTimeout = TemplateWithoutTimeout.bind({})
SuccessWithoutTimeout.args = {
message: 'Success Toast message',
type: 'success',
disableTimeout: true,
}
export const WarningWithoutTimeout = TemplateWithoutTimeout.bind({})
WarningWithoutTimeout.args = {
message: 'Warning Toast message',
type: 'warning',
disableTimeout: true,
}
export const ErrorWithoutTimeout = TemplateWithoutTimeout.bind({})
ErrorWithoutTimeout.args = {
message: 'Error Toast message',
type: 'error',
disableTimeout: true,
}
export const InfoWithoutTimeout = TemplateWithoutTimeout.bind({})
InfoWithoutTimeout.args = {
message: 'Info Toast message',
type: 'info',
disableTimeout: true,
} and in ODDToast.stories.tsx i see another 8: export const Success = TemplateWithTimeout.bind({})
Success.args = {
message: 'Success Toast message',
type: 'success',
}
export const Warning = TemplateWithTimeout.bind({})
Warning.args = {
message: 'Warning Toast message',
type: 'warning',
}
export const Error = TemplateWithTimeout.bind({})
Error.args = {
message: 'Error Toast message',
type: 'error',
}
export const Info = TemplateWithTimeout.bind({})
Info.args = {
message: 'Info Toast message',
type: 'info',
}
export const SuccessWithoutTimeout = TemplateWithoutTimeout.bind({})
SuccessWithoutTimeout.args = {
message: 'Success Toast message',
type: 'success',
disableTimeout: true,
}
export const WarningWithoutTimeout = TemplateWithoutTimeout.bind({})
WarningWithoutTimeout.args = {
message: 'Warning Toast message',
type: 'warning',
disableTimeout: true,
}
export const ErrorWithoutTimeout = TemplateWithoutTimeout.bind({})
ErrorWithoutTimeout.args = {
message: 'Error Toast message',
type: 'error',
disableTimeout: true,
}
export const InfoWithoutTimeout = TemplateWithoutTimeout.bind({})
InfoWithoutTimeout.args = {
message: 'Info Toast message',
type: 'info',
disableTimeout: true,
} |
we want one ODD toast story and one desktop story with configurable props |
Oh, I see what you mean. I was counting the whole file as one story, and it contained multiple examples of how the configurable props could be initialized, so you could easily see them in action and set them as you want. I'll remove all the examples. |
@shlokamin I managed to address both things. The storybook stories have been simplified and just contain a single example and the Flex component swapping has been reduced to pure CSS setting. |
Overview
This PR adds Toasts and Snackbars to the ODD. It also refactored the ToasterOven component and hooks so it could bake both types of components.
snackbar: https://www.figma.com/file/OIdG64Q5cgvEw82ish5Eee/Design-System-(Flex)?node-id=1108-55875&t=9rfcF1oaxwy9W6vd-0
toasts: https://www.figma.com/file/OIdG64Q5cgvEw82ish5Eee/Design-System-(Flex)?node-id=1108-55574&t=BP86HBXk18gH2gFv-0
TODO: Add closing animation (also still a TODO for desktop toasts)
Closes RAUT-379
Test Plan
There are complete sets of storybook stories and unit tests for both components.
Changelog
Review requests
The storybook stories have all the different styles and configurations.
Risk assessment
Low
Screen.Recording.2023-03-28.at.6.45.59.PM.mov
Screen.Recording.2023-03-28.at.6.46.40.PM.mov