Can I Create A Complete Toast Notification Library?

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
i'm going to be attempting to create this really awesome toast notification that you see on the right here but i'm not just going to create the toast notification i'm going to create an entire library around it that implements all of these different features and i'm going to try to do it in less than an hour this is the very first time i'm trying to solve this problem so you can see my thought process how i go about thinking about the problem running into issues and solving those issues [Music] welcome back to web dev simplified my name is kyle and my job is to simplify the web for you so you can start building your dream project sooner and like i mentioned we're going to be building out this full toast library now this is going to be based on the react toastify library but i'm actually going to be building it out using plain javascript so there's going to be quite a few differences but all the functionality is going to be the same if we come over to the documentation we can see all the properties that are available on this toast library that we need to implement and i'm going to be implementing probably about 90 of them there's a few that just don't make sense because they're boring to do such as things like style like we don't really need to worry about that because this is just for our own use case but it's something that's really easy to implement so to get started i first just want to create an index.html file i want to create a script dot js file i'm going to create a style sheet which called styles.css i'm going to create here just a toast.js file so this toast.js file is going to contain all of the logic for the library and then the script.js file is where we're going to actually just use that library so i want to create this as if it's a library for npm and styles.css this is just going to contain the styles for our actual toast itself so if we come into our index here we just exclamation point i need to link in that style sheet and also i need to get our javascript so we're going to say script.js and this is going to be a type of module just like that if you're unfamiliar with the module type i have a full tutorial covering it i'll link in the cards and description for you but essentially i don't really care about having anything in my body it really doesn't matter all i want to do is actually have the toe show up on the screen so the body is essentially irrelevant it really doesn't matter so the first thing that i want to do is inside of here i'm just going to put like a placeholder toast so we can just call this like toast yeah we'll just call it toast is fine and inside here we're just going to put some text that just says test message there we go and this is just so that we can style what our toast is going to look like so if we just open this up with live server real quick and i make sure that we go to local whoops just copy that over there we go so now we have our test message showing up we can just zoom this in really big so we can see it really easily and what i want to do is i want to style out this toast it's going to be really basic styling i mean the styling that they have over here if i show a toast is honestly pretty simple it's just essentially a card so what we can do is we can just say we're going to select our toast and of course what i want to do is i want to set our box sizing here to border box there we go and then what i'm going to do is i'm going to give it some padding we'll say one rem maybe background color is going to be white i can spell color correctly and we're just going to give it a simple border of 1 pixel solid 333 again this tutorial is not so much about how the actual thing looks it's more about how it functions let's give it a border radius of 0.5 em as well and we'll zoom that out so it's about more normal scale this is about what a normal toast message scale will look like i'm just going to zoom in a little bit so it's easier to see on your screen so there we go that's about what we're working with i think that looks pretty good maybe reduce the border radius a little bit good enough next thing we need to do is have a close button that we're going to put in the top right corner so we'll say toast we're going to select the after element content inside of here what i want to do is i want to put in the ampersand times i'm not sure if this will actually show up okay it does not show up as a x button let me just look for html entity [Music] code times so what i need to do is just copy this uh let me see i need to get the actual code for css html css code there we go so we can just copy this and paste this in here and this should hopefully give us a x and the reason i'm using this instead of just the character x is because depending on your font the actual x is not centered it's going to be different sizes so this will just give us a consistent looking x that we can put in the top right corner so i'm going to position my toast as relative and this i'm going to position absolutely in the top left corner so we'll just say top i'm sorry top right corner we'll say top and right are zero and what i want to do is just give it a little bit of spacing so we'll just say that the top is going to be like 10 pixels and the right is 10 pixels and that looks pretty big actually we'll change that to like five and two maybe there we go that looks like it's about in the top right hand corner that looks pretty good okay and we don't actually need this x to be selectable to be closing it because if we click anywhere on our toast i just want to close the toast message so it doesn't actually matter that this x is not like a selectable button it's fine because we're just going to be closing our text anytime that we focus inside of this toast okay so i think that's really all we need to do for our styling we probably need to have a container for our toast message because we need to make it display in different sections also we should probably give it a max size because if you show the toast to you can see they have like a maximum width so we're going to give this a max width let's say like 300 pixels just see how that looks that looks a little big we'll maybe do 200 pixels or 250. now let's do 200 i mean maybe 250 is fine because that's about 100 screen looks like there we go so we have 250 pixels at our maximum width and that all looks really good so now the next step is going to be actually making it positioned on the correct sections of our screen because right now it's in the top left we want to be able to position it in a bunch of different places as you can see here we have this position property could be top right top center top left and then bottom for all three of those positions so what i want to do is i want to create a container we'll just call it toast container and inside of here we're going to put our toast and the toast container is going to have a data attribute i think is what we're going to use called position and we're going to set it to like top right for example and this is going to position in the top right hand corner so inside of our styles we can take our toast container and we know that we want to position this as a fixed position because no matter where we are on our screen like no matter how much scrolling we do for example if i show this i always want it to stay fixed in that top right or top left corner so position fixed makes sense and then what i want to do is i want to position it based on that data attribute so we can say toast container we call this data position and what i want to do is we'll just say like top right for now and i believe we can actually just come in no we'll just do this for now okay so we have top right and come back over to here so i want the top position to be 0 and the right position to be zero there we go you can see it's showing up in the top right hand corner that looks really good instead of giving this a max width i'm going to give it just a width that way it's always exactly the same size of 250 pixels that looks good and what i want to do is i want to essentially have a space so i think i want to just use margin for this we can say like 10 pixels maybe there we go that way it's just 10 pixels away from the side of our screen at all times no matter what side of the screen it's on that looks really good and i think what we can do to make this a little bit cleaner is we can actually just use four separate selectors one for top one for right one for bottom and one for left i believe what we can do is if we put inside of here the carrot symbol if we had to put it here that's going to say select me anything that starts with top dash and i set the top to zero here i want to select anything that ends with dash right and i can do that by putting the dollar sign symbol on the end of it so it's going to say select anything that ends in right and hopefully we just comment these out it should still work top right hand corner yep it does so now what i want to do is just we'll just copy this one down we're going to have left and we're going to copy this down one more time for bottom so this should say bottom is zero and this should say left is zero and i want to create the caret symbol here just organize these a little better we'll do that so now if i save and i come over to here we should be able to say like top left it goes in the top left oh i guess we need to have center as well so inside of here let's add one more for center and this is going to have a left of 50 and a transform translate in the x direction of negative 50 percent there we go and i think what i want to do is instead of having my width on the toast i want to put it on the toast container and then just the toast should have a width of 100 so it'll fill the entire container there we go now let's test all these out we have center you see that's in the center and then if we try out the bottom version you see it's in the bottom on the center on the left and on the right and it might be a little hard to see on the bottom so we're going to mostly stick with top styling just so it's easier for you to see it's not stuck behind my camera okay that's pretty good also i'm going to give our toast here a cursor of pointer just so we know that it's clickable because i want to be able to just close the toast whenever i click on it so when i click it's going to close out of the toast because that's how this works over here you click on it it gets rid of it pretty straightforward so i believe that's really all we have our styling i mean if we have multiple toasts we obviously should probably style those they look good together so let's just put two in here and for our toast what i'll do is i'll just change the display to flex flex direction to column and i'll say like a gap of one we'll rem 0.5 ren that'll just space them out from one another and then if we just have a bunch of toast they're just going to all stick right next to each other and they're going to look really clean yeah i think that looks really good so now we essentially have everything done for our css our html is going to start out empty so i'll just comment this out for now all we really have left is to actually do the javascript so let's start with the toast class itself because we need to think about what we all need to implement and i kind of already mentioned the idea i have for this i want to do this using classes so we're going to say like here we're going to export a default class called toast and we'll just give it a constructor for now that does nothing and inside here what i want to do is i want to have a bunch of setters so i'll say i'll have a setter called like position and this is going to take in a value and inside this setter what i want to do is i want to take our toast element and i want to for example put it inside of a container that has the correct data position inside of it so that's going to be what like my position property does or i'll have one that says set text and what i'll do inside here is i'll take like toast.text content equals value you know i would have just set the text that way so kind of the way that i'm going to be handling this is just setters and all these setters are going to implement all the dom behavior so like when i change something it's going to change it inside the dom that's like my idea who knows if it's going to work but that's kind of what i'm thinking so what i want to do with my toast is also implement all the different functions we need so we're going to need a function for updating it we're going to need a function for removing it if we want to remove it programmatically and i think we probably want to have a function for showing it as well so we'll just create a show function in here oops my styling correct there we go so we have a show function update function a remove function and the constructor all i want that to do is just take in some options there we go and these options i'm just going to set on our object and like i said we're going to be using a bunch of setters for that so like let's say that i pass in options for like position we come over here you can see we have like position on open on close let's say i pass those three options in what i could do is i could say you know like position on open on close etc that's a lot to type out so instead what i'm going to do is i'm going to take in our options i'm just going to loop through all of them so we're going to say object.entries so for each one of my options i want to loop through it and what we're going to get is a key and a value and what i can do is i can just say hey this key equals value all i'm doing is i'm setting the property for the key to the value so now when i create a new toast i say like new toast position top right what that is going to do is it's going to loop through here it's going to say hey my key is positioned value is top right and it's going to set that and if i have a setter for position that takes in a value it's going to call this setter and actually do something inside of it so i can just say like console.log value for now if i copy this out this should hopefully work if i come into our script we're going to import that toast class just like this and then we're just going to create a new toast and hopefully this should print out top right to the console so if we inspect our page i bring the console over let's see yeah it prints out top right because it's taking in this position key and it's saying okay we have a setter for that called the setter and pass in the value so this is working pretty much as i expected to now the next step is going to be obviously making it work so let me think here show is going to be pretty easy this is where we create our actual toast element so we can say like const toast column equals document dot create element this is just going to be a div toast elem dot class list dot add toast i believe that's the only thing on our toast yet just has a class that's it um okay let me think let me think let me think do we want to do anything else maybe when we create the toast we just automatically show it right away that might be a better way to do this because i'm thinking if we take our options into our constructor here then we're going to need to essentially define those options when we do this show i guess you know what we could do is we could create our element here we could create our toast element here in the front and we'll just set it to this dot toast element i'm going to make it a private variable just so we can't mess with it anywhere else so we're creating our toast element here and then inside of our show what i want to do is move this up here this dot in our show what i want to do is i just want to append that to the correct location so whatever position it's currently in that is where i want to append it to maybe i won't do that maybe we're just going to automatically show it we don't even need a show function for now we're going to get rid of the show function but we might take it back later okay so yeah we create our toast element that's good we have our toast element class list then what i want to do is figure out how to position it so position is probably the first thing we want to focus on so instead of setting a value instead of what i want to do is i want to get a container because by default our body is empty it's going to look like this what we want to do is we want to add in a container that's going to be where we position these and if we already have a container we want to use that container instead so let me think here what we can do when we set our position is we can take the container so we can say const container equals document.queryselector data position equals this is going to be equal to our position so let's do this inside of back ticks here it's equal to our value there we go so this is going to get the container for our position okay that makes sense yeah and then if we don't have a container i want to create a brand new one so we're going to say or create container pass passed in a value so let's just create a function called createcontainer which takes in a position this is going to essentially do very similar stuff up here so we're going to say const container is created creating a new container container.classlist we're adding toast container to that i want to make sure i use that class list up here for my selector here we go and then what i want to do is just say container dot data set dot position equals position and we can return that container we actually probably want to append it to the body as well so we'll say document.body.append container there we go so now up here everything is working this should not have a there we go let me uh maybe turn this into its own variable so we'll say const selector is equal to that there we go we kind of minimize this side down so we have more room to work with our code so we're either getting the container if it exists or creating a brand new container then what we can do is we can say container dot append and i want to append my toast element so we can say this dot toast element okay i think that's all we need to do to make position work let's also make text work so we can see the text inside of it and all i have to do is say this dot toast element dot text content equals value that one's really simple to do so let's see if this works already it looks like it is showing us a toast and if we look here we're not actually setting our text so if we set our text to hello there we go it's putting the text directly inside of there it looks like the space is kind of too big um let me see here it's just our padding is really large we probably don't need as much padding as we have because this looks really big um let me come into our styles i'm going to reduce our padding like half that's a little bit small maybe 0.75 yeah we'll do 0.75 again it's not so much about styling but i don't want it to be completely ugly if that makes sense okay back to our index so this is creating a toast and you know we could call toast.remove and we would need to handle removing it as well so inside of our here and let's just do like a set timeout set timeout we're going to do it after one second we're going to remove our test so back into here what i want to do is i want to implement this remove function so what i want to do is i want to take our toast element and i just want to remove it this should be all we need to do so after a second there we go it removed itself but also i want to check to see if our container has elements inside of it and if not i want to remove it because if we go into here and we look at our elements tab you'll notice this container is still down here even though we don't actually want this container to be here we want to get rid of it immediately if there's no more elements inside of it so what i probably can do is just say this dot before i remove it i can say toast element dot parent element so i can say container is equal to that and then i can remove it or sorry this is in the wrong section this should be here there we go then i can say if container dot has child nodes then do nothing so return otherwise container dot remove that should be all we need to do so it should now hopefully remove the container because it has no children inside of it and it did and if we also wanted to add another toast like two seconds later for example two seconds after our page starts we're going to add a new toast that says second we're going to put it in the top right location and we're also going to add a new toast in the top left and this is going to say third okay let's see if that works so we have third and we have second these are a little wide if i zoom out here you can see okay we have third and we have second let's inspect our page to see if our containers worked properly living container for top right and container for top left that's perfect so it looks like it's able to remove and show our containers exactly as we want and if we don't add this top right one hopefully when i inspect here we're only going to have a container for the top left inside of here yeah we only have a top left container it's always using the minimal amount of containers possible which is obviously what we want that's really good so now let's think of what we all want to implement for our toast because right now it's just a really basic message that doesn't do anything probably one of the first things we want to implement is auto close because that's like the most common thing you're going to do is automatically close this after a certain delay or just make it not auto close so inside of our toast let's implement that we're going to have a setter for auto close there we go and in auto close what we want to do is want to set a timeout in this timeout we're just going to call remove and then we're going to have our value here that's going to be taken in there we go what i want to do is i want to say hey if our value is false i guess if it's just any falsy value so we just say if we don't have a value so if it's falsy actually let's make it so it has to be exactly the value false so you have to pass in exactly false so if you pass in false then do nothing because we don't want to automatically close it otherwise we're going to use whatever the value is to close it after that set period of time this way even if you pass in zero it'll automatically close itself immediately we can put this on one line to clean this up a little bit what i want to do is i want to say interval actually we'll call this auto close timeout is equal to that and the reason i'm doing this we can just come up here to find that the reason that i'm doing this at least the reason i'm thinking i'm doing this is because if we change our auto close value i essentially want to reset the timer that we have running inside of our thing what i could do is i could say if this is not equal to null then i could clear timeout of our auto close timeout make sure i put this in front of it on all those instances this and this there we go i can clear the timeout and then restart it that way if you change your auto close time after the fact it'll restart your timer i think that's what we want that seems straightforward i mean honestly changing the auto close timer is probably something you're not going to do but if you do it'll reset the timer okay so let's see if auto close works first we're just going to say auto close of 1000. if we come back over here we click save it should hopefully remove itself after one second and it does if we pass in false for example it doesn't do anything and if we leave this value off it also doesn't do anything which i believe is what we want also what i want to do going back into my toast is i want to set up some default options so we're going to come up here we're going to say const default options is equal to and this is where i'm going to find some default things so for example auto close i'm going to set to like five thousand so auto like if you don't set anything auto close will be five thousand and if i could just say here my options is equal to actually we don't want to do equal to we can just say options uh let me think about the best way to do this here we go so when we do our entries i'm going to spread our options over our default options we're going to go like this so what this a little bit of code right here does is it's saying take all my default options and then take all the options being passed in i make sure i've spread this it's saying spread out all my current options that are default and all the options i pass in overwrite anything that's not defined in default options like anything i pass in overwrites what's in the default but if i don't pass in an auto close like i didn't pass one here it should auto close after five seconds so if we give it a little bit of time i think it's been over five seconds it didn't oh no there we go it's been five seconds it closed itself so now our auto close is set to close after five seconds same thing with position we should probably give it a default position of let's just say like top right this is going to be our default position so now if we come in here and remove our position it should still show up in that top right position and it does okay so far i'm kind of liking how this is coming along we have auto close we have position and these are essentially done i don't need to like mess with these at all same with text that is done um update what i want to do is i want to take in some options with update i want to do the exact same thing that i'm doing up here so i'm going to copy this paste it down and actually what i'm going to do yeah here pass in those options so for each option in the update i want to call this function and up here i just want to call the update function and i want to pass it in my default options so that way i don't have that code duplicated so now if we call update we should hopefully be able to change something for example if we come into our script i can say toast.update and i want to update the text to buy i'm going to do that after a second so now it says hello and after a second it changed to buy that looks really good one thing that i think will break though is if we change our position i'm not sure how this will work so let's change it to like top left okay so it does move to the top left but i bet you that our old container is still there yeah our old container for top right is still there so inside of our toast when we change our position what we need to do is we need to get the current container that the element is in and just do our check to remove it so now we can do is we can just come up here we can get our we'll call this current container there we go then we can copy this and we can paste it down here so if our current container has children do nothing otherwise remove it so i think that works looks like we have an error so let me inspect our page cannot read property null current container okay so if current container equals null or it has children then return there we go so now if we inspect we should hopefully see that that container is removed and yes it is okay so essentially any time that we move something from one container to another or when we remove something from a container so either remove or setting our position we need to make sure we get rid of the old container so we don't clutter up our html okay that's done we got position done we have update done we have removed done now we just have a lot of the more fun functionality in my opinion of getting a bunch of these different properties to work so position check that off we're done with that on open and on close those are pretty straightforward since we don't actually have a show method on open doesn't really make sense but on close does so we're going to have an on close option that by default is just going to be nothing so we'll say on close by default does nothing it's just an empty function and then whenever we call remove what i want to do is i want to call that on close so we say this dot on close there we go and we can create a setter for on close and i want to call on close oops this dot on close equals value um actually we don't even need a setter because honestly this doesn't do anything when we set it so we can just have our update function set the on close property we don't actually need a setter for this so i believe this should work so if we come into our script here we just say on close and we're going to say alert i so now if we set the auto close to something a little bit sooner like a thousand we see okay we already saw the message but yeah now after one second it's going to print out that high message there we go works really good um actually though i don't think that's quite working let me remove that real quick let's see okay perfect when we move position it doesn't trigger on close which is good because we don't want it to there we go so it's only triggering when we actually close out of the toast that looks really good okay what is next on the list to implement so on open again doesn't make sense for us we have auto close close button okay this one we're not going to do the close button because we don't want to be able to have people change the close button but we are going to make it so that it's either going to show the close button or not so i think what we can do is we'll just do like a can close yeah we'll call it can close and that's either going to be true or it's going to be false so by default if we come into here we're going to set it to true so we're going to say can close is true there we go and if we can close what i want to do is i want to set up an event listener on the button that is going to close it so we can say um in our update actually we can do this in the we can say set on close yeah we can do a setter for this because we can just say document dot at event listener on click so just click and what we want to do is just remove it so we can say this dot remove we need to make sure we bind this oh this is kind of a pain to do let's just create i think the best way to do this yeah so we could say like this dot remove equals this dot remove find it there we go bind this i believe that we have to do this and i'll explain why in just a second here so by default if we say our we're adding our event listener we're passing in this dot removes our function the actual this keyword will not reference our object it'll reference you know something else related to the document being clicked so by binding the this property to this current object all we're doing is saying hey when we call this function this which we reference inside of here multiple times references the actual toast object itself so i believe that's why we have to do that and the reason i'm doing this is because i want to be able to remove the event listener based on this value so if value is true then what i want to do is i want to add the event listener else i want to remove the event listener there we go that should be all we need to do so um yeah let's come into here we're going to say auto close false so it's not going to automatically close and get rid of this set timeout for now so now if i click on this it should close it's not we're clearly doing something wrong i think it's because we don't have a default for can close oh we do it's true and here we called this on close that is my problem should be can close still not working when we click on it let me see nothing um console.log value let's see what this is printing out console it's printing out true so that means it's adding the event listener for remove binded which is calling this function right here for remove so it should be calling this we just say console.log here let's see inspect console click nothing okay something is happening oh duh we don't want to add the event list in our document we want to add it on our toast element first of all that's the problem still not quite working but at least i added it to the right thing this time so let's see if we just do like this this dot remove this should hopefully work okay that does work so something to do with my binding is wrong i probably just am not remembering how to bind something so let's just google that real quick we'll just say uh js bind class function i'm just going to put react on the end because this is something that you have to do all the time in react so i should be able to hopefully find a good example of it um [Music] on click bind this that is exactly what we're doing hmm i'm just trying to think here so remove bind this is set to remove binded [Music] why does it not actually call that function then i could just do this i think this is going to do the exact same thing let's try then we can get rid of that whole bind syntax which i'm terrible at that's still not working oh i'm an idiot let's just back this up a few steps here and i know exactly what the problem is we're calling update before we're creating this function we just swap those two lines there we go it worked okay so i was just trying to access this before it even existed so that was dumb okay pretend you just didn't see the last 10 minutes of me trying to work on this so now whenever we click on it it is removing it and if we say can close and we set it to false so let's do that real quick we'll say can close false now no matter how much i click on it it's not going to remove it and we should also make this x button disappear as well so let's actually do a setter for it so if can close is true then actually what we can do is we can just say this this dot toast element.classlist.toggle can close and it's going to be toggled based on our value so now we can do is we can say hey our toast that we can close then we're going to put an x so only if we can close the toast do we put the x so this one cannot be closed so there's no x that shows up if we change can close to true by just leaving as the default now the x shows up we click it and remove it okay awesome so can close is done text position auto close we're starting to really get through this pretty quick so that's our close button transition i'm not going to work on because that's something that is in the react that's going to be handled on react but speaking of transition we should probably add some css transition because right now it just appears and appearing is just kind of ugly so what i'm going to do i'm going to get rid of all this i'm going to create a button and i'm just going to say show toast okay and this is just for testing purposes so i'm going to say crease document.createselector button button dot whoops yeah just say just add event listener click and i just want to create a toast there we go so whenever i click that it's going to create a toast and they're just stacking on top of each other right now i want to make it so that they are going to uh slide in because right now if we look over here and we click that show toast you can see it slides in it's super cool you can just see them all sliding in i really like that so i want to implement essentially the same exact thing that should be really easy to do by just putting an animation on our toast actually maybe a transition would be the best option for this let me think because we want to make it so it animates out as well because if we look at this we click show toast and then we remove it you can see it slides back in so transition might actually be the best option for that so we can say here that our transform translate in the x direction we're going to start at negative 100 and like 10 so it's going to start just outside the bounds of the screen i believe is what we want but i guess the translate is going to depend a bit on the position because this is going to work fine we'd have to add like a show class as well so this would set the translate x to zero this isn't quite going to work though even if we add the transition on here we'll say like 100 millisecond ease in out on the transform property let's make it 250 milliseconds cap so if we give it a show class um so like in our toast we can just say we're gonna add the show class as well that didn't do anything oh we need to show the toast okay it already is showing up we need to add the show class after it shows up so we can just say like set timeout actually i believe request animation frame is going to be the best way to do this so request animation frame and what we want to do is just whoops at our show class let's see if this works okay that is working i'm doing it in the wrong direction this should be positive there you go you can see that they're sliding in from the right hand side the problem is though if we position it in the opposite direction this needs to be a negative percentage so an easy way to i think fix that is we can say dot toast container data position right then we're going to use this transform and if we have the position on the left then we're going to use negative that should hopefully fix all of our problems so in our script let's say position oops position is going to be math.random greater than 0.5 top right top left so half time will be on the left half time to be on the right that's not working um [Music] something is going on let me click show toast um it is not doing what i expect i probably don't have my show class translate x0 oh duh i need to select the toast inside of here so get the toast there we go that's saved um nothing is quite working as i expect changing x 110 translates to x of zero when the show class is added let's see what's going on click show it is showing this it says it's in the correct position but it's off the screen oh the css specificity gets me every time this selector is more specific than this one so we can just make this more specific by adding the toast container into it there we go so now it's sliding in half time to slide in from one side half time the other side there you go you can see that they're perfectly sliding in we also need to make the center work as well so center this should be translate of 0 0 because this is going to translate us in the y direction negative 110 percent sure so let's let's do that so our position is going to be top center okay um actually that doesn't quite work because we want it to come from all the way off the edge of the screen and not just slightly above its current position interesting interesting interesting trying to think of the best way to implement this i could just do like negative 100 vh that'll technically work and no matter how far down the screen it's always going to come from the top that i think is fine so let's come in here make our translation here like 300 milliseconds a little bit longer the x and y's are fine as is it's just the top and bottom so this is going to be for top center and then we're going to also need to do one for bottom center because the bottom center needs to come from positive 100. so if we set this to bottom we do the animation yeah they're working as expecting and you kind of see a little bit of jankiness of everything moving up one by one and that's just because we're adding these to the bottom of the list so like the thing is there and then it slides into place so everything else has to move up to account for it that's okay that's actually how this library is working as well you can see when we click show toast if we do it newest on top you can see it just kind of pushes them down it's fine and it's really hard to work around so i don't think we're going to worry about that right now so that gives us our positions with our translations so we got the transition done the next thing is the progress bar i think that's really cool so they have these really cool progress bars that you can see kind of slide down and then once the progress bar gets to zero then it disappears so i think we should implement something like that also we need to make it so that these disappear actually that's probably the first thing we do so auto close set to a thousand so if we show our toast after or we should probably put at the top so it's a little bit easier to see after a second it's just going to disappear it doesn't actually slide away so we need to remove the show class first before we remove it so that's actually really easy to do so in our toast whenever we call remove what i want to do is instead of immediately removing it i want to say this dot toast element dot class list dot remove show and then i can say this dot toast element dot um let's see here add event listener for transition end there we go then i can remove it yeah and oops we can also check for this information up here okay let's see if that works so now it's going to show up and then after a second it'll fade away and it should hopefully also remove itself because of that transition end we look yeah it's removed and the reason this is working is because transition end essentially waits for a css transition to finish and we're using transition here so it's going to wait as soon as this transition finishes then it's going to extract the code inside of here okay that looks good now unfortunately if we change our position we're not going to get a fancy cool animation but honestly changing position is something that's really niche and it doesn't really need a fancy animation you could implement it but i don't think we need it and kind of what i'm saying is if we come in here we like set a set timeout for a second we said toast.update position is going to be whoops top left put that inside of here change this to 2. so sorry my dog just went berserk i had to step away there for a second but we're testing this so we click it shows up on the top right and it shows up on the left there's no animation i think that's fine it that's something you're not going to change very often at all okay moving on transition the next step is going to be that progress bar i like the idea of the progress bar so we're going to have a property that's called like show progress and by default we'll set it to true let's say so let's just copy that into our toast up in the default setting show progress is going to be true so we need to actually change around our styles a little bit and we can do this really easily with like a before after element um even though we already have an after element on our toast for that close button so it might be a little difficult to do this let's see how they have theirs implemented let's see okay we can actually do this within just a before element because we just need one single rectangle pretty simple to do so we can say toast dot progress before content is going to be empty this time what i want to do is i want to put the position to be absolute inside of our toast i'm going to change our overflow to hidden that's just going to be so that if we click our show here you can see that the progress bar cuts off on these rounded corners without overflow hidden it would overflow those rounded corners i'll show you when we get to that point i'll just comment this out for now so our progress bar we're going to give it a height of like 2 pixels we don't want it to be very big and we're going to give it a width of 100 percent by default actually let's use a css variable for this so we're going to say progress is our css variable and we're going to do a calculation where we do 100 times our progress so our progress is going to be a value between zero and one and by default oh we can figure that out in our javascript sorry okay so let's do a background color of i should say blue for now i mean i'm not doing this for style purposes i think that'll be fine and we can say by default we'll set our progress to like 50 just so we can see what it looks like so we click show toast nothing pops up because we need to add that progress class so let's come in here what did i call the property show progress so we'll say set show progress takes in a value um and we'll say this.hostelement.classlist.toggle progress based on this value so you can see we have our progress bar obviously it is not positioned correctly bottom zero left zero right zero there we go there we go you can see our progress bar is on the bottom it's a little bit large um let me come back to our toast here for our script i don't want it to auto close i'm gonna do top center just to see what we're working with we can see our progress bar is really big for some reason uh let's oh this should be 0.5 there we go now that makes sense okay uh so now it's going to be 50 because we have 0.5 we change it like 0.25 25 if it's one it'll fill the full progress bar and as you can see if i zoom in really large here and i show this on like the top right real quick or there we go click show you can see very barely there's a little like pixel blue that's sticking out of our corner here if we change that overflow back to hidden that is going to fix that pixel blue and if our progress bar was bigger it would be more noticeable but since our progress bar is small it's pretty hard to notice so there we go we have our progress part looks really good and we're using the progress variable to define it and by default i'm not going to actually have a value for our progress variable i'm going to define that in our javascript so let's see if we're showing our progress we want it to be based on our auto close time here so we actually probably need to save information about the time remaining for it to show yeah we're gonna need to save that so we'll say like time visible and by default that'll be set to zero okay um and then we can just use a set interval i believe so like if value set interval and this interval is going to be every like 10 milliseconds yeah that's fine and what we can do here we should probably set our style.set property dash dash progress to one so by default we're starting our progress at one so we're going to set an interval and inside this interval we're just going to update this progress variable by taking the time that it has been visible we're gonna say like time visible divided by our auto close we're not saving that anywhere so we need to save that so inside of our auto close we're going to say this dot auto close equals value so then we can divide by our auto close value try to find that up here there we go make sure this is this so this is going to give us our proportion right there and then all you need to do is just update our time visible um [Music] so the best way to do that is actually just say uh this variable is going to be equal to time shown or like date shown we're gonna do like showing we'll do visible sense there we go i like that naming and then inside of here we're just gonna say this dot visible sense equals new date there we go and then inside of here we can say visible sense uh what i want to do is i want to get a time visible variable and it's just going to be our current date minus this date okay i think that'll work clearly something's not working i don't even know if i have everything set up properly yet we're not getting any errors let's just do a console.log of here see if it's even running this okay yeah definitely running that so our visible sense property should be set to the current date so let's just print that out we're going to print out time visible see what this gives us console okay it's definitely giving us a value which is good so our toast element if i inspect this real quick oh duh it's because our auto close right now is not set to anything it's set to false let's actually make it so it can auto close there we go our progress bar is doing the exact opposite of what we wanted to do we wanted to go the other direction so let's fix that next what i want to do is i want to say that we're going to do 1 minus this value and then in our styles i want the let's see what's the best way to do we can just say like display oh no we want to say margin on the left is auto that way it's always going to be as far pushed to the right as possible i believe that will work there we go we actually probably want the margin on the right though to be auto and honestly i don't think we even need that it'll just do it yeah do it on his own there we go and then once it gets to zero it closes the progress bar we obviously need to make sure we clean up these intervals though and these timeouts so let's save a variable for that we'll say [Music] progress interval our progress interval is going to be equal to that and then i remove what i want to do is i want to take our progress interval and i want to clear it yeah so we'll say this dot oops i already had this copied clear interval of that and i want to clear my timeout as well copy that over paste that into here so if we have a timeout i want to clear it okay so now for our auto close we can actually make it so if we change our auto close it'll not reset the time but it'll take into account the time that we've already had because we have this visible sense property um [Music] let me think yeah actually this visible sense we should probably put inside of our auto close because if we're resetting our auto close we want to reset our visible sense yeah okay that makes sense i think that works still yeah and if we change our auto close so for example i say toast.update close and i set it to 2000 milliseconds and i do this after a certain period of time has elapsed so if i do it after one second you can see our progress bar will reset and then it'll count down from that 2000. okay and everything is working i don't think we have any errors there we go and we're making sure we're cleaning up all of our memory so that i believe is working i feel like we're missing something but it seems to be working so far i think that's good i guess what happens if we set show progress to false so if we just say show progress false should hopefully just work yeah there's just no progress bar and i don't think we'll have any errors in the console nope no errors okay let's see um pausing on hover i don't really care to implement that it doesn't really matter in my opinion same with pausing on focus loss closing on click already have that class name styles more styles draggable don't care about that don't care about that delay honestly i don't think delay needs to be implemented because you could just use a set timeout so we don't need that so that's pretty much everything maybe we should do these pause and hover then so we'll do pause on focus loss and pause on hover okay so this is going to be really easy we just set a variable up here called paused which is equal to false by default and then any time that we lose focus or that we hover we want to pause it and we're going to do those based on variables so let's get rid of this show cause we're not implementing that we could say pause on hover value this is going to work very similar to what we did for can close pause on hover um yeah so if it's true we want to add the event listener for is there an event listener for hover i don't think there is um js hover event i think you just have to do mouse enter and mouse leave i guess mouse over there we go that's perfect mouse over okay and we're also going to remove the event listener for that okay and we need to create a variable for that um we're going to call this other pause binded we don't need to hover pause it's just going to be a function that's going to set this dot hover this dot pause equals false yeah we also need to add an event listener for mouse leave too i guess though so we're gonna have hover pause and hover [Music] i guess we could just i'm trying to think the best way to do this so hover pause is going to pause it on hover and this is going to be like actually we'll just call these variables pause and unpause i like this way better it's just going to set pause to false or true i have these named the wrong thing so unpause sets it to true oh no i had it right there we go so here we can just pass unpause and on the mouse leave we can pass pause copy these paste them down and instead of add it is removed so now if the pause variable is true then we essentially want to not update any of this information so let's see what the best way to do that is because obviously we just say you know like if this dot pause return but it's still going to be counting the difference between our date and the visible sense so that's not going to quite work as i expect it to so instead of doing this visible sense i think i do need to do a counter so we're going to say what i could do is i could say like let last render last time called equal new date okay yeah yeah this will work this will work and here we just constantly update last time called so new date so what i can do here is i can take the current date minus the last time called and that will give us something we can subtract from our variables we'll say time visible there we go that's what we need we can get rid of where we set i believe we set it in our auto close we don't need to set this anymore okay so i'm just changing this around how this works so our time visible is going to be our last time called minor our new date minus our last time called we're going to get our time visible minus equal or added that and then this gonna go down there it's a little bit messy but i think this is what i want i can clean this up a little bit by saying this goes in here and this goes in here so if it's not paused do that okay let me think about this real quick to see if this works so what we're doing is we're getting the last time this function was called and every time that this set interval runs we're getting the last time called it doesn't matter if it's paused or not and then when it unpauses or when it's when it's not paused we're just taking the current date and we're subtracting the last time that we called this function so it's going to be just the time between these two calls so it'll be around 10 milliseconds we're going to add that to our current time visible then we're going to take our time visible variable and divide it by this auto close here let's see if that works show toast okay it's already broken let's inspect and see what's going on private field unpause must be declared in an enclosing class oh um so we're going to say this should say like it shouldn't say pause i should say pause um okay actually we can call this pause and we can call this is paused just so we have some good naming we could say unpause and pause is paused there we go and then down here it should say is paused okay let's see if that works there we go we're not showing our progress let's make sure we show that okay the progress bar is not updating that's a problem um if this dot is paused is false then run this by default paused is false okay hmm let me just do a quick console log of this dot is paused it's probably going to be printed out true a bunch of times it's printing out false okay so it is running the code inside of here it's just this variable is probably not getting updated correctly let's see what this looks like not a number oh it's because we need to start it at zero by default there we go it's decreasing we had some weird going on there not quite what i wanted see if that repeats itself it does interesting so our time visible is incrementing by too much at a time that's really weird i think this through why this is doing this even when we hover it's not actually pausing mouse over should be calling pause and this should be calling unpause that should fix part of the problem no it's done that's still not pausing i should be sending pause to true if it's true this shouldn't run let's just do quick console.log here and i'm going to change my auto close to like a large number okay minimize that down show toast here hover still saying here this pause is actually more difficult than i expected because we just need to like stop counting but it sounds simple but it's a little bit trickier than i expected hmm and it's all because like when we pause it we can't just use the old date because when you use the old date it's way easier than having to do this like subtraction kind of stuff every single time instead of set interval let's do a request animation frame this is actually going to be quite a bit easier i think so request animation frame actually gives us a time variable and we can use this time variable so let's call we don't need to pass it this we're going to call requestanimationframe uh so we need to give it a function to pass so we're going to create a const funk is equal to name is kind of ugly but it's fine time i'm just going to copy and paste all this into there and we're going to request our animation frame for funk we don't even need to worry about this um yeah requesting animation frame for that and then we also need to request it again here i think we can pass it like a default time so like request animation frame takes in a callback there's a cancel animation frame okay that's good i thought there was a way to change the start time of it first animation frame start time let's see not quite okay it doesn't look like there's a way to do that that's fine we can just say uh if last time equals null last time equals time return uh we could say let last time equal well we don't have to equal anything okay and then here we could say time minus last time see if this works a little better okay we're messing up something see we had an error our console nope no error let me just read our code so the last time equals null oh we we can't return here we need to call the best animation frame again there we go it's all right okay is it even logging out here okay last time called is not defined where do i have that there we go we don't need that that went really fast uh very very fast let me see gosh what is this this time variable should be milliseconds i believe let me just print it out do time minus last time it's constantly growing oh because we're never updating our last time there we go gosh it has that huge jump what is going on this time visible i think there's something really weird going on here let's just print out what our time visible is for the test like it seems like updates pretty smoothly try that again yeah it seems like it updates smoothly like nothing seems to be jumping in my opinion so let's print out what this value is because maybe it has something to do with like rounding or something i don't know inspect console okay there's a big jump there there's a really big jump i saw it go up a little ways it jumped from like 10 to essentially 90 almost instantly i thought yeah here we're at 10 10 10 10 50 um that's interesting oh duh it's because we're changing our auto close here uh so if we change our auto close it's going to mess with all of our timings for everything um so if we change our auto close oh yeah duh we just say this dot time visible equals zero there we go that fixed that now we just need to obviously clean this up so we can say when we call request animation frame how does this work um return value let's see how we can return it every time we call it yeah we need to update it so what we can do is we can say progress we'll still call our progress interval it really doesn't matter every time we call this we should need a set oops this is in the wrong location there we go we should need to set our progress interval every time that way we clean this up there we go so now if i console.log time come over here click show toast and i inspect go to my console it's still not cleaned up and that's because instead of calling clear interval we need to call remove uh what is it called cancel animation frame there we go let's inspect go to the console it's printing and as soon as it's done boom done no more printing so it clears out that animation perfect okay so now we got a progress bar showing i like it i like it we also need to so if we hover it'll pause it's not doing anything with the pause thus that's the next thing we need to work on mouseover this dot pause should say this dot is paused equals false let's just see what's going on in here i guess it's the unpause function i care more about what's happening inside pause oh it's probably the this property thing again i don't know we'll see we'll see we'll see um [Music] console.log this get rid of all these parentheses there we go okay inspect the page go to the console gotta make sure this console log is removed as well yeah when i'm hovering is doing absolutely nothing it's not calling that function on mouse over oh my gosh i think i know exactly what it is it would really help if we passed pause on hover as true there we go stop the countdown it doesn't stop the auto close though that's the next thing we have to work on but man am i an idiot so auto close um we can't quite do a set timeout can we because pause we need to pause that timer so we can just use this time visible here we can again do a request animation frame up here so we can say um yeah we can say request animation frame or our funk we call it that shirt const funk which takes in a time oops man i cannot type today okay it takes a time we have our time visible so here what i want to do is i want to change around how this works i believe because this is updating our last time this is the thing updating our time visible i want to update time visible inside of auto close because that's the one that actually cares about the time visible okay get our last time information up here as well there we go get this little if check and we're going to call this auto close interval so this dot auto close interval is equal to that there we go and here it should say the same thing so we're duplicating a lot of this code and then we're going to un-duplicate it by removing it from here because we don't need that we don't need that we don't need this we don't even need this time variable anymore it doesn't matter this doesn't matter all we're saying is if it's paused take the time visible yeah we go there we go okay and yeah that's pretty much it so up here we can do is just do our code to remove it so if i removed this down here too soon let me back up a few steps okay i guess that's the only thing i removed so we want to take our time visible and increment it and then if our time visible is greater than or equal to our auto close then this dot remove there we go it's that simple and then what we can do is our request animation frame thing again okay but this time i'm going to return after this because if we remove it obviously we shouldn't create a new animation frame okay get rid of the timeout related stuff so [Music] if the auto close timeout we don't even need that anymore i don't think yeah because we'll just set the time visible back auto closes our value okay i think this is what we need down here let's get rid of all that extra code we don't need and then we just need to make sure that if it's paused not do any of this so it's not paused then we can increment everything okay let's see if this works automatically error kind of what i expected console private field auto close timeout done down here we changed it to auto close interval and this should say clear animation frame okay it's not quite working reference time is not defined all the way up here time minus last time we don't need this in the show progress that could be removed still got some errors though go to our console printing out a toast i don't know why we got a toast being printed out oh it's because our pause has toast being printed in it i think yeah we can get rid of that doesn't look like anything is working let's go into our auto close here because this is where all the magic should be happening console.log this dot time visible let's just see if this is incrementing up as we expect not a number this dot time visible equals zero time minus last time if last time is equal to null then we're not doing anything oh this should be removed i don't know why that was up there okay that went really fast what is our auto close time all right i guess we'll just inspect this real quick and see why this counts so incredibly fast whoa that yeah that counted way fast i mean that was huge time minus last time oh we're never updating our last time i forgot to do this again there we go okay show test that's working there we go okay and now if we hover over it and unhover over whatever hey i think that actually worked if we get rid of this weird stuff that's changing our auto close time hover paused on hover unpaused yeah that looks really good and then as soon as we wait for it to go boom disappears now the last thing that we have left is the pause on focus loss boom set it to true this is going to be significantly easier i believe because we have all the pause logic already done so we can just copy this pause on focus loss and we're going to add a event to the document so let me see uh window lose focus mdn.js oh that's not i think it's like visibility there's like an event for specifically yeah page visibility here we go um visibility change okay there we go it's called visibility change okay and what does it return to us what does the actual event look like does it have no okay we'll just use document.visibilitystate so we need to create a another function for this called like visibility change equals okay so if it is hidden then this dot pause is paused equals true let me just say this dot is paused is equal to that okay and we can use that function down here visibility [Music] what i call it visibility change i try to find it up here and right there and we can remove the event listener down here so now hopefully we show our toast let's go to a different window and now we waited a while we come back it didn't pause pause on focus loss let's make sure i spelled this the same everywhere pause on focus loss should be calling this visibility change let's just do console.log of our visibility state not even calling this function it should definitely be calling this function whenever our visibility changes maybe i spelled this wrong visibility change visibility change is ability change it should definitely be evoking unless it's not supported it definitely looks like it's supported for a long time let me see not supported okay but it definitely has been supported for a long time so we should be fine let's just see console.log here let's just make sure it's actually calling this in the first place okay i did call it we get rid of our other console logs that we don't need uh where's that one we don't need there we go get rid of this one um should be see console hidden visible so hidden okay this dot is paused it's equal to true when it's hidden we call it is paused everywhere yeah is paused as pause is paused let's just console.log this let's see okay console go toast move away okay true it is hidden false it is visible but our thing is still updating itself and it shouldn't be let's print out this to see what this is because maybe our this is referencing the wrong thing show the toast no it is referencing our toast and right now pause is set to true when we come here it's clearly not pausing our time visible is still updating even when paused is set to true but this doesn't make any sense oh it's probably because request animation frame doesn't run when you lose focus on the page uh okay let's see oh okay so it loses focus when the page loses focus it stops calling our event listeners our animation frame event listeners this is a bit of a pain because we kind of set this all up assuming that these are constantly going to be running so let's see go back up to our auto close we need to essentially change this to a variable that's like should on pause so if the visibility is visible then this should be set and then we can say if this dot should on whoops i'll try to find that out here this is a bit hacky but i think it'll work should on pause then last time equals null let's try it show toast okay move over here move back i did something definitely did something oh and then we need to say this dot should unpause equals false okay so essentially what i'm doing with this is i'm saying hey once our page becomes visible we need to unpause but our timer has been running in the background for a long time like we haven't been updating our last time so we should just reset everything and reset our update times when i come back yeah it's it's working now we come back here come back yeah and it removes itself okay it's a bit hacky i'm not a huge fan of it but it works and that finally is the last step that we needed to do in order to make this work exactly the same as the react toast and honestly it's not too much code with you know everything included well that took a little bit longer than expected but overall it turned out great now if you want to see a shorter project of me live solving a multi-step form in javascript it's going to be linked over here and with that said thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 106,959
Rating: undefined out of 5
Keywords: webdevsimplified, toast notification, toast js, react toastify, toast library, toast message, toast message js, javascript, js, javascript toast, javascript toast message, javascript toast notification, js toast notifcation, toastify
Id: HhpbzPMCKDc
Channel Id: undefined
Length: 84min 19sec (5059 seconds)
Published: Tue Mar 15 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.