YouTube Transcript:
The Complete Svelte 5 Course For The Most Loved JavaScript Framework
Skip watching entire videos - get the full transcript, search for keywords, and copy with one click.
Share:
Video Transcript
Hey friends, welcome to the Swelt 5
course. This course was made for new and
existing Swelt developers. In this
course, you're going to get hands-on
experience starting from the basics to
more advanced topics. You're not only
going to learn how to use Swelt, but
also how it works. I believe that
knowing how things work gives you
greater joy by being more competent at
what you do. This course was a lot of
work. So before we get started, I would
appreciate it if you subscribed and
engaged with the video by liking and
leaving a comment for the algorithm and
listening to the message from our
sponsor. This video is sponsored by
Sentry. If you want to see all of the
errors in your application and have more
insight when things go wrong instead of
guessing, you want to check out Sentry
at sentry.io. The worst case scenario is
when something goes wrong in your app
and you don't know about it, costing you
a potential customer. Sentry gives you
complete visibility in case something
goes wrong with error monitoring to get
actionable insights to resolve the most
important code related issues and other
features like log so you can see what
happened and why. Session replace to get
to the root cause of an issue faster by
watching actual replays of real user
sessions. Tracing to find out why an API
is slow or where a crash came from. And
Sentry even has a new AI debugging
agent, Sier, that can debug the root
cause of an issue and open a pull
request with a fix for you. Sentry
supports almost everything and makes it
incredibly easy to get started with SW.
If you're using Swellit, you can use
their installation wizard to set
everything up for you or you can do a
manual setup. Thanks to Sentry, Sulki
now has even first class support for
observability with built-in open
telemetry tracing and a dedicated
instrumentation setup file that ensures
your monitoring tools work seamlessly.
If you're a solo developer, you can get
started today for free with Sentry's
generous free tier. So, make sure your
user experience remains great by using
Sentry at sentry.io. Thank you, Sentry,
for sponsoring the video. All right,
before we get started, you're going to
need Node.js JS to run and install npm
packages. So you can go to the node
website and under get NodeJS, you can
pick your target platform. For the code
editor, I'm going to use Visual Studio
Code, but any VIP coding fork of VS Code
is going to work. And of course, we're
going to need the swelt for VS Code
extension for syntax highlighting and
other features. If you're using another
editor like Jet Brains or Vim, you can
find the Swelt language server for your editor.
editor.
Usually to set up swelt you would use
the vit C cli by saying npm create vit
at latest and then you would get a bunch
of options for other frameworks but you
could pick swelt and you can pick if you
want typescript or javascript in this
course I want to focus on swelt and I
think that types are just visual noise
so I'm not going to be using typescript
but if you care about types I'm going to
include a link to a post where all of
the examples are going to be typed and
this course is also not going to be
focused on swell kit the meta framework
for swell If you want something with
more opinions that has routing,
serverside rendering and so on, then
once you're done with the course, I
encourage you to look at swell kit. In
this case, we're not going to use the
vit CLI, but a swel starter that I
prepared. The swell starter includes the
assets, styles, and packages that you're
going to need through the course. It
also uses the minimal CSS framework,
Picos CSS, so everything looks great out
of the box. This way, we can focus on
what's really important. To get started
with the SWEL template in your terminal,
you can type npx dit the name of the
repo which is going to be joys of code /arn-swelt.
/arn-swelt.
And you can name the folder whatever you
want, but I'm going to name it learn-swelt.
learn-swelt.
This is just going to copy the repo
without a commit history and it should
take a second. All right, let's cd into
learn swelt. All right, so now that
we're inside learnswelt, we have to
install the dependencies. So we can say
npmi and this should take a second. Once
it's done, you can run the development
server by saying npm rundev. All right,
let's go to the browser. Now you can
open a new tab and let's navigate to
localhost 5173 which should open the
default example. Now you should have
swelt running on your machine. All
right. So what is swelt? If we go to the
swelt web page, we can see that swelt is
a word that means attractively thin,
graceful, and stylish. And here we have
the definition. Swelt is a UI framework
that uses a compiler to let you write
breathtakingly concise components that
do minimal work in the browser using
languages you already know, HTML, CSS,
and JavaScript. So, let's actually
investigate this claim before you even
start learning about swelt. So, here I
am inside of VS Code and I already
opened the learn Swelt project and this
is just a minimal VI project so we keep
everything simple. And if you aren't
familiar with Vit, here we have index
html which is the entry point of our
application. Here we have the public
folder so you can put your assets inside
of here and the most important source
folder where we're going to keep our
code. So let's open the app.swel file.
Let me bump the font size up. As you can
see here, we have something that looks
like regular JavaScript and HTML. But
unlike regular JavaScript, this count
value here is reactive. So if we go to
our example here, and we can just
increment the count and you're going to
see it's going to be reactive. So the
advantage of cell being a compiler is
that you can take the syntax of
JavaScript and change the semantics for
a better developer experience. In this
example where we have count++ here we're
actually using reassignment to update
the value reactively. So you can also
say plus= 1. And this is the same thing
of course and we can actually see the
compiled output. If you have the spelt
extension you can press control shift p
and you can type show compiled code here
and it's going to show you the compiled
code. As you can see, this is human
readable JavaScript. Of course, I
cleaned it up a bit so we can actually
examine it more. So, let me just open
this empty tab and I'm going to copy
paste some code here. So, here we have
this function app which accepts a
target. And then we're creating this
reactive value which is actually a
signal under the hood. And then here
we're creating the DOM elements which is
the button in this case. And then we're
going to append it to the DOM. And here
we're just retrieving the text node from
the button. And then this is the
reactive part. So we can update the DOM
when state changes using this template
effect. And later we're going to learn
more how this works. But as you can see,
what we learned from this exercise is
that swell doesn't have a virtual DOM.
It doesn't rerender the entire component
when your state updates like React. It
does granular updates to the DOM when
the state changes. This is what makes
SWEL fast and performant and what it
means to do minimal work in the browser.
All right, let's start from the
beginning. Every file that ends with the
dotselt extension is considered a swelt
component. To be more precise, it's a
single file component. As the name
implies, a single file component means
that all of your logic, markup, and
styles are inside of a single component.
So, for example, here we can create this
logic block. We have markup
and styles. So, let's create a script
tag here. And then we create a variable
named title that has the value of inside
of the markup. You can put anything you
want. You don't need a special template
tag or anything like this. You can just
create elements directly. So let's
create a heading and then we can use an
expression inside of it. So we can use
the opening and closing curly boys. Now
we can press save and we can see swelt
in the output. But of course we can add
some styles. So let me create a style
block. We're going to target the h1
element. Let's say color orange red.
Same as swelt. And that's basically it.
I'm going to save it. And now we're
going to see we have this orange text as
well. And of course, the order of the
blocks isn't important. For example,
even if I take this style block and I
put it at the top, I'm using prettier.
So when I'm going to save it, it's going
to reorder it for me. So I'm pressing
save. And as you can see, it reordered
the blocks. So the order of the blocks
isn't important at all. Of course, you
can also use TypeScript. You can specify
here leng. And then you can say
TypeScript here. And of course, this is
inferred, but we can use types here. We
can say string. And you can even use
TypeScript because it's natively
supported in the template. So we can say
title as string. But of course, I'm not
going to focus on TypeScript in this
course because I actually think it's
very distracting when you're learning.
It's just visual noise. But if you care
about types, I'm going to link to an
accompanying post in the description.
All right. So lowerase tags behave
exactly like regular HTML elements, and
so do attributes. So let's for example
create an image here. We can pass it a
source attribute.
Let's say image GIF. And we're going to
see something also very cool. So when we
do this, we're going to get a warning
from cell that says image element should
have an alt attribute. So let's do that.
Let's add a description. We're going to
say alt
person nodes. Let's save this and we're
going to see the output. How wonderful
is this friends? All right. So going
back, we also have the power of
JavaScript. So we can create the script
tag. Let's create a variable source.
We're going to say image.give.
And let's also create another one. Name
it alt. And we can also give it a description.
description.
Awesome. So now we can use an expression
here. We can say source.
And we can say alt. Another cool thing
is if the attribute name and the value
have the same name, you can just use the
shortand. So in this case, instead of
source equals the source expression, we
can just say source. But let me actually
show you something cool. Because I'm
using prettier, it's automatically going
to do that for me. All right. So, I'm
going to save right now. And you're
going to see it works the same as
before. But of course, we can also use
an object. So, I can say let object,
let's say source
image.g. And then let's give it a
description. And we can say person not.
So now we no longer need this. And of
course, this would be really tedious if
you had to do something like this.
source equals object source alt equals
object alt. Of course, it works as
expected if you look here, but there's a
simple way to do this and we can spread
this object on this element. So, we can
just remove all of this, use the curly
boys and we can just use the spread
syntax. So, we can spread this object
and everything works as expected.
There is one more thing regarding
attributes that I want to show you and
that is how to conditionally render
them. So, often people make this
mistake. they define some piece of state
like lazy let's say false and then maybe
you want to conditionally render this
attribute loading here so we can pass an
expression and then you can say okay
lazy in that case we can use short
circuit evaluation and then we can say
lazy all right anyway we think since
this is false this isn't going to be
rendered but that is wrong and also
typescript gives you a warning here
because the types don't match so here
for example if I save and then I go here
and inspect the element you're going to
see we're going to get loading equals
false which might be completely
unexpected Or you might do something
like this. You might use a turnary. So
let's say lazy. And then in that case,
we can actually show lazy. Otherwise,
you might be thinking to yourself, okay,
let's just use an empty string here. And
again, we get this warning in our
editor, which is super useful. In this
case, when I save this, we're going to
see we're going to get an orphan
attribute loading. All right. So the
solution to this is to never use short
circuit evaluation like this or this
turnary where you return an empty
string. Always use null or undefined. So
for example, if I say no here, you're
going to see TypeScript is going to be
happy. So now if I save this, you're
going to see this behaves exactly as you
would expect and the attribute isn't rendered.
rendered.
All right, so let's talk about component
styles. Let's create a script block with
a color variable. So let's say orange,
red. Let's create a heading with some
text inside. And I heard a bunch of you
like some inline styles with this thing
called tailing CSS. So, of course, you
can just use the style attribute and you
can include all of your styles inside of
here, right? I'm just joking. But the
style attribute is really cool in SW and
I'm going to show you why. So, we can
just use a regular CSS property. And
here we can use an expression. So, you
can pass color and you're going to see
it works as expected. But there is also
a shortand you can use. So, instead of
saying style equals, we can just use the
CSS property using colon color. Then we
can remove this and we can just leave
the expression in like this. Boom. And
since the variable name is the same name
as the CSS property, we can also omit
this part. So you can remove this. And
I'm going to save this. And you're going
to see it works as expected. The only
thing you can do with a style attribute
like in another framework, you can't
really pass an object. So something like
this isn't going to work. If you say
style equals, and then you may want to
pass a color. That being said, I don't
think I actually ever needed this use
case. And if you want something like
this yourself, you can write a simple
utility function. The style attribute is
also great for using CSS variables. Let
me show you how cool that is. So here we
can create a style block. Let's just say
H1. And then we're going to define the
color. Let's use a CSS variable. By
default, we're going to pass color. If
that doesn't exist, we can specify a
default value as white. And here we can
just use a CSS variable
dash color.
And we can just use our color as before.
And of course we can also use the
shortand. So here we can say d-color.
And then you can say equals. And we can
pass in the expression or a color. All
right. So if I save this, you're going
to see everything is going to work the
same as before. And this is something
that I absolutely love about swelt.
Thankfully, you're not just limited to
the style attribute. So let me just
remove all of this code.
And we're going to say that color should
be orange red.
And this leads us to another awesome
thing about SWEL. By default, any styles
that you define inside of a SWEL
component are going to be scoped to that
component. That means that the color we
define here is only going to affect the
heading inside this component and not
globally. So if we go here to our
example and open the developer tools, we
can go to the head and see what swell
generated. So we can see that swell
generated a unique class name. So this
way your styles aren't going to clash
with anything else. You can also of
course import CSS inside of your
component. So for example, if you have a
script tag here, you can say import and
then you can say something like app.css
and then you're going to import styles
that apply to this component. But of
course you can also have global styles.
So if I remove this, I'm going to go to
the root of my app which is main.js.
And here I can import app.t CSS which
I'm already using. So let's actually
look at app.tss. So here I have just
some basic imports and some CSS
variables. So if you want to define
something global here, you can just go
here and you can say for example H1
color red and now we have global styles.
That's how easy peasy lemon squeezy that
is. But of course I'm not going to do
that. So now you know how to apply
global styles if you have to. So
speaking of global styles, you can also
have global styles in your component. So
let's say for example that you receive a
post from a content management system
and maybe you don't have control over
it. So here I have some piece of content
and let's say I want to render it. I can
use H group and then we can use the
special at HTML tag in SW to render raw
HTML. So we can say HTML content. Let's
save it. And you're going to see it
works as expected. So let's add some
styles. So we can say style. Let's
target the H1. Let's say text transform.
And we can say capitalize. What you're
going to see, we immediately get a
warning in the editor by SWelt undue CSS
selector H1. And that is because in
quotes SWelt can't see that this style
is being applied here. So, it's going to
be removed.
And for this reason, we can use the
global style modifier. So, we can say
colon global. Let's use parenthesis
like this. Save. And you're going to see
everything works as expected. All right.
But this would be really tedious if you
had to do this for every element. So for
example, if you had to do global P and
etc. Now it's really annoying, right? So
let's say we have some styles here,
whatever. And we can actually get around
this by just using global. So here's
what we can do. We can say global. Then
we can just use the curly boys. And then
we can just move the styles inside of here.
here.
And of course, we don't have to use global.
Let's just do this. Remove it
like here. And now we're going to see if
we save this everything is going to work
as expected. And this is only
complaining because we don't have any
styles here. But we can for example say
color orange red.
And now we're going to see it works as
expected. Of course, one downside of
this approach is that these styles can
clash with your global styles. But we
can also fix this. You can have global
scope styles. So what do I mean by that?
So here we have this HG groupoup
element. before global we can actually
just say H group and it's going to be
scoped just to this element. So let's
save this. All right. So we can open the
developer tools to see what SW
generated. Let's go to the head. We can
open the style block and we can actually
see here SW generated this unique class
name but it's prefixed with H group. So
this way you can have globally scoped
styles. You can also have global key
frames. So, for example, inside of here,
if you use a key frame, it won't really
work. But you can do this. You can say
add key frames.
And now you can just preface this with
global. And you can just use the name of
your animation. You can say animation.
And then you can define your animation
inside of here if you want to make it
global for whatever reason. And there is
one more cool thing about the style
block and that is that you can use a
different pre-processor. So similar to
TypeScript, you can define a lang
attribute here and you can define SCSS
for SAS or you can use post CSS and it's
going to work out of the box. How cool
is that? All right, so let me show you
another cool feature of SWEL which are
dynamic classes. So for example, let's
say we have an accordion here. We can
say open false and then we can create
button with a class button and then
we're going to have a span item A and
then another span. So we can say point
let's see use this emoji. So this is
going to be our trigger
and then of course we can use an
expression inside of here. All right if
open is true then we can say apply an
open class otherwise do nothing and then
we can create some styles. So we can say
trigger. We have to say that this is
display inline block. So our animation works
works
and let's just say transition. We're
going to use rotate. So we can say
rotate 2 seconds ease
ease
and then we can say hey if this has an
open class then we're going to animate
it. So let's say rotate
minus 90°.
All right but in this case this isn't
reactive yet. We're going to learn about
reactivity in the next section. But for
right now we can just say state false.
And then here we can just say on click.
And then we can just set open to the opposite.
opposite.
All right. So let's save this. And we
should see, let me just zoom in. We
should see this works as expected.
Awesome. All right. But applying classes
like this can be really tedious. So
there's actually a better way. We can
use the class directive to conditionally
apply classes. So we can remove all of
this and we can say class colon and then
we can say open. And of course you can
base this on some other expression. But
in this case we can just remove this.
And now I can save this. And you're
going to see it works the same as before.
before.
You can also pass an object or array to
the class attribute. So let me show you
how cool this is. So we can say class.
And let's first start with an object. So
we can say trigger. And if this is true
then this is going to apply this class.
We can also just pass open. So now this
is going to be trigger and open
conditionally. All right. Let's save
this and it should work the same as
before. Of course, you can also pass an
array. So, for example, if I pass an
array here, we can first define our base
styles. So, it's going to be trigger and
then we can apply open conditionally.
So, we can say if open is true, then
this is going to be open. Let's save
this. And you're going to see it works
the same as before. Or instead of this,
you can pass an object, which is a lot
simpler in my opinion. So, you can just
say open
and it works the same as before. And
under the hood, this uses the CLSX
library to merge all of these styles
together. And this is really useful if
you're working with Tailwind and you
need to apply a bunch of classes. So for
example, here again we have our base
styles, we can say transition transform.
And if you want to apply some tailwind
class like for example rotate 90, we can
just make it conditional like this and
it's going to work beautifully. All
right, but there's something else that
you should consider. So instead of
applying a bunch of classes, if you have
something more complicated, use data
attributes instead. So for example,
instead of this being a boolean, we can
say status and this can be open or
closed. So in this case, this on click
really doesn't matter. Let me just
remove this and then we can just go
here. We can say class trigger. So we
are separating our styles for styles and
our logic for data attributes, which is
really cool. So we can say data status
and then we can just say status. And now
if you have something more complicated,
now it's way easier to orchestrate your
transitions. So instead of using a bunch
of classes, we can just go here and we
can say data status
status
and we can say open. And now if you have
more of these styles, of course, now
it's way easier. You can do whatever you
All right, let's talk about soil
reactivity. In the context of JavaScript
frameworks, application state refers to
values that are essential to your
application working and cause the
framework to update the UI when changed.
All right, so let's look at a counter
example. I'm going to create a script
tag. Let's say count equals zero. Then
I'm going to create a button. We can use
an expression inside. Let's add an
onclick event handler.
And we can say count equals count + one.
But of course this isn't reactive. And
we even get a warning from swelt. Count
is updated but is not declared with
state. And we can see it ourselves that
count is not going to reactively update.
To create a reactive piece of state in
swelt, we use the dollar sign state
rune. So we can see it looks like this.
State we can say zero. Now it no longer
complains. If you look at our example,
we can increment the count. And this
might look like a function, but it's
just part of the language. So, Selt is
actually going to turn this rune into a
signal under the hood. And because this
looks like a regular function, if you're
using something like TypeScript, you can
just pass your type in here and it's
going to work.
As you can see here, we reactively
update this value by using assignments.
So, we can reassign count by saying
count + one. Of course, you can be much
simpler about this. So you can say count
plus equals 1 or you can just say count
++. We can save this and we're going to
see that it's going to be reactive.
We can also have deeply reactive state.
And what do we mean by that? Well, let's
say for example that you're working on
something like an editor. So we can say
editor state. And now if you pass an
array or object inside of editor, it's
going to become a deeply reactive state
proxy. So what does that mean? But that
means if you for example change
something like editor content, it's
going to reactively update. Same is true
if the editor is an array. So we can say
editor push one and it's going to
reactively update. And that is really
cool. So here we can create a theme.
We can say dark by default. Let's add
And now we can render the content. So
you can use curly boys HTML editor
content and this works as you might expect.
expect.
All right, but let's actually change the
content by using a text area. I'm going
to remove this.
Let's say class is going to be editor.
And now we can say value equals
editor content.
And now we want to update. So we can use
on input. we get access to the event and
now we can say editor content equals e
target value and we can also disable
All right, so let's save this and now we
can see it works. Okay, but something
like an editor might become quickly
complex and maybe you don't want to
reactively update the entire editor
object when a property changes. In that
case, you can use the state raw rune.
And now when you save it, you're going
to see it's not going to reactively
update. The only time it's going to
reactively update is when you reassign
the entire object or array if you're
using that. So for example, here we can
take this.
Let's just like this. So this isn't
going to work.
It's only going to work if you reassign
the object. So we can say reassignment.
And then let's say editor equals.
We can spread all of the old values and
we can say content e target value. Let's
save this and we're going to see now
it's going to work. All right, but I
want to show you another useful state
room. So let's actually undo this and
make it just state. So we can log editor
and we can see that this is a proxy. So
if we open the developer tools, we can
see the proxy object is here. And this
is a bit awkward because we have this
target and we have to dig our way
through this content. But this might be
even worse if you pass this to some API
that doesn't expect a proxy. So let's
say for example that you want to save
and now we can define const editor state
and maybe we want to clone the object.
So we can use structure clone and we can
pass the editor. But now if we try to
save the editor so you can say save
editor state.
So now we get this error that it failed
to execute the structure clone because
it expects a regular object and we
passed a proxy. To fix this problem, we
can use the state.napshot rule. So we
just have to go here. We can just say
state snapshot and then we can pass our
editor. And this is going to give us the
actual value. So we can even console log
editor state. Let's save it. Now if you
refresh it, we're going to see that we
just get a regular object. And what's
also interesting is that swell does this
under the hood. So let me just delete
this and previously we said console log editor.
editor.
Now you can see that actually swell
detected that you're using console log.
So it actually did state.napshot for
you. So you get the actual value and
that's really cool.
And the last thing I want to show you is
that you can actually destructure the
value from this deeply reactive proxy.
So we can go here and we can use curly
boys. We can pluck theme and content.
Yoink. Now we can remove all the
Great. We can remove this. And of course
we can delete this code. And this works
right now. All right. So we can save and
Awesome. But it's not going to work if
you try to dstructure these values where
they weren't defined. So for example,
let's keep this. But we're going to name
it editor. And if you for example go
here and say let and we structure these
values from editor, this isn't going to work.
But if you want to do this, you can use
the derived rune which we're going to
learn about next. We're going to see is
going to be reactive.
All right, let's talk about derived
state. So I'm going to create this count
here. Let's initialize it as zero. We're
going to have a multiplication factor.
And then let's also create the result
which is going to be the outcome of
And we can already see that swell gives
us a warning. This reference only
captures the initial value of count.
Reference it inside a derived instead.
And this is where the derived rune comes
in. So this has different names
depending on the framework you're using.
Some frameworks call this computed
values. Some frameworks call this
derived values. In case of state to
derive the value we can just use the
derived rule and that's it. Now each
time count or factor changes result is
going to update. So let's actually do
that. Let's create a container.
Now inside of here we can say count
times factor
is going to be equal to the result. And
let's also create the buttons so we can
We can say count plus+. We can do the
All right. And now we can save this. So
now we can go to the example and we can
And that's how simple it is to create
derived values.
There's one important thing to know
about derives and that they're lazy
evaluated. And what do I mean by that?
Well, let's actually just first delete
all of this code. So we can just keep
And that's it. So let's say you have
some value max which is a derived. So we
can say derived and we can say count is
greater than or equal to four. And we
can go here and add a disabled
what's really important to know is that
the right values only run when they're
read like in this example where we pass
max to disabled and they only update
when they change and not when their
dependency change to avoid unnecessary
work. So in this example here where we
have this derived max value even though
it depends on count max isn't going to
update when count changes is going to
update if it changes due to count
changing. So we can actually see this by
using the inspect rule which is a really
useful way to log when a reactive value
changes. So you can say inspect max and
this is only going to log when max
changes. So when we go 1 2 3 4, we
should not see max being logged. So
let's save this. Let's go to our
example, open the developer tools,
you're going to see first we get init
false and we're going to see 1 2 3 4.
Nothing happens until we reach the
number four. Only then is the derived
value going to update.
What's actually cool about signals is
that they only have to be read to become
a dependency. So let me show you what
this means. I'm going to delete this and
let's simplify this expression. Under
the hood, actually turns this derive
into a function. And count is actually
something like this. Count get greater
than four. But the cool part is that we
can just create a function with some
state inside of it and it's going to be
reactive. So let me actually show you.
Let's create a function limit and then
let's say we're passing count and we can
say return count greater than four. But
this actually doesn't work how you might
expect. So for example, if we say here
limit and we pass count, count is going
to be get count. So this function is
going to be tracked inside of this
derived. This is what's actually going
to rerun when count updates and max
updates. Count is not some magic
reactive container. And I can prove this
to you by showing you that passing count
is completely optional. So we can
actually remove count.
And now inside of our function I can
just take this remove count. And now
this is going to be get count. As long
as the signal is red is going to become
a dependency. So this limit function is
going to rerun when max changes. If you
just pass count to limit here, it
doesn't mean anything because it's just
a regular value. The only thing that
matters is that count is red. So if you
want to be explicit, you can pass it as
an argument, but you don't have to.
All right, but what if you have
something more complex? So for example,
let's create a card here. We're going to
say state, and we're going to pass an
array of items. So we can say item,
and let's pick a juicy apple. And let's
say the total is 10.
Now let's pick a banana.
Now let's say that we want to derive the
total sum. We can use the derived rune.
So we can say total derived. But how can
we actually do this? We can only pass an
expression inside of here. You could
actually use an array method like reduce
or map. But let's say that you just want
to loop over the items and return a sum.
In that case, we can use derived by and
we can just pass a function inside of here.
And now we can say let sum equals zero.
And now we can loop over the items and
and let's return the sum.
That's it. So now in the template we can
and as you can see it works as expected.
The only thing you shouldn't do is use
the drives for side effects and swelt
isn't even going to let you change state
inside of them to save you from
yourself. So for example, if I want to
push something to the cart here. So let
me actually just copy over this apple
and let's see what happens. And now we
should get an error in our console. It
says updating state inside arrived or a
template expression is forbidden and
swelt even tells you that if the value
should not be reactive you should
declare it without state but I think
some use cases are fine like for example
let's say that you want to fetch some
data inside of derived you're actually
not doing any side effects so if you
wanted you could do something like that
since everything is contained inside of
that function
all right so to finish the holy trinity
of reactivity in swelt let's talk about
the effect rune eventually you're going
to have to do some side effects like
fetching data from an API or
manipulating the DOM directly. In that
case, you want to use an effect.
We can say count++. All right. So, to
create an effect, we just use the dollar
And really effects are just functions
that run when their dependencies change
or when the component is removed from
the DOM. Any state that is read inside
of an effect is going to be tracked. So
we can say console log count and now
count is going to be tracked. As you can
see there is no dependency array.
Now we can open the developer tools and
when we increment count we're going to
One important thing to keep in mind is
because how of signals work values are
only tracked when they're read. What
does this mean? Well, let's say for
example that we have a condition here
and let's say this is false. So we can
copy over this button
and we can say toggle.
So now we can say condition equals the
opposite of condition. And let's also
add a container here.
So now inside of the effect if we use a
conditional block like an if. So if we
say if condition
and then we log the value of count in
this case since condition is false only
condition is going to be tracked since
it's red and not the count.
So going back to the example if we
increment the value of count
you're going to see it's not going to be
logged as expected but also your effect
isn't going to rerun. But of course, if
we change the condition from false to
In this example, if condition is false,
then the only value that's going to be
tracked is condition. And if condition
is true, then both condition and count
are going to be read and tracked inside
of the effect.
That being said, there's an exception to
the rule what gets tracked. If a value
is read a synchronously, like inside a
promise or a timer inside of an effect,
it's not going to be tracked. So, let's
look at an interval example.
Let's say count the same as before.
And let's copy this over. This is going
to be our delay.
And this is going to be 1 second or
1,000 milliseconds. So now in the
template, let's create a div. We can say
count. And let's create the buttons to
control the interval speed.
So this is going to slow down the
So we can say delay times equals 2. All
right. So let's copy the button.
So to make it faster, we can just divide
So now we can pass a call back to the
interval and we can say count plus+. So
we want count to be incremented every
second. So you can also pass a delay. So
in this case because we're reading this
value in an asynchronous function like
set interval. It's not going to be
tracked. But what is going to be tracked
is going to be the delay. So let's go to
our example. And you can see it works as
expected. Well kind of. Let's try to
make the interval faster.
And that works. Okay. So, let's make it slower.
slower.
Uh, but that just makes it go faster.
And of course, that is because this
effect runs each time delay updates and
it creates new intervals. Thankfully, we
can return a cleanup function from the
effect. So, we can say return
and we can say clear interval and we can
pass our interval and this function is
going to run each time its dependencies
change or when the component is removed
from the DOM. So now we can go back to
our example. We can see it works as
expected. So let's speed it up.
All right. So let's see if we can slow
it down. As you can see, it works as expected.
If you don't want to track a value
inside of an effect, then you can use
the unttrack function from SW. So let's
look at an example. So let's create two
pieces of state A and B.
Let's copy it over.
Then let's create the button to
And we can copy this over. Let's say B.
All right. So now we can create the effect.
Let's say that we want to log the sum of
All right. So now if you look at the
example, if we increment the value of
And if we increment the value of B, it's
also going to log the sum.
But what if we don't want to track A? We
only want to log the sum when B updates.
In that case, we can use the unttrack
function from swelt.
Let's start typing a track. And if you
press enter, it should autoimp import
for you. The unttrack function accepts a
call back. So we can just pass it a call
back. And then we can pass the piece of
state that we don't want to track. And
that's it. Now a isn't going to be
tracked. So now if you go back to our
example, if we increment the value of
count, of course, it's going to update
in the background, but it's not going to
log the sum.
But if we increment B, then it's going
All right, let's talk more about
dependency tracking inside of an FX. So
let's say for example that you have an
object and array. So we can create an
object state.
Let's pass current and then let's say we
have an array
and this is just going to be an empty
array. So now we're going to have a
So inside of here, we're just going to
say object current++
and array push one. All right. So let's
Now if we say console log object and
let's also copy this effect.
So we can say array. You're probably
expecting that this is now going to
track the object and array, but that's
really not the case. So, we can see if
we update these values, nothing is going
to happen. And that is because the
effect is only going to rerun when the
object changes and not its properties.
So, we have to be more explicit. We have
to say that we want to track object
current. And in the case of arrays, this
isn't going to be enough. We have to
track array length. Now, the FX should run.
run.
As you can see, it works as expected.
But of course, we can get around this.
Let's say, for example, that we want to
store this object value inside of local storage.
And we say JSON stringify
object, then we actually don't have to
track object.curren for it to be
tracked. The entire object is going to
be tracked. And this is a pretty cool
hack if you want to react to this object
changing. So for example, you don't even
have to use JSON stringify directly. You
can just use it to track this dependency
and then you can do something else when
this object deeply changes. But of
course, if you only want to track
reactive values updating, then you
should use the dollar sign inspect rune.
So now we can just say object array and
it should work. And you can also
customize what happens when you inspect
a value. So you can say width and then
you get the values. But of course you
can also do other things like run
console trace and etc. You can do inside
of here whatever you want.
In general, effects are something that
you're rarely going to use, but you
should especially avoid using effects to
synchronize state. So, let's look at an example.
example.
So, let's create count
and then let's create double.
Next, we're going to create a button.
Let's add one click.
So let's update double when count changes.
changes.
Unless you have to, you should
absolutely avoid using effects to
synchronize state like this because you
might run into unexpected results like
your state being out of sync. So let me
actually show you this in practice here
where we increment count. Let's say that
we depend on double updating.
So we can console log
count and double. And now in our example
when we increment count you're going to
see the value of double is going to be
And that is because effects run last. To
be more precise, Swelt cues your effects
and runs them on the next microtask
before the DOM updates. So, we can
actually test this claim. So, let's go
here and we can say console log. We're
going to say script. Let's copy the
console log.
And then we can say on click.
So now in the example when I increment
the value you're going to see that on
click runs before the effect that is why
double is not updated. So we can see the
first thing that ran was the script
block then the effect when the component
was added to the DOM then we pressed on
click to increment count and then the
effect ran after it to update double.
The lesson here is that you should
always derive state instead. So we can
just remove this effect. We don't need
this. And instead of state here, we can
just use derived. And we can say count
times 2. And now everything should work
Another reason why you might not need
effects is because of the onmount life
cycle function. So let's say that you
want to run something once and then run
a cleanup function when the component is
removed from the DOM. In that case you
can use the onmount life cycle function.
So we can say onmount and then we can
import it from self and we can just pass
a call back to it. So now we can say
console log
and we can also return a cleanup
And we can say component removed. And
this is also great because you don't
have to worry about tracking some state
inside of an effect on accident. You can
also use the on destroy life cycle
function from swelt to run a cleanup
when the component is removed from the DOM.
So we can import on destroy from swelt.
And then inside of here you can run
whatever cleanup you want. Also keep in
mind that you can put this life cycle
functions in other functions. So you can
import them in your component. They
don't have to be declared at the top
level of the script block.
All right. So when should you use
effects? Effect should only be used as a
last resort when you need to synchronize
with some external system that doesn't
understand swell's reactivity. For
example, fetching data from an API or
working with the DOM directly. All
right. So to show this, we can create a
simple Pokémon search.
All right. So, let's create the search
query which is going to be Pokemon.
Let's say it should be Charizard by
default. And then we're going to get the
And then let's create the input.
So, this is going to be of type search.
Let's make this more readable.
And let's say placeholder should be enter
enter
Pokemon name. And then on input we're
going to update the search query. So we
get access to the event and then we can
say Pokemon
equals E target value. Now we just need
to add the image.
So the source is going to be image and
And that's it. And now for convenience,
I'm going to copy paste this get Pokemon
function. So this is just using fetch
and the Pokémon API to get the Pokémon.
But now this makes sense to use an
effect because this is a side effect. We
want to rerun this function each time
Pokemon updates. So we can create an effect
effect
and we can just pass a function inside
of here. One common mistake I see people
do is pass a promise here. So for
example, if you say async, Selt is also
going to give you a warning because
these types don't match. So for example,
if inside of an effect you were to say
cones data await get Pokémon, this would
actually work. But the problem is that
since you're passing a promise, your
cleanup function is never going to run.
So instead of passing a promise here,
you can reassign state inside of this
function get Pokemon and then you can
just say get Pokemon and that's it. Or
you can use an immediately invoked
function expression. So you just need
two round boys. Here is our logic. Then
we can invoke the function inside. And
you just need to pass a function inside.
And now you can make this async. But of
course this isn't readable. In this
example, we're just going to do get Pokémon.
Pokémon.
Pass the Pokémon. Then we can say then,
and we get the data.
And now we can update the image.
So we can say image equals data sprites
prompt default. So let's be more
responsible and not spam the Pokémon
API. So one of the options that fetch
accepts is an abort signal that's going
to cancel the request. So we can pass it
as an option here. So you can say signal
and swelt provides a useful function get
abort signal which is going to cancel
the request as we type. So we can say
get abort signal is going to be
important from swelt. We can just invoke
it and that's it. So now in our example
we can see that we already fetch
Charizard. So we can try fetching Pikachu.
Pikachu.
So you can see it works as expected.
All right friends, one last thing I want
to talk about when it comes to effects
is the effect. Pre-rune. So for example,
you might need to do something before
the dome updates like measuring some
elements or the scroll position. In that
case, you can use the effect pre-rune.
For the sake of time, I'm going to copy
and paste this example here.
So, here we're using the gap animation
library and the flip plugin. So, we just
register the plugin and then we're going
to create 10 elements and then we're
just going to shuffle them. So, in the
markup, we're just looping over these
elements. Nothing special. And then
we're going to shuffle them.
In this example, I want to use the gap
flip plugin to animate the view changes
when we update state. So instead of
these numbers teleporting around, I want
them to smoothly animate their change in
position. For that to happen, we have to
record the previous and after state. So
All right. So whenever we shuffle the
items, we want to run this effect. So
let's add items as a dependency. For
this, we can just say items. All right.
Now we need to measure the elements
before the DOM updates. So we can say
const state equals flip
get state and then we can give it the
class of the item.
So this is going to be dot item. All
right. So now we can transition the
elements. So we can say flip rom. We can
pass it a state with some animation
options. We can say duration 1 second stagger
stagger
0.01 second. And then we can specify an easing.
easing.
So we can say power one in out. But as
you can see this isn't going to work. If
we save this for example and go back
here we can shuffle the item but nothing
is working. And that is because this
effect runs too late. We need to measure
these elements before the dome updates
and then we need to run flip after that
fact. So we can measure the elements
again and do the flip. So to do this we
can use the effect pre- rune. So, we can
just go here and say effect pre. And now
we can save this. But you're going to
see this still isn't going to work. So,
if we shuffle, nothing happens. And that
is because this all happens at once. We
need to measure the dome before it
updates. And then we need to measure it
again after it updates. So, we need to
somehow schedule this function. So,
there's a couple of ways that we can do
this. We can use request animation frame
or Q microtask. So for example, if I go
here and say Q micro test
and this is actually what Selt uses
under the hood to cue your FX but in
this case we can use this to schedule
this task to run. Now you can see when
and SWEL actually provides a function
that does this for you and uses Q
microtask under the hood. So let me just
remove this and we can import tick from
Selt. So now tick is imported from Selt
and tick returns a promise. So we can
invoke it and we can say then
How cool is that? All right, so keep
this in mind if you ever need to do
something before the DOM updates.
So far we only use state at the top
level of the component. But we can use
state inside the functions and classes
including derives and effects. So let's
look at an example. Let's create a
function named create counter which
accepts a initial value. So let's create
some state inside of it. So we can say
count equals state and let's pass the
initial value and let's return count.
But this isn't going to work. So if you
go to the example and try incrementing
count, nothing is going to happen. And
that is because count here is just a
regular value. So when we define a piece
of state with the state rune, this isn't
some magic reactive container. The value
of count is going to be the same value
as when it was evaluated. Sville doesn't
change how JavaScript works. So we
actually need some mechanism to always
get the latest value of count. So for
example, we can use functions. So we can
say count and then we can return the
latest value of count. To update count,
we can say set count. we can get the
value and then we can say count equals
value. But the downside of using
functions is that it's very verbose. So
for example, now we have to use
functions everywhere. We have to invoke
count here. It's not simple anymore. We
have to say counter set count. Now you
have to say counter count have to invoke
this and then we can increment it. All
right. So let's save everything. Now we
can try incrementing the count.
As you can see, it works as expected.
All right. But there is actually a
better way. Instead of using functions,
we can use getters and setters to create
property accessorers. Instead of this
count function, we can just say get
count. And instead of set count, we can
say set count. And that's it. So now
instead of doing all of this,
we can remove this. We can say counter
count plus. and we don't have to invoke
this anymore. So, let's save this and
let's try incrementing the count.
As you can see, using accessors is a way
cleaner syntax. All right, but even this
approach isn't perfect. And speaking of
magic reactive containers, we can use
deeply reactive state. So here, instead
of initial, we can pass in an object. So
this becomes a deeply reactive proxy. So
now we can say count and we can pass
initial. Now let's rename count to
counter. And instead of returning this
junk, we can just return counter.
So let's try incrementing the count.
As you can see, it works as expected.
All right. But if you want, you can
create your own reactive container. And
another reason you might want to do that
is because of type safety. So let's say
for example that you're using TypeScript.
TypeScript.
So let's create a reactive container. So
you can say function reactive but you
can name this whatever you want. Let's
say value and then let's create state.
So we can say state equals state and now
we can pass the value. So this can be
regular or deep state.
Let's return the state and that's it. So
now you can actually type this function.
So we can say t or the generic and you
can do whatever you want here.
So now we can just replace dollar sign
state with reactive and everything is
All right, so this reactive utility
looks really useful. So why doesn't
swelt ship something like this out of
the box? Well, there are actually two
reasons. The first reason is because
it's only a couple of lines of code as
you can see. But another reason is that
swelt encourages you to use classes.
Because when you use state inside of
classes, it unlocks some superpowers.
So, let me actually remove this
and let's yink all of this. So, we can
create a class named counter. We're
going to create a constructor
same as the function is going to accept
an initial value. And the only thing
that we have to do is create this count
field. And we can say equals state and
pass initial. So let's create the counter
counter
new counter. Let's pass the initial
value. All right. So let's try
incrementing the count.
As you can see, it works as expected. So
what kind of black magic is going on
here? Well, let's actually look at the
compiled code. As you can see under the
hood, Swelt is going to turn this into a
private field and is going to create the
getters and setters for you. Of course,
at the end of the day, it doesn't matter
if you use functions or classes as long
as you understand how swelt reactivity
works. All right, so let me show you
another cool thing. Swelt has this
concept of universal reactivity. That
means that not only can we use state
inside of functions and classes, we can
also use it in a regular JavaScript
module. So let's do that. I'm going to
open the sidebar and inside of the
source folder, I'm going to say new
file. Let's create a lip folder and then
we're going to create the counter. So
you can say counter and the only caveat
is that the file name has to end with swelt.js
swelt.js
or ts for TypeScript. So this way the
swell compiler knows that this is a
special file and it doesn't have to do
unnecessary work.
All right. So let's create the file.
So I'm going to close the sidebar and
let's just copy the code. So we can take
our beautiful counter.
Let's go back to counter.swwelljs.
We can paste the code in and we just
need to export it.
Now in app.swelt Well, we can just start
typing counter and it should autoimp import from lib. All right. So now we
import from lib. All right. So now we have our beautiful counter
have our beautiful counter and everything works as expected.
and everything works as expected. All right. So let's talk about something
All right. So let's talk about something very important and that is passing state
very important and that is passing state to functions and classes. So let's say
to functions and classes. So let's say for example that we have a doubler
for example that we have a doubler class. So we can say doubler.
class. So we can say doubler. We can create a constructor.
So we can say this count equals we're going to derive count time two. So
we're going to derive count time two. So let's create count using regular state
let's create count using regular state and then let's create the doubler. So we
and then let's create the doubler. So we can say let doubled new doubler and then
can say let doubled new doubler and then we can pass count. All right trick
we can pass count. All right trick question. Is this going to work? The
question. Is this going to work? The answer is no. And why it is? Well,
answer is no. And why it is? Well, because as we learned before, count is
because as we learned before, count is just a regular value. And we can
just a regular value. And we can actually see this if we create the
actually see this if we create the button.
button. So let's say doubled count. Let's create
So let's say doubled count. Let's create on click.
on click. So we can say count plus+. And we can
So we can say count plus+. And we can look at our example. We can see that
look at our example. We can see that nothing works. So again we have to use
nothing works. So again we have to use some mechanism to get the latest value
some mechanism to get the latest value of count. And usually that is a
of count. And usually that is a function. So instead of just passing the
function. So instead of just passing the plain value of count, we can pass in a
plain value of count, we can pass in a function. So because this is a function,
function. So because this is a function, we need to invoke this. Let's try
we need to invoke this. Let's try incrementing the count. And you're going
incrementing the count. And you're going to see it works as expected. So we
to see it works as expected. So we learned that we can use deep state if we
learned that we can use deep state if we pass an object inside of here for
pass an object inside of here for example or we can use a reactive
example or we can use a reactive utility. But in our case, we already
utility. But in our case, we already created a count class which is already
created a count class which is already reactive. So we can use it. So we can
reactive. So we can use it. So we can just say new
just say new counter. So we can import it from
counter. So we can import it from lib/counter.swelt.
lib/counter.swelt. We can pass in the initial value. And
We can pass in the initial value. And now we can just pass the count
now we can just pass the count and this is actually going to be
and this is actually going to be counter. So we can rename this to
counter. So we can rename this to counter.
counter. Let's say counter dot count. And here we
Let's say counter dot count. And here we just need to change count to counter.
And we can just say counter dot count times two. So we can derive the value.
times two. So we can derive the value. All right. So let's try incrementing the
All right. So let's try incrementing the count.
All right. So now when you increment the count, the doubled value is also going
count, the doubled value is also going to update.
to update. You can also have reactive global state
You can also have reactive global state thanks to swell's universal reactivity.
thanks to swell's universal reactivity. So for example, let's say that you have
So for example, let's say that you have a global config. So we can create a new
a global config. So we can create a new file inside of the lip folder. We can
file inside of the lip folder. We can name it config.swelt.js.
name it config.swelt.js. Let's close the sidebar and we can
Let's close the sidebar and we can export const config equals state and the
export const config equals state and the only thing you have to do is pass in an
only thing you have to do is pass in an object to create a deeply reactive state
object to create a deeply reactive state proxy. So for example we can say theme
proxy. So for example we can say theme and of course it's going to be dark by
and of course it's going to be dark by default and that's all you need to have
default and that's all you need to have reactive global state. Of course you can
reactive global state. Of course you can just use a class. So let's create a
just use a class. So let's create a config class. We don't even need a
config class. We don't even need a constructor. We can just say theme
constructor. We can just say theme equals
equals state
state and let's say dark. I'm also going to
and let's say dark. I'm also going to add a method to toggle the theme. So
add a method to toggle the theme. So let's say toggle theme.
let's say toggle theme. So we're going to say this theme equals
So we're going to say this theme equals let's check what the current theme is.
let's check what the current theme is. So we can say this theme.
So we can say this theme. If it's light then we're going to set it
If it's light then we're going to set it to dark otherwise it should be light.
to dark otherwise it should be light. All right. So now we can create a
All right. So now we can create a singleton. So we can say const config
singleton. So we can say const config equals new config. And of course we
equals new config. And of course we should export it. Now let's go back to
should export it. Now let's go back to app.swelt. Let's create a button. So we
app.swelt. Let's create a button. So we can say config. Let's import it. We can
can say config. Let's import it. We can say config. And now we can also add an
say config. And now we can also add an onclick event handler.
So we can say config toggle theme. All right. So now we can toggle the
All right. So now we can toggle the theme.
theme. And there is only one gotcha with
And there is only one gotcha with classes. So we have to do something like
classes. So we have to do something like this inside of an anonymous function
this inside of an anonymous function because the context of this depends on
because the context of this depends on where it was called. For example, if you
where it was called. For example, if you just pass config.ggle theme, this isn't
just pass config.ggle theme, this isn't going to work
going to work because in this case this refers to the
because in this case this refers to the button. But you can also use an arrow
button. But you can also use an arrow function since it doesn't bind this. So
function since it doesn't bind this. So we can go back to the config. So we can
we can go back to the config. So we can use an arrow function here.
All right, so let's see if it works. Awesome.
All right, friends. So, let me show you how you can avoid using effects. And I
how you can avoid using effects. And I honestly don't want to scare you from
honestly don't want to scare you from using effects. If you sometimes use an
using effects. If you sometimes use an effect when you shouldn't, it's not a
effect when you shouldn't, it's not a big deal. It's not about performance or
big deal. It's not about performance or anything like that. If effects were that
anything like that. If effects were that bad, they wouldn't be part of the
bad, they wouldn't be part of the framework. Effects are necessary. The
framework. Effects are necessary. The problem is that it's easy to over
problem is that it's easy to over complicate your code with effects
complicate your code with effects because it seems like the right thing to
because it seems like the right thing to do. So let's look at an example how you
do. So let's look at an example how you can make your life hell using effects
can make your life hell using effects when you don't even need to use them.
when you don't even need to use them. All right, so let's use the same counter
All right, so let's use the same counter class that we used before.
class that we used before. So we can say let counter equals new
So we can say let counter equals new counter
counter and then let's set zero as the default.
and then let's set zero as the default. All right, let's create a button.
All right. So let's say that you maybe want to read and write to local storage
want to read and write to local storage when you update count. That sounds like
when you update count. That sounds like a side effect, right? So that's a
a side effect, right? So that's a perfect use case for an effect. So let's
perfect use case for an effect. So let's go to counter and inside of this
go to counter and inside of this constructor, I'm going to copy and paste
constructor, I'm going to copy and paste this effects for sake of time. So here
this effects for sake of time. So here we have two effects. one that is going
we have two effects. one that is going to read a value from local storage and
to read a value from local storage and if it exists is going to update count.
if it exists is going to update count. The second effect is going to track when
The second effect is going to track when count updates and is going to update the
count updates and is going to update the value in local storage. So if we go to
value in local storage. So if we go to the example and let's open the developer
the example and let's open the developer tools, we can go here to application and
tools, we can go here to application and local storage. We're going to see that
local storage. We're going to see that the count is zero. So let's try
the count is zero. So let's try incrementing the count.
As you can see, it works as expected. But let's see if the count value
But let's see if the count value persists when we refresh the page. And
persists when we refresh the page. And it does. All right. So, what is the
it does. All right. So, what is the problem? Well, let's go back to our
problem? Well, let's go back to our example. So, let's say that you have a
example. So, let's say that you have a favorite counter that you want to share
favorite counter that you want to share with everyone. So, we can say export
with everyone. So, we can say export cons counter equals new counter.
cons counter equals new counter. So, we can go back to app.2 12 and we
So, we can go back to app.2 12 and we can import the counter. We can remove
can import the counter. We can remove this counter that we created and
this counter that we created and everything should work the same as
everything should work the same as before, right? Well, if we go back to
before, right? Well, if we go back to our example, we can see that we have a
our example, we can see that we have a bunch of errors. So, let's go to the
bunch of errors. So, let's go to the console
console and we get this mysterious effect orphan
and we get this mysterious effect orphan error. Effect can only be used inside of
error. Effect can only be used inside of an effect, for example, during component
an effect, for example, during component initialization. What does this actually
initialization. What does this actually mean? Well, your entire Swelt app is
mean? Well, your entire Swelt app is actually a root effect and your
actually a root effect and your component is just a nested effect inside
component is just a nested effect inside of it. This way, Swell can keep track of
of it. This way, Swell can keep track of the effects and run the cleanup
the effects and run the cleanup automatically for you. So, what this
automatically for you. So, what this error is saying is that you're trying to
error is saying is that you're trying to create an effect outside of that root
create an effect outside of that root effect.
effect. So, let's go back to counter.swell.
So, let's go back to counter.swell. All right. So, this is how you enter the
All right. So, this is how you enter the first circle of hell. We can actually
first circle of hell. We can actually create our own root effect. To do this,
create our own root effect. To do this, SW provides an advanced rune called
SW provides an advanced rune called effect.root.
effect.root. So we can go here at the top. Let's say
So we can go here at the top. Let's say effect.root. And now we can pass a call
effect.root. And now we can pass a call back. So let's move effects inside of
back. So let's move effects inside of the callback.
the callback. The major downside of effect.root is
The major downside of effect.root is that you have to do cleanups manually.
that you have to do cleanups manually. So for example, at the top we can
So for example, at the top we can declare a private field called cleanup
declare a private field called cleanup and then we can assign it here.
All right. Then at some point you're going to have a destroy method
and inside of it we can call the cleanup.
cleanup. As you can see this is starting to
As you can see this is starting to become convoluted. So now let's enter
become convoluted. So now let's enter the second circle of hell. Let's remove
the second circle of hell. Let's remove all of this.
all of this. We no longer need a root effect.
and let's remove this cleanup. All right, so there is another advanced
All right, so there is another advanced rune that we can use and that is the
rune that we can use and that is the effect. Rune. This rune is going to
effect. Rune. This rune is going to check if you're inside of a tracking
check if you're inside of a tracking context like the template. So maybe
context like the template. So maybe that's the solution. All right, let's
that's the solution. All right, let's try it. So we can go here. Let's say if
try it. So we can go here. Let's say if effect tracking
effect tracking and then let's also move effects inside
and then let's also move effects inside of it.
of it. And if we go to our example, we can see
And if we go to our example, we can see we have no errors. So let's go to
we have no errors. So let's go to application
application local storage. We can see count is 10.
local storage. We can see count is 10. That looks good. That's the default
That looks good. That's the default value that we picked. So let's go up to
value that we picked. So let's go up to 20. We can see the count increments, but
20. We can see the count increments, but the value is never updated even if we
the value is never updated even if we refresh the page. And why that is? Well,
refresh the page. And why that is? Well, that is because our effects are never
that is because our effects are never going to run because this counter was
going to run because this counter was created outside of a tracking context.
created outside of a tracking context. All right. So how can we start escaping
All right. So how can we start escaping this hell? Well, it would make more
this hell? Well, it would make more sense that we only create this effect
sense that we only create this effect when we read the value and we can write
when we read the value and we can write to local storage when we write to count.
to local storage when we write to count. So this effect is completely
So this effect is completely unnecessary. So let's start by creating
unnecessary. So let's start by creating a private field count
a private field count and then we can rename count to use the
and then we can rename count to use the private field count. And now we can
private field count. And now we can create the getter and setter.
create the getter and setter. All right. So let's go here and let's
All right. So let's go here and let's say get count
and we can return this count. All right. So we can do the same thing for setting
So we can do the same thing for setting the count.
the count. We get the value and then we can say
We get the value and then we can say this count equals value. So now we can
this count equals value. So now we can yink this local storage line. We can
yink this local storage line. We can just place it here. We don't even need
just place it here. We don't even need this count. We can just say the current
this count. We can just say the current value and then we can yink this effect
value and then we can yink this effect just delete it and we can copy this
just delete it and we can copy this entire effect where we read the count
entire effect where we read the count value
and as you can see things are a lot simpler. All right. So now when we go to
simpler. All right. So now when we go to our example let's increment the count
our example let's increment the count and we should see that everything works
and we should see that everything works as expected. So let's see if the value
as expected. So let's see if the value persists and it does. But there's
persists and it does. But there's actually one problem. If we read this
actually one problem. If we read this count in multiple places, we're going to
count in multiple places, we're going to create an effect. But we can easily fix
create an effect. But we can easily fix this. So we can create a new variable at
this. So we can create a new variable at the top. Let's say first. And this is
the top. Let's say first. And this is going to be true. So now inside of the
going to be true. So now inside of the effect, we can actually check if this
effect, we can actually check if this ran the first time. So we can say, hey,
ran the first time. So we can say, hey, if you already ran, then return.
if you already ran, then return. Otherwise, we're going to retrieve the
Otherwise, we're going to retrieve the value from local storage once. And then
value from local storage once. And then we're going to set first to false.
So now we can increment the value and everything works as expected.
everything works as expected. All right, we've been through many
All right, we've been through many circles of hell, but we're still not
circles of hell, but we're still not done. As you might have noticed, we
done. As you might have noticed, we don't even need an effect here. So we
don't even need an effect here. So we can just remove this effect.
can just remove this effect. And let's say if this is the first time
And let's say if this is the first time this ran
this ran then we can run this
then we can run this and we can set first to false. As you
and we can set first to false. As you can see this is much simpler. So you
can see this is much simpler. So you should always avoid using fx. So now if
should always avoid using fx. So now if you go to our example and if we
you go to our example and if we increment the count we're going to see
increment the count we're going to see that everything works as expected. Let's
that everything works as expected. Let's see if the count value persists.
see if the count value persists. And it does. As you can see, this is why
And it does. As you can see, this is why you should avoid using effects. You can
you should avoid using effects. You can do side effects inside of event handlers
do side effects inside of event handlers like on click. So, always avoid using
like on click. So, always avoid using effects if you can.
effects if you can. All right, friends. So far, I've been
All right, friends. So far, I've been constantly talking about signals, how
constantly talking about signals, how values are being read, and etc. But what
values are being read, and etc. But what does this actually mean? So, in this
does this actually mean? So, in this section, you can get the popcorn out
section, you can get the popcorn out because we're actually going to learn
because we're actually going to learn how signals work. So, let's look at this
how signals work. So, let's look at this example. So far we learned that we can
example. So far we learned that we can declare reactive state using this rune
declare reactive state using this rune and to update state we can use
and to update state we can use reassignment but this equal sign isn't
reassignment but this equal sign isn't anything special. If we look at the
anything special. If we look at the compiled code we're going to see that
compiled code we're going to see that this just gets turned into a function
this just gets turned into a function call. So this gets turned into set. So
call. So this gets turned into set. So we pass the signal and we pass the new
we pass the signal and we pass the new value. But how does this actually get
value. But how does this actually get updated? And this is a true Scooby-Doo
updated? And this is a true Scooby-Doo moment because you're usually
moment because you're usually discouraged from using effects in swel
discouraged from using effects in swel but actually under the hood swelt
but actually under the hood swelt compiles this template into effects. So
compiles this template into effects. So you can see here is a template effect
you can see here is a template effect and that is how swelt updates the dom.
and that is how swelt updates the dom. So in this section I actually want to
So in this section I actually want to implement a simple version of signals so
implement a simple version of signals so you understand how they work and swelt
you understand how they work and swelt isn't the only framework that uses
isn't the only framework that uses signals. You have angular solid quick
signals. You have angular solid quick and so on. You're going to see that
and so on. You're going to see that signals aren't just hype, but they're
signals aren't just hype, but they're the perfect primitive for building user
the perfect primitive for building user interfaces.
All right, friends, let's pretend that this is just regular JavaScript.
this is just regular JavaScript. So, what is a signal? A signal is
So, what is a signal? A signal is basically a container that holds a value
basically a container that holds a value and subscribers. So, we can create
and subscribers. So, we can create function called state. Let's pass in a
function called state. Let's pass in a value and let's create a signal which is
value and let's create a signal which is going to hold the value and subscribers.
going to hold the value and subscribers. So we're going to use a set. So the
So we're going to use a set. So the subscribers are unique and then let's
subscribers are unique and then let's return the signal. As you can see, a
return the signal. As you can see, a signal doesn't do anything on its own.
signal doesn't do anything on its own. For signals to be actually useful, we
For signals to be actually useful, we need effects. So let's create an effect.
need effects. So let's create an effect. So effects accept callback functions. So
So effects accept callback functions. So we can accept the function. And now we
we can accept the function. And now we need to track the active effect. So
need to track the active effect. So we're going to say active effect equals
we're going to say active effect equals this function.
this function. And then we're going to invoke the
And then we're going to invoke the effect. So let's create this active
effect. So let's create this active effect.
All right. So the actual magic happens when we invoke the effect and we read a
when we invoke the effect and we read a signal. So let's create a function
signal. So let's create a function called get. So we're just going to pass
called get. So we're just going to pass a signal.
a signal. So now inside of get we can check, hey,
So now inside of get we can check, hey, who called me? Then we can say signal
who called me? Then we can say signal subscribers add the active effect and
subscribers add the active effect and then we can return the value. So you can
then we can return the value. So you can say signal do value. All right. So now
say signal do value. All right. So now when we update the signal we notify it
when we update the signal we notify it subscribers.
subscribers. So we can say function set we're going
So we can say function set we're going to pass in the signal and a new value.
to pass in the signal and a new value. So we're going to say signal value
So we're going to say signal value equals the new value. And now we can
equals the new value. And now we can notify the subscribers that the value
notify the subscribers that the value has changed. So we can say signal
has changed. So we can say signal subscribers
subscribers for each
for each effect. We can invoke the effect.
effect. We can invoke the effect. And that's pretty much it. And that's
And that's pretty much it. And that's really how simple a basic signals
really how simple a basic signals implementation is. So let's actually use
implementation is. So let's actually use it. In this case, since we're not using
it. In this case, since we're not using swelt in particular, we're just going to
swelt in particular, we're just going to create a button. But of course since
create a button. But of course since we're still in SWEL I'm going to use
we're still in SWEL I'm going to use onmount to query the element
and then we can create the state. So we can say let count equals
can say let count equals state. Let's pass the initial value. Now
state. Let's pass the initial value. Now let's query the button.
All right. So let's update the count by saying button on click.
saying button on click. So we can use our set function which
So we can use our set function which accepts a signal. So we can pass count
accepts a signal. So we can pass count and we need to use get to get the latest
and we need to use get to get the latest value from the signal and we can
value from the signal and we can increment it and that's cool. But the
increment it and that's cool. But the actual magic happens is when you use an
actual magic happens is when you use an effect.
effect. So again we're going to pass a call back
So again we're going to pass a call back to this effect. So we want to update the
to this effect. So we want to update the button text node. So we can say button
button text node. So we can say button text content. we can say equals and we
text content. we can say equals and we have to say get count. So when we read
have to say get count. So when we read the signal, it's going to rerun this
the signal, it's going to rerun this effect. All right? So I hope you're
effect. All right? So I hope you're starting to understand how cool this is
starting to understand how cool this is because when this effect runs, this
because when this effect runs, this callback is going to run. This is going
callback is going to run. This is going to become the active effect. Then we're
to become the active effect. Then we're going to read the signal. And when we
going to read the signal. And when we read the signal, it's going to ask
read the signal, it's going to ask itself, hey, who called me? Is there an
itself, hey, who called me? Is there an active effect? If so, let's add it to
active effect? If so, let's add it to our subscribers. And then when we update
our subscribers. And then when we update the signal, we can notify the
the signal, we can notify the subscribers. Of course, this is very
subscribers. Of course, this is very oversimplified, but this is a basic
oversimplified, but this is a basic example of how signals work. All right,
example of how signals work. All right, but let's actually see if this works at
but let's actually see if this works at all. So, we can save this. So, let's go
all. So, we can save this. So, let's go to our example and let's see if we can
to our example and let's see if we can increment count.
increment count. How beautiful is this, Rens? All right.
How beautiful is this, Rens? All right. So, not only did we learn how signals
So, not only did we learn how signals work, but we also learned that doesn't
work, but we also learned that doesn't compile reactivity. This is what it's
compile reactivity. This is what it's called runtime reactivity because this
called runtime reactivity because this happens each time you update a value. It
happens each time you update a value. It runs the signals and recreates the
runs the signals and recreates the dependency graph. The only thing that
dependency graph. The only thing that swell compiles for is developer
swell compiles for is developer experience because it hides this method
experience because it hides this method set get and etc. And that is the reason
set get and etc. And that is the reason why you can use signals like regular
why you can use signals like regular values in swelt. As the react people
values in swelt. As the react people love to say it's just JavaScript.
love to say it's just JavaScript. All right, friends. So, I hope you
All right, friends. So, I hope you understand now why signals are so
understand now why signals are so powerful. Instead of having to do all
powerful. Instead of having to do all the manual setup to update values,
the manual setup to update values, anyone that is interested about a value
anyone that is interested about a value updating can just subscribe to the
updating can just subscribe to the signal. Once you understand how signals
signal. Once you understand how signals work, you're going to understand them in
work, you're going to understand them in other frameworks. And there's even a
other frameworks. And there's even a proposal to add signals to JavaScript.
proposal to add signals to JavaScript. And now that you understand how
And now that you understand how dependency tracking works in Swelt is
dependency tracking works in Swelt is going to give you more confidence in
going to give you more confidence in your own projects. And now you also
your own projects. And now you also understand that this isn't some magic
understand that this isn't some magic under the hood where swell compiles
under the hood where swell compiles reactivity. It's just JavaScript. And
reactivity. It's just JavaScript. And this is also important when you read in
this is also important when you read in the docs. So for example, here they
the docs. So for example, here they mention something that's called the
mention something that's called the tracking context. And they say that's
tracking context. And they say that's the effect. So your user effects and
the effect. So your user effects and things inside your template. But what
things inside your template. But what they don't explain here is that your
they don't explain here is that your templates get compiled to effects. So
templates get compiled to effects. So that is the tracking context. And
that is the tracking context. And speaking of effects, the ride values are
speaking of effects, the ride values are also effects. A derived value has its
also effects. A derived value has its own tracking context and it returns a
own tracking context and it returns a signal. Unlike user effects, when a
signal. Unlike user effects, when a derived updates, it gets immediately
derived updates, it gets immediately evaluated. All right, so I hope this was
evaluated. All right, so I hope this was helpful. All right, so let's talk about
helpful. All right, so let's talk about using logic in your template. HTML
using logic in your template. HTML doesn't have conditionals and loops, but
doesn't have conditionals and loops, but in Swelt, we can use control flow blocks
in Swelt, we can use control flow blocks and even blocks to deal with data
and even blocks to deal with data loading and promises. So let's look at
loading and promises. So let's look at an example how we can conditionally
an example how we can conditionally render content in Swelt.
render content in Swelt. I'm going to create a piece of state
I'm going to create a piece of state called status
called status and this is by default going to be
and this is by default going to be loading. So this state can be loading
loading. So this state can be loading success or error. Now inside of our
success or error. Now inside of our template we can start by opening the
template we can start by opening the curly voice. We can say pound if and now
curly voice. We can say pound if and now here we can use an expression. So we can
here we can use an expression. So we can say status
say status does it equal to loading.
does it equal to loading. So we can use a paragraph tag and we can
So we can use a paragraph tag and we can say loading. All right. So let's close
say loading. All right. So let's close the if block again. We're going to use
the if block again. We're going to use the curly boys slash if let's take care
the curly boys slash if let's take care of other state such as success and
of other state such as success and error. So we can go here and we can add
error. So we can go here and we can add another block. So we can use curly boys
another block. So we can use curly boys again. We can say colon else if and now
again. We can say colon else if and now we can use another expression. We can
we can use another expression. We can say if status is equal to success. Let's
say if status is equal to success. Let's also use a paragraph. Then we can say
also use a paragraph. Then we can say success. All right. So let's copy this
success. All right. So let's copy this block over. So we're going to say if
block over. So we're going to say if status is error, then we're going to say
status is error, then we're going to say error.
error. We can also add another else block. So
We can also add another else block. So we can say curly boys colon else and we
we can say curly boys colon else and we can say paragraph tag impossible state.
can say paragraph tag impossible state. All right. So let's add some buttons.
Let's say loading. And then we're going to add an on click event handler.
So we can say status equals loading. All right. So let's copy this over a
All right. So let's copy this over a bunch of times.
bunch of times. So we can say success.
All right. So let's go to the example. So let's go from the loading state to
So let's go from the loading state to the success state. And then we can go to
the success state. And then we can go to the error state. And if we go to other,
the error state. And if we go to other, we should see impossible state. And that
we should see impossible state. And that is how we can conditionally render
is how we can conditionally render content in SW.
content in SW. All right. So let's look at how we can
All right. So let's look at how we can loop over data in SW. So let's say that
loop over data in SW. So let's say that you have a list of items such as to-dos.
you have a list of items such as to-dos. We can say state. This is going to be an
We can say state. This is going to be an array of to-dos.
array of to-dos. So let's say ID1
So let's say ID1 the text is going to be to-do
the text is going to be to-do and we can say done false. So let's copy
and we can say done false. So let's copy this over a bunch of times.
this over a bunch of times. So now we can say to-do 2 three or we
So now we can say to-do 2 three or we can also bump the ID
can also bump the ID and that's it. All right. So in the
and that's it. All right. So in the template we're going to create a list.
template we're going to create a list. All right. So let's use the curly boys.
All right. So let's use the curly boys. Then we can say pound each in this case.
Then we can say pound each in this case. So now we can say each to-dos as to-do.
So now we can say each to-dos as to-do. We can also close the each block by
We can also close the each block by using curly boys slash each. Now inside
using curly boys slash each. Now inside the each block, we're going to create a
the each block, we're going to create a list item. Inside of the list item,
list item. Inside of the list item, we're going to have an input and a span.
we're going to have an input and a span. So we can say input type checkbox. And
So we can say input type checkbox. And then we can set the checked value. So we
then we can set the checked value. So we can say checked equals to to-do done.
can say checked equals to to-do done. And then let's add a span for the text.
And then let's add a span for the text. So we can say to-do.ext. text. All
So we can say to-do.ext. text. All right. So, we can add one more thing. If
right. So, we can add one more thing. If the list is empty, so we can go here. We
the list is empty, so we can go here. We can open the curly boys. We can say
can open the curly boys. We can say else.
else. So, if the list is empty, we're going to
So, if the list is empty, we're going to render this paragraph that's going to
render this paragraph that's going to say no items. As you can see, we
say no items. As you can see, we successfully iterated over the items. We
successfully iterated over the items. We can also destructure the values from the
can also destructure the values from the item we're currently iterating over. So
item we're currently iterating over. So instead of to-do here we can use curly
instead of to-do here we can use curly boys and we can the structure ID text
boys and we can the structure ID text and done. We can even get the index here
and done. We can even get the index here and you can name this whatever you want
and you can name this whatever you want like index but I'm just going to say I
like index but I'm just going to say I and then we can also pass a unique key
and then we can also pass a unique key like the ID. So this is as well can keep
like the ID. So this is as well can keep track of changes. So we can use the
track of changes. So we can use the round voice and then we can just pass
round voice and then we can just pass the ID. In this case it's unnecessary
the ID. In this case it's unnecessary but in general it's a good practice to
but in general it's a good practice to provide a unique key so can keep track
provide a unique key so can keep track of changes. All right. So now we have to
of changes. All right. So now we have to remove to-do dot and let's also do
remove to-do dot and let's also do something more fun with the index. So we
something more fun with the index. So we can color odd and even rows. So here we
can color odd and even rows. So here we have our span. We can use the style
have our span. We can use the style attribute and we can say colon color.
attribute and we can say colon color. So we can say I modulo to if there is no
So we can say I modulo to if there is no remainder then we can say that the color
remainder then we can say that the color is going to be orange red otherwise
is going to be orange red otherwise we're going to use the default color.
we're going to use the default color. So now if we go to example you can see
So now if we go to example you can see that every odd row is colored.
that every odd row is colored. All right. So let's say that you want to
All right. So let's say that you want to loop over an arbitrary amount of items
loop over an arbitrary amount of items like creating a grid for example. In
like creating a grid for example. In that case we can even omit the s part in
that case we can even omit the s part in the each block. So let me show you. In
the each block. So let me show you. In this example we're going to create a
this example we're going to create a 10x10 grid. So let's say cells and then
10x10 grid. So let's say cells and then we can start with the curly boys. We can
we can start with the curly boys. We can say each. And now we want to create an
say each. And now we want to create an array of 10 items. So we can just say
array of 10 items. So we can just say array and then we can pass the amount of
array and then we can pass the amount of items that we want to create. So let's
items that we want to create. So let's close the each
close the each and here we don't have to specify as
and here we don't have to specify as anymore. We're only interested in the
anymore. We're only interested in the index. So we can name this index row.
index. So we can name this index row. All right. So now that we created the
All right. So now that we created the rows, we can create the columns. So
rows, we can create the columns. So let's just copy this code here
let's just copy this code here and we can rename row to call. Now let's
and we can rename row to call. Now let's create a div. We're going to name this
create a div. We're going to name this cell and we can just output the row and
cell and we can just output the row and column number. So let's use curly boys.
column number. So let's use curly boys. We can say row
We can say row and then let's say column. As you can
and then let's say column. As you can see we created a 10x10 grid of rows and
see we created a 10x10 grid of rows and columns.
All right. So what's really cool about the each block is that you can iterate
the each block is that you can iterate over any value that supports array from.
over any value that supports array from. So for example, we can create a map.
So for example, we can create a map. Let's say let items map. We can say new
Let's say let items map. We can say new map. Let's pass in some default values.
map. Let's pass in some default values. We can use an array of arrays to do so.
We can use an array of arrays to do so. So we just need to pass a value. Let's
So we just need to pass a value. Let's say apple.
Then let's copy this over. We can say banana.
New set. Let's pass in an array. So again, we're
Let's pass in an array. So again, we're going to have an apple and a banana.
And let's also create a generator. So we can just say function and we can use a
can just say function and we can use a star. So this is a generator. So we can
star. So this is a generator. So we can say items generator. And then we can
say items generator. And then we can just yield the apple and the banana. So
just yield the apple and the banana. So we can say yield.
So we can yield the apple. And then let's seal the banana.
All right. So let's loop over these items. So now in the template, let's
items. So now in the template, let's create a list. All right. So this is how
create a list. All right. So this is how we can loop over the map. We can use
we can loop over the map. We can use curly boys each. We can say items map as
curly boys each. We can say items map as and then we can the structure the key
and then we can the structure the key and the value.
All right. So let's close the each block and then let's just output the key and
and then let's just output the key and the value.
the value. So we can say key colon value. All
So we can say key colon value. All right. So next let's loop over the set
right. So next let's loop over the set which will be the same as looping over a
which will be the same as looping over a regular array. So we can copy this list.
Instead of items map we can say items set
All right. So the last one is going to be the generator. So we can copy over
be the generator. So we can copy over this block
this block and this is also really simple. The only
and this is also really simple. The only thing we have to do is invoke the
thing we have to do is invoke the generator. So we can say items generator
generator. So we can say items generator and that's it. All right. So let's go to
and that's it. All right. So let's go to the example. As you can see we iterated
the example. As you can see we iterated successfully over a map set and even
successfully over a map set and even generators.
generators. Awesome. So keep that in mind. You can
Awesome. So keep that in mind. You can loop over basically anything as long as
loop over basically anything as long as it works with array. Swelt even has
it works with array. Swelt even has reactive versions of some built-in
reactive versions of some built-in JavaScript objects that we're going to
JavaScript objects that we're going to look at later.
look at later. All right, so let me show you a simpler
All right, so let me show you a simpler way of dealing with promises using the
way of dealing with promises using the await block.
await block. So previously we fetched some Pokémon
So previously we fetched some Pokémon data using this get Pokemon function. As
data using this get Pokemon function. As you can see the function is mostly the
you can see the function is mostly the same. The only thing I changed is that I
same. The only thing I changed is that I explicitly returned the name and sprites
explicitly returned the name and sprites from the response. But in that example
from the response. But in that example where we used an effect, we didn't even
where we used an effect, we didn't even account for any loading success or error
account for any loading success or error state which becomes quickly tedious. So
state which becomes quickly tedious. So to make that simpler, we can use the
to make that simpler, we can use the await block in swelt to deal with
await block in swelt to deal with promises like a synchronous data
promises like a synchronous data loading. So let's go to the template and
loading. So let's go to the template and we can use the curly voice, we can use
we can use the curly voice, we can use the pound side and then we can say
the pound side and then we can say await. If you want you can store a
await. If you want you can store a promise in a variable or you can invoke
promise in a variable or you can invoke a function like this directly. So we can
a function like this directly. So we can say get Pokemon
say get Pokemon and then let's say Charizard and then
and then let's say Charizard and then let's close the await block by using
let's close the await block by using curly boys/await.
curly boys/await. All right. So let's show the loading
All right. So let's show the loading state. So we can just say loading but
state. So we can just say loading but then when the promise is resolved we can
then when the promise is resolved we can use the then block.
use the then block. Let's use the curly boys. We can say
Let's use the curly boys. We can say colon then and we can name the return
colon then and we can name the return result. So this is going to be Pokemon.
result. So this is going to be Pokemon. All right. So inside of here, let's
All right. So inside of here, let's create a container named Pokemon
create a container named Pokemon details. And now we can create an image.
details. And now we can create an image. So the source is going to be Pokemon
So the source is going to be Pokemon image and the description is going to be
image and the description is going to be the Pokemon name.
the Pokemon name. And let's also add a paragraph here. So
And let's also add a paragraph here. So we can say Pokemon name. All right. So
we can say Pokemon name. All right. So now we can also handle the error state
now we can also handle the error state by using the catch block. So we can go
by using the catch block. So we can go here and we can again use a curly voice
here and we can again use a curly voice colon
colon catch
catch and we can say error. All right. So now
and we can say error. All right. So now that we get the error we can display the
that we get the error we can display the error message.
error message. So we can say error dot message. All
So we can say error dot message. All right. So let's see if it works. And
right. So let's see if it works. And awesome we got Charizard. All right. So
awesome we got Charizard. All right. So if you don't care about errors you can
if you don't care about errors you can omit the catch block and you can also
omit the catch block and you can also omit the den block if you only care
omit the den block if you only care about the result. So let's just take the
about the result. So let's just take the markup.
markup. We can delete this. We can paste our
We can delete this. We can paste our markup here. And the only thing we have
markup here. And the only thing we have to do is use then here. So we can say
to do is use then here. So we can say then Pokemon.
then Pokemon. And everything works the same as before.
And everything works the same as before. Hey friends, I wanted to let you know
Hey friends, I wanted to let you know that there's an experimental async
that there's an experimental async feature that you can enable in Swelt. By
feature that you can enable in Swelt. By the time you're watching this video, it
the time you're watching this video, it might no longer be experimental. But
might no longer be experimental. But currently, if you enable this
currently, if you enable this experimental flag, you can use a weight
experimental flag, you can use a weight at the top level of your component
at the top level of your component inside state and inside your markup. So
inside state and inside your markup. So the only thing you have to do is enable
the only thing you have to do is enable the async feature in your swel config.
the async feature in your swel config. And then you have to include this
And then you have to include this boundary at the root of your app.
boundary at the root of your app. Basically, this is like react suspense
Basically, this is like react suspense if you're familiar with that. And now
if you're familiar with that. And now you can use await directly in your
you can use await directly in your component. So in this example, we're
component. So in this example, we're adding A and B. As you can see, we can
adding A and B. As you can see, we can use it directly in the markup. And you
use it directly in the markup. And you can find more information in the
can find more information in the documentation like indicating loading
documentation like indicating loading state. So you can use this
state. So you can use this effect.pending rune. But yeah, there's a
effect.pending rune. But yeah, there's a lot more information in the SW
lot more information in the SW documentation.
documentation. All right. Sometimes you might want to
All right. Sometimes you might want to recreate some elements when a piece of
recreate some elements when a piece of state changes. In that case, you can use
state changes. In that case, you can use the key block. So let's look at an
the key block. So let's look at an example.
example. Let's create this value. I'm going to
Let's create this value. I'm going to set it at zero. And then we can create a
set it at zero. And then we can create a cute ghost. I mean a spooky ghost.
cute ghost. I mean a spooky ghost. We're going to learn more about
We're going to learn more about transitions later, but for right now we
transitions later, but for right now we can just say in colon fate. And we can
can just say in colon fate. And we can just import fate from swelt /t
just import fate from swelt /t transition. All right. So now let's
transition. All right. So now let's create a button.
create a button. So now we can create a spook on demand
So now we can create a spook on demand service by adding an on click event
service by adding an on click event handler.
handler. So let's just increment the value. So
So let's just increment the value. So now we want to play the fade transition
now we want to play the fade transition each time value updates. So we can use
each time value updates. So we can use the key block for that. So we can go
the key block for that. So we can go here and we can use the curly boys pound
here and we can use the curly boys pound key. So now we can pass any expression
key. So now we can pass any expression here like value and now we can close the
here like value and now we can close the key block. So let's use the curly boys /
key block. So let's use the curly boys / key and that's it. Now we can save it
key and that's it. Now we can save it and now we have a spook on demand
and now we have a spook on demand service. All right. So now when we click
service. All right. So now when we click on the button it should recreate the
on the button it should recreate the ghost element and play the transition.
Spooky. How spooky is that, friends?
How spooky is that, friends? All right, friends. The last cool thing
All right, friends. The last cool thing I want to show you is local constants.
I want to show you is local constants. Basically, local constants lets you
Basically, local constants lets you define variables in your template. So,
define variables in your template. So, when would it be useful? Let's actually
when would it be useful? Let's actually look at an example. So, let me just copy
look at an example. So, let me just copy this example. So, this is the same
this example. So, this is the same example that we used in the loop section
example that we used in the loop section where we structured ID, done, and text.
where we structured ID, done, and text. But this approach kind of sucks because
But this approach kind of sucks because now we lost the original reference to
now we lost the original reference to the to-do, right? And what if we want to
the to-do, right? And what if we want to use the to-do as a key here? Now we
use the to-do as a key here? Now we can't anymore. We have to pass ID. Well,
can't anymore. We have to pass ID. Well, we can actually fix this with local
we can actually fix this with local constants. To create a local constant,
constants. To create a local constant, it has to be a child of any of the
it has to be a child of any of the blocks like if each and so on. And it
blocks like if each and so on. And it can also be a child of a component. So
can also be a child of a component. So in this case, we can just go here. We
in this case, we can just go here. We can use the curly boys. Then we use the
can use the curly boys. Then we use the at sign and then we can say const. So
at sign and then we can say const. So now we can define a variable that is
now we can define a variable that is scope to this block. But in our example,
scope to this block. But in our example, we just want to structure these values
we just want to structure these values from to-do. So we can just take that and
from to-do. So we can just take that and we can say equals to-do.
we can say equals to-do. Now we can just say to-dos as to-do. And
Now we can just say to-dos as to-do. And now we preserve the original reference
now we preserve the original reference to to-do. So now we can pass that as the
to to-do. So now we can pass that as the unique ID. And we can also rename done
unique ID. And we can also rename done to checked.
to checked. And we're not using ID anywhere. So we
And we're not using ID anywhere. So we can just remove it actually. And we can
can just remove it actually. And we can go here and we can just say checked. And
go here and we can just say checked. And we already the structured text. As you
we already the structured text. As you can see, local constants are very
can see, local constants are very useful.
useful. So let's look at another example that
So let's look at another example that creates an SVG grid.
creates an SVG grid. As you can see, we can define the size
As you can see, we can define the size and tiles in the script block. And now
and tiles in the script block. And now we can pass them to the SVG. So now we
we can pass them to the SVG. So now we can combine what we learned before on
can combine what we learned before on how to create a grid. So in this
how to create a grid. So in this example, we're creating a chessboard.
example, we're creating a chessboard. And now we can use local constants to
And now we can use local constants to keep everything tidy and legible. And
keep everything tidy and legible. And this also helps us avoid creating
this also helps us avoid creating unnecessary components. And it's also a
unnecessary components. And it's also a benefit to performance if we compute the
benefit to performance if we compute the value once if we use it in multiple
value once if we use it in multiple places. But in this case, we're just
places. But in this case, we're just creating the tile X and Y coordinates
creating the tile X and Y coordinates with height and the fill. So we just
with height and the fill. So we just pass them here to W. And now we can look
pass them here to W. And now we can look at the example. As you can see, we're
at the example. As you can see, we're creating this chessport. Local constants
creating this chessport. Local constants are a very useful tool in your arsenal.
are a very useful tool in your arsenal. All right, let's talk about event
All right, let's talk about event listeners in SW. So far, we used a
listeners in SW. So far, we used a button with an on click event listener.
button with an on click event listener. In swelt events are just regular
In swelt events are just regular attributes. So you can say on and the
attributes. So you can say on and the name of the event and you can pass an
name of the event and you can pass an inline function like this
inline function like this and we can say console log click. So if
and we can say console log click. So if we open the developer tools and click on
we open the developer tools and click on the button, we should see click. And
the button, we should see click. And what's really cool about events in swelt
what's really cool about events in swelt is that they mirror JavaScript events.
is that they mirror JavaScript events. So what do I mean by that? Well, you
So what do I mean by that? Well, you might be familiar with something like
might be familiar with something like this. So where we have element add event
this. So where we have element add event listener
listener and now we can pass the event listener
and now we can pass the event listener and we get access to the event. So we
and we get access to the event. So we can do whatever we want. But there's
can do whatever we want. But there's also an alternative syntax where you can
also an alternative syntax where you can say element on click and we also get the
say element on click and we also get the event and we can do whatever we want.
event and we can do whatever we want. And of course we also get access to the
And of course we also get access to the event here. And instead of using an
event here. And instead of using an inline function, we can create a handle
inline function, we can create a handle click function. So let's take this and
click function. So let's take this and we can name this handle click.
we can name this handle click. So let's remove this yoink. Let's name
So let's remove this yoink. Let's name this function handle click.
this function handle click. And we get the event implicitly. So we
And we get the event implicitly. So we don't have to pass it. And then we can
don't have to pass it. And then we can just put our console log here. And now
just put our console log here. And now if we click on the button, we should see
if we click on the button, we should see click again. And also because events are
click again. And also because events are just regular attributes if they have the
just regular attributes if they have the same name then we can use a shortand. So
same name then we can use a shortand. So in this case we can rename handle click
in this case we can rename handle click to on click and if I save and format the
to on click and if I save and format the file is going to use the short hand and
file is going to use the short hand and because events are just regular
because events are just regular attributes we can also spread them. So
attributes we can also spread them. So let's take this console log here and
let's take this console log here and let's create this object called events.
So you can have on click and then let's copy it over. And this is
and then let's copy it over. And this is going to be on double click.
So now when we click on the button, we're going to get click. And if we
we're going to get click. And if we double click the button, we're going to
double click the button, we're going to get double click.
get double click. All right, let's do a more fun example
All right, let's do a more fun example where we track the mouse coordinates
where we track the mouse coordinates using the on mouse move event.
using the on mouse move event. So we need to track the X and Y mouse
So we need to track the X and Y mouse coordinates. So let's create mouse
coordinates. So let's create mouse equals state and then let's pass in an
equals state and then let's pass in an object here. So we can say X is equal to
object here. So we can say X is equal to zero and the Y coordinate is also going
zero and the Y coordinate is also going to be zero. So let's create this
to be zero. So let's create this container. I'm going to use this mouse
container. I'm going to use this mouse class. So this container is going to
class. So this container is going to take the entire width and height and
take the entire width and height and then we can say the mouse position is
then we can say the mouse position is and we can use the coordinates. So we
and we can use the coordinates. So we can say mouse x
can say mouse x and mouse y. All right. So let's create
and mouse y. All right. So let's create the function to track the mouse
the function to track the mouse coordinates.
coordinates. So let's name this on mouse move. Then
So let's name this on mouse move. Then we can accept the event. Now we just
we can accept the event. Now we just need to update the mouse position. So we
need to update the mouse position. So we can say mouse x equals e client x and
can say mouse x equals e client x and let's also update the y-coordinate.
let's also update the y-coordinate. So mouse y equals client y. And that's
So mouse y equals client y. And that's it. Now we just need to add the event
it. Now we just need to add the event handler. So we can just go here and we
handler. So we can just go here and we can use the curly boys and let's just
can use the curly boys and let's just say on mouse move and we're going to get
say on mouse move and we're going to get an accessibility warning, but we can
an accessibility warning, but we can just ignore it by clicking on quick fix
just ignore it by clicking on quick fix and then we can disable it.
and then we can disable it. All right. So let's go to our example.
All right. So let's go to our example. And now we can see that the mouse
And now we can see that the mouse position is being tracked. How cool is
position is being tracked. How cool is this? And that's how simple that was.
this? And that's how simple that was. All right. So in the last example, I
All right. So in the last example, I want to show you that you can actually
want to show you that you can actually use forms to get the user submitted data
use forms to get the user submitted data instead of always using state. So let me
instead of always using state. So let me show you. Let's create a form. It's not
show you. Let's create a form. It's not going to have any action because this is
going to have any action because this is going to be purely client side. When
going to be purely client side. When you're using cell by default, you're
you're using cell by default, you're building client side applications. So
building client side applications. So everything is handled on a single page
everything is handled on a single page using JavaScript. So let's say for
using JavaScript. So let's say for example create an input which is going
example create an input which is going to be email. So to get the data from the
to be email. So to get the data from the form we have to give it an identifier
form we have to give it an identifier such as a name. So we can say email and
such as a name. So we can say email and then let's create a submit button. So we
then let's create a submit button. So we can say type submit.
can say type submit. So for example this might be your
So for example this might be your newsletter. So we can say subscribe. All
newsletter. So we can say subscribe. All right. So usually where you would use
right. So usually where you would use state to get the email we can actually
state to get the email we can actually just create a function and we can listen
just create a function and we can listen to the onsubmit event. So let's say
to the onsubmit event. So let's say function onsubmit. We get the event as
function onsubmit. We get the event as the argument. And now this is the most
the argument. And now this is the most important part. We have to prevent the
important part. We have to prevent the default behavior because the form is
default behavior because the form is trying to post to the server. To avoid
trying to post to the server. To avoid that we can use event prevent default.
that we can use event prevent default. So now we can control the form using
So now we can control the form using JavaScript and avoid a page reload. All
JavaScript and avoid a page reload. All right. To get the form data we can say
right. To get the form data we can say cons data equals new form data and we
cons data equals new form data and we can pass the form. In this case we can
can pass the form. In this case we can just use this to reference the form
just use this to reference the form element. And then we can say con email
element. And then we can say con email equals data get. And this is where our
equals data get. And this is where our unique name identifier comes in. So we
unique name identifier comes in. So we can say email and that's it. So now we
can say email and that's it. So now we can console log the email.
can console log the email. All right. So now we can go to the form
All right. So now we can go to the form and we can use onsubmit.
and we can use onsubmit. All right. So let's enter an email like
All right. So let's enter an email like test.com
test.com and let's open the developer tools. And
and let's open the developer tools. And now we're going to see if we subscribe
now we're going to see if we subscribe is going to output the email. As you can
is going to output the email. As you can see, sometimes a form can be enough and
see, sometimes a form can be enough and you don't need any extra state.
you don't need any extra state. All right, let's talk about data binding
All right, let's talk about data binding in SWEL. So here I have a special
in SWEL. So here I have a special example for you. I'm going to copy and
example for you. I'm going to copy and paste for sake of time, but it's really
paste for sake of time, but it's really just a simple search. Here we have a
just a simple search. Here we have a list of JavaScript frameworks. Here
list of JavaScript frameworks. Here we're using a derive to filter the list
we're using a derive to filter the list based on the search. And this is how we
based on the search. And this is how we update the search using this input. So
update the search using this input. So we assign the value to search and then
we assign the value to search and then we use on input to update the value. And
we use on input to update the value. And here we're just looping over the list.
here we're just looping over the list. Nothing special. All right. So for
Nothing special. All right. So for example, if we type in s now we're going
example, if we type in s now we're going to get solid and swelt. And of course in
to get solid and swelt. And of course in the example I would also make this to
the example I would also make this to lowerase where you have item and search.
lowerase where you have item and search. So it's case insensitive. All right. So
So it's case insensitive. All right. So in previous examples where we used
in previous examples where we used events like on input, there were
events like on input, there were probably some people yelling at the
probably some people yelling at the screen that already know SWelt. What are
screen that already know SWelt. What are you doing? This can be so much simpler.
you doing? This can be so much simpler. And yes, that is true. This is part of
And yes, that is true. This is part of the plan. What we're doing here is
the plan. What we're doing here is called one-way data binding because
called one-way data binding because we're using the input to update some
we're using the input to update some state in our application, but the state
state in our application, but the state in the application doesn't reflect in
in the application doesn't reflect in the input. What's worse is that you do
the input. What's worse is that you do something like this all the time. So,
something like this all the time. So, this is just boilerplate. Thankfully,
this is just boilerplate. Thankfully, Swelt supports two-way data binding
Swelt supports two-way data binding using the bind directive. So let's see
using the bind directive. So let's see how we can use the bind directive to
how we can use the bind directive to improve this experience. All right, so
improve this experience. All right, so let me show you how cool this is. So we
let me show you how cool this is. So we can just delete all of this junk and we
can just delete all of this junk and we just need to say bind colon value and
just need to say bind colon value and what do we want to bind it to? So we can
what do we want to bind it to? So we can say search and that's it. Now we can
say search and that's it. Now we can save. And now if we go to our example,
save. And now if we go to our example, we can see that it works the same as
we can see that it works the same as before.
before. And swell has many writable and readable
And swell has many writable and readable bindings that you can use. Let me show
bindings that you can use. Let me show you one of the more useful bindings
you one of the more useful bindings which is going to be bind colon this to
which is going to be bind colon this to get a reference to a DOM element. So
get a reference to a DOM element. So let's look at an example. Let's say that
let's look at an example. Let's say that we have a canvas and we can give it some
we have a canvas and we can give it some styles.
styles. So let's say canvas width 200 pixels by
So let's say canvas width 200 pixels by 200 pixels.
And then let's give it a white background. And now we have a simple
background. And now we have a simple canvas with a white background. All
canvas with a white background. All right. So let's say that we want to
right. So let's say that we want to reference this canvas. Maybe we can go
reference this canvas. Maybe we can go inside of here and create an effect
inside of here and create an effect and then we can say const canvas
and then we can say const canvas document query selector and let's select
document query selector and let's select the canvas and then we can get the
the canvas and then we can get the context. So we can say const ctx equals
context. So we can say const ctx equals canvas get context
canvas get context 2D. And if we log the context,
so if we open the developer tools, we can see that it works. But the downside
can see that it works. But the downside of this is that you're targeting any
of this is that you're targeting any canvas in your app. So you could have
canvas in your app. So you could have multiple canvases and etc. So you
multiple canvases and etc. So you actually don't know what you're
actually don't know what you're selecting. So instead of doing this, we
selecting. So instead of doing this, we can remove this line and we can go here
can remove this line and we can go here and we can say let canvas. And this is
and we can say let canvas. And this is going to be undefined until your
going to be undefined until your component is added to the DOM. So now we
component is added to the DOM. So now we can go to our canvas element and we can
can go to our canvas element and we can get a reference to it by saying bind
get a reference to it by saying bind colon this. And now we can bind it to
colon this. And now we can bind it to canvas.
canvas. As you can see now we get a reference to
As you can see now we get a reference to the canvas. And of course instead of
the canvas. And of course instead of using an effect here if you don't care
using an effect here if you don't care about tracking any values you can use
about tracking any values you can use onmount
onmount and you're going to get the same result.
and you're going to get the same result. All right. So let me show you another
All right. So let me show you another cool feature when it comes to bindings.
cool feature when it comes to bindings. Let's say that you want to make a
Let's say that you want to make a mocking Spongebob case converter. So in
mocking Spongebob case converter. So in this example, I have a simple function
this example, I have a simple function which is called to Spongebob case which
which is called to Spongebob case which accepts some text and then it converts
accepts some text and then it converts it to the mocking Spongebob case meme.
it to the mocking Spongebob case meme. And here is our state. All right. So how
And here is our state. All right. So how do we make this work? Well, we learned
do we make this work? Well, we learned that we can bind a value. So we can say
that we can bind a value. So we can say bind value and then we can just maybe
bind value and then we can just maybe pass text. But we have to convert the
pass text. But we have to convert the case. So maybe we can pass a function
case. So maybe we can pass a function here. So we can say to Spongebob case
here. So we can say to Spongebob case and then we can pass text and we
and then we can pass text and we immediately get an error because we
immediately get an error because we can't bind to a function of course. All
can't bind to a function of course. All right. So maybe you're thinking let's
right. So maybe you're thinking let's create a derived. So we can say mocking
create a derived. So we can say mocking spongrol case
spongrol case and then let's say derived. So we can
and then let's say derived. So we can say to spawn case and you can pass in
say to spawn case and you can pass in the text. All right. So let's go here.
So maybe this is going to work. Well, let's save it and we can go to our
let's save it and we can go to our example. So it seems that it works at
example. So it seems that it works at first, but we're going to see if we type
first, but we're going to see if we type in anything else, nothing is going to
in anything else, nothing is going to work. And that is because we can't bind
work. And that is because we can't bind to derives. All right. So if we can't do
to derives. All right. So if we can't do this, then maybe we need to go old
this, then maybe we need to go old school and just use the regular
school and just use the regular attributes. So we can go here for
attributes. So we can go here for example and say value
example and say value So you can say to Spongebob case. Let's
So you can say to Spongebob case. Let's pass the text and then let's use the
pass the text and then let's use the event listener on input.
event listener on input. So we get access to the event. And now
So we get access to the event. And now we can say text equals e target value.
we can say text equals e target value. All right. So let's see if this works.
All right. So let's see if this works. And if you go to our example and start
And if you go to our example and start typing. Awesome. You're going to see it
typing. Awesome. You're going to see it works. All right. But there's actually a
works. All right. But there's actually a better way to do this using function
better way to do this using function bindings. So what are function bindings?
bindings. So what are function bindings? Well, instead of binding to the value,
Well, instead of binding to the value, we can pass a get and set function. So
we can pass a get and set function. So we have complete control what happens
we have complete control what happens when you read and write to a value. So
when you read and write to a value. So here is how it looks like. Let's just
here is how it looks like. Let's just delete all of this. We can say bind
delete all of this. We can say bind colon value. But now we can pass a get
colon value. But now we can pass a get and set function or we can just write it
and set function or we can just write it in line.
in line. So let's define a getter.
So let's define a getter. So we can say to spawn case we can pass
So we can say to spawn case we can pass the text and now we can set the value
the text and now we can set the value when we update it. So we can say value
when we update it. So we can say value and now we can reassign the text. So we
and now we can reassign the text. So we can say text equals to Spongebob case
can say text equals to Spongebob case and we can pass the new value and I'm
and we can pass the new value and I'm also going to wrap this in curly boys
also going to wrap this in curly boys because of formatting.
because of formatting. All right. So let's go to our example
All right. So let's go to our example and let's type test. And we can see it
and let's type test. And we can see it works. So now we can let everyone know
works. So now we can let everyone know that React is just JavaScript.
All right friends, let me show you some cool bindings that you can use. Among
cool bindings that you can use. Among the many bindings, you have awesome
the many bindings, you have awesome media bindings for audio, video, and
media bindings for audio, video, and image elements. Let's look at the video
image elements. Let's look at the video player. So in this example, I have a
player. So in this example, I have a simple video player. Right now, it
simple video player. Right now, it doesn't do anything. So if you look
doesn't do anything. So if you look here, here we have a reference to the
here, here we have a reference to the clip. And then we're going to bind the
clip. And then we're going to bind the current time, duration, and the pause
current time, duration, and the pause state. In the markup, I just have a
state. In the markup, I just have a simple video element, some controls.
simple video element, some controls. Here we have the time and the timeline
Here we have the time and the timeline is just a range input. So, we're going
is just a range input. So, we're going to bind the value of the current time.
to bind the value of the current time. The max value is going to be the
The max value is going to be the duration. And here we have the step. All
duration. And here we have the step. All right. So, let's go to the video element
right. So, let's go to the video element and let's bind some values. So we can
and let's bind some values. So we can bind the current time,
bind the current time, the duration, and the pause state.
the duration, and the pause state. All right. So now we can go to the
All right. So now we can go to the player. Let's see if playing the video
player. Let's see if playing the video works.
Of course, we can also scrub through the video.
Awesome. And if you want to learn about all of the values that you can bind, you
all of the values that you can bind, you can go to the SW documentation. As you
can go to the SW documentation. As you can see, there's a lot of them.
All right, I want to show you one last cool example.
cool example. In this example, I have this content
In this example, I have this content editable area so we can edit the text.
editable area so we can edit the text. And let's say that we want to measure
And let's say that we want to measure when its width and height changes.
when its width and height changes. Usually, you would use something like
Usually, you would use something like the resize observer API, but SWEL
the resize observer API, but SWEL provides read only bindings for the
provides read only bindings for the client width and client height. So here
client width and client height. So here we defined width and height and now we
we defined width and height and now we just need to bind the value. So we can
just need to bind the value. So we can go to text area and we can say bind
go to text area and we can say bind client width and we can bind it to width
client width and we can bind it to width and we can also bind the client height
and that's it. Now we can go to the example and we can type something.
As you can see, it's that easy. All right, friends. In this section,
All right, friends. In this section, we're going to learn everything about
we're going to learn everything about components. First, we're going to create
components. First, we're going to create a basic to-do app, and then we're going
a basic to-do app, and then we're going to split it into multiple components so
to split it into multiple components so we can learn how we can pass data around
we can learn how we can pass data around and so on. Let's start by creating a
and so on. Let's start by creating a form to add the to-do.
form to add the to-do. All right. So, let's add an input and a
All right. So, let's add an input and a placeholder.
So, we can say add to-do. And then we're going to bind the value
going to bind the value to to-do. So let's use the onsubmit
to to-do. So let's use the onsubmit event.
event. And we can create a function that's
And we can create a function that's called add to-do. All right. So let's
called add to-do. All right. So let's add some state. So the first piece of
add some state. So the first piece of state we're going to need is of course
state we're going to need is of course going to be let to-do.
And then we can copy it over and create to-dos. And this is going to be an array
to-dos. And this is going to be an array by default. All right. So let's create
by default. All right. So let's create this add to-do function.
And of course, we get the event implicitly. So, we want to prevent the
implicitly. So, we want to prevent the default behavior. So, we don't reload
default behavior. So, we don't reload the page. And then we can just push the
the page. And then we can just push the to-do to the to-dos array. So, we can
to-do to the to-dos array. So, we can say to-dos push. So, let's pass in an
say to-dos push. So, let's pass in an object. So, first we're going to create
object. So, first we're going to create an ID. So, we can use crypto from window
an ID. So, we can use crypto from window to get a random UU ID. And then we're
to get a random UU ID. And then we're going to have text, which is going to be
going to have text, which is going to be the to-do text. And then we can say
the to-do text. And then we can say completed is false by default. All
completed is false by default. All right. So now let's loop over the
right. So now let's loop over the to-dos.
to-dos. So let's create a list. Then we can use
So let's create a list. Then we can use the curly voice. We can use the each
the curly voice. We can use the each block. So we can say each to-dos as
block. So we can say each to-dos as to-do. We can pass the to-do as the
to-do. We can pass the to-do as the unique key. Let's close the each block.
unique key. Let's close the each block. And then here we can just create a list
And then here we can just create a list item.
All right. So we can create a checkbox. So we can bind the checked value
So we can bind the checked value to to-do completed. So let's add another
to to-do completed. So let's add another input which is going to be our to-do. So
input which is going to be our to-do. So we can bind the value to to-do text. And
we can bind the value to to-do text. And let's also add a button for removing the
let's also add a button for removing the to-do.
to-do. So we can say on click
So we can say on click we're going to create this function
we're going to create this function called remove to-do. And we can just
called remove to-do. And we can just pass the to-do. All right. So now we can
pass the to-do. All right. So now we can go here in the script block under add
go here in the script block under add to-do. Let's add this function.
to-do. Let's add this function. Remove to-do. It's going to accept the
Remove to-do. It's going to accept the to-do. And now we can reassign to-dos to
to-do. And now we can reassign to-dos to equal to-dos filter. So we get the
equal to-dos filter. So we get the to-do.
to-do. And then we can say if the to-do ID
And then we can say if the to-do ID doesn't equal to the to-do ID that we
doesn't equal to the to-do ID that we passed, then we're going to filter the
passed, then we're going to filter the items based on that. All right. And the
items based on that. All right. And the last thing I want to do is add a
last thing I want to do is add a container here for styles.
container here for styles. So we can say to-dos
and that should be it. All right. So let's see if we can add any to-dos here.
let's see if we can add any to-dos here. So we can say learn swelt.
So we can say learn swelt. As you can see it works as expected. All
As you can see it works as expected. All right. But let's add a simple
right. But let's add a simple transition. We're going to learn more
transition. We're going to learn more about transitions later in the course.
about transitions later in the course. But for right now I'm just going to go
But for right now I'm just going to go to the list item. Then we can say
to the list item. Then we can say transition colon. So we can type slide.
transition colon. So we can type slide. So let's press enter to import slide
So let's press enter to import slide from swelt /transition.
from swelt /transition. As you can see slide is imported from
As you can see slide is imported from swelt /transition.
swelt /transition. All right. So now if we go back to our
All right. So now if we go back to our example, let's type in learn swelt. Now
example, let's type in learn swelt. Now you're going to see this beautiful
you're going to see this beautiful transition.
transition. And that's how simple that is. All
And that's how simple that is. All right. So let's fix one more thing. So
right. So let's fix one more thing. So for example, if we add a to-do like
for example, if we add a to-do like learn, you're going to see the input
learn, you're going to see the input doesn't clear. So let's clear the input
doesn't clear. So let's clear the input by going to add to-do and then we can
by going to add to-do and then we can just clear the to-do value. All right.
just clear the to-do value. All right. So now we can say learn swelt
So now we can say learn swelt profit and as you can see now the input
profit and as you can see now the input is cleared and let's also remove the
is cleared and let's also remove the to-do so we can see our animation
to-do so we can see our animation working and removing the to-do works. So
working and removing the to-do works. So you can see it looks great. All right
you can see it looks great. All right let's show the remaining to-dos. So we
let's show the remaining to-dos. So we can say let remaining. So this is going
can say let remaining. So this is going to be a derived piece of state based on
to be a derived piece of state based on when to-dos change. So we can create
when to-dos change. So we can create this function remaining to-dos
this function remaining to-dos and we can create this below remove
and we can create this below remove to-do.
to-do. So we can say function
So we can say function remaining to-dos.
remaining to-dos. All right. So we basically want to
All right. So we basically want to filter the to-dos and return the length
filter the to-dos and return the length of the array. So we can say return
of the array. So we can say return to-dos filter. So now we get access to
to-dos filter. So now we get access to the to-do and then we can say if to-do
the to-do and then we can say if to-do is not completed. But of course we want
is not completed. But of course we want to return the length.
to return the length. So below the list we can create a div
So below the list we can create a div and let's create a paragraph tag. So we
and let's create a paragraph tag. So we can say remaining and then let's use an
can say remaining and then let's use an expression. So we can say if remaining
expression. So we can say if remaining is one
is one then we can say item otherwise is going
then we can say item otherwise is going to be items and then we just need to add
to be items and then we just need to add left. All right. So now let's add a
left. All right. So now let's add a to-do.
All right. So, let's delete that to-do. As you can see, everything works as
As you can see, everything works as expected. All right. But I also want to
expected. All right. But I also want to be able to filter the to-dos by all
be able to filter the to-dos by all active and completed. And I also want to
active and completed. And I also want to have an option to clear the completed
have an option to clear the completed to-dos. So, back in the code, let's
to-dos. So, back in the code, let's create this filters div. And let's use
create this filters div. And let's use the curly boy. So, we can create an each
the curly boy. So, we can create an each loop. And now, let's use an array
loop. And now, let's use an array directly. So we can define our filters
directly. So we can define our filters which are going to be all
which are going to be all active and completed. So we can say s
active and completed. So we can say s filter. Let's close the each block.
filter. Let's close the each block. All right. So let's create a button.
All right. So let's create a button. So we can say the name of the filter.
So we can say the name of the filter. And now we only have to update the
And now we only have to update the filter. So we can say on click.
filter. So we can say on click. So let's say set filter. And then we can
So let's say set filter. And then we can just pass the filter. And then the last
just pass the filter. And then the last thing we have to do is add the button to
thing we have to do is add the button to clear the completed to-dos.
clear the completed to-dos. So let's add a button here. Then we can
So let's add a button here. Then we can say clear completed.
And then we're going to create another function named clear completed.
function named clear completed. All right. So now let's go back to the
All right. So now let's go back to the script block.
script block. And this looks like a good place to add
And this looks like a good place to add our functions. So let's say function set
our functions. So let's say function set filter is going to accept the new
filter is going to accept the new filter. So we can just say filter equals
filter. So we can just say filter equals new filter. And of course we need to add
new filter. And of course we need to add this piece of state.
this piece of state. So let's say let filter
So let's say let filter state and by default is going to be all.
state and by default is going to be all. All right. So now we only have to clear
All right. So now we only have to clear the completed to-dos.
the completed to-dos. So we can say function clear completed.
So let's say to-dos equals to-dos filter. Now we get access to the to-do.
filter. Now we get access to the to-do. Now we can filter the to-dos that aren't
Now we can filter the to-dos that aren't completed.
All right. So let's add our to-do. Learn swelt profit. What you're going to see
swelt profit. What you're going to see if we complete this and we try using our
if we complete this and we try using our filters, it won't really do anything.
filters, it won't really do anything. And that is because in our code here,
And that is because in our code here, we're looping over to-dos. What we
we're looping over to-dos. What we actually want to loop over are the
actually want to loop over are the filtered to-dos. So let's go to the top.
filtered to-dos. So let's go to the top. So here below filter, let's add another
So here below filter, let's add another piece of state. Let's say filtered
piece of state. Let's say filtered to-dos equals derived. So let's create a
to-dos equals derived. So let's create a filter to-dos function. So let's keep
filter to-dos function. So let's keep everything organized.
everything organized. All right. So, let's create the filter
All right. So, let's create the filter to-dos function. Let's find a cozy spot
to-dos function. Let's find a cozy spot here. Looks perfect.
here. Looks perfect. We can say function
We can say function filter to-dos.
filter to-dos. All right. So, we just need to filter
All right. So, we just need to filter the list of the to-do items. So, we can
the list of the to-do items. So, we can return to-dos filter.
And now we can say if filter equals all then we can return true. So
equals all then we can return true. So let's copy this over two times. We can
let's copy this over two times. We can say active
say active and completed.
and completed. So here we can just say isn't completed
So here we can just say isn't completed and then for completed we can say
and then for completed we can say completed.
All right. So now we can replace to-dos with filter to-dos.
So, let's go to our example. And now, let's add a to-do.
Let's complete the first to-do. So, now let's sort the to-dos by active. As you
let's sort the to-dos by active. As you can see, it works. So, let's sort them
can see, it works. So, let's sort them by completed and let's sort them by all.
by completed and let's sort them by all. So, now let's see if clear completed
So, now let's see if clear completed works.
works. Awesome. Everything works as expected.
Awesome. Everything works as expected. All right, friends. Let's learn about
All right, friends. Let's learn about components by taking the contents of
components by taking the contents of this file and splitting it into multiple
this file and splitting it into multiple components. So, let's open the sidebar
components. So, let's open the sidebar and inside the lip folder, let's create
and inside the lip folder, let's create a new folder called to-dos.
a new folder called to-dos. And we already learned that swel
And we already learned that swel components end with the dotswelt
components end with the dotswelt extension. So, for example,
extension. So, for example, to-dos.swelt. But the casing doesn't
to-dos.swelt. But the casing doesn't matter. This can be lowerase or
matter. This can be lowerase or uppercase. The name of the component
uppercase. The name of the component itself doesn't matter as long as it ends
itself doesn't matter as long as it ends with a dotswelt extension. All right.
with a dotswelt extension. All right. So, let's oneshot all of the components
So, let's oneshot all of the components that we're going to need.
that we're going to need. So, let's create add to-do.
We're going to have a to-do list, a to-do item,
All right. So, let's close the sidebar, and we can close all of these files. All
and we can close all of these files. All right. So let's start with the add to-do
right. So let's start with the add to-do component. So we can go here to our
component. So we can go here to our form. We can cut this content. And to
form. We can cut this content. And to use a component, we start with the
use a component, we start with the pointy boy. And then we can type
pointy boy. And then we can type component. And in this case, the casing
component. And in this case, the casing is important. The component name has to
is important. The component name has to be capitalized or use the dot notation.
be capitalized or use the dot notation. For example, my component. But in this
For example, my component. But in this case, we want to import the add to-do
case, we want to import the add to-do component. So let's say add to-do. As we
component. So let's say add to-do. As we start typing it, if we press enter,
start typing it, if we press enter, we're going to autoimp import it at the
we're going to autoimp import it at the top. All right. So how can we pass
top. All right. So how can we pass things to this component? Components
things to this component? Components like regular HTML elements also have
like regular HTML elements also have attributes but for components we call
attributes but for components we call them properties or props for short. So
them properties or props for short. So what we want to pass to add to is the
what we want to pass to add to is the add to-do function itself and the to-do.
add to-do function itself and the to-do. All right. So let's go to the add to-do
All right. So let's go to the add to-do component
component to accept props inside of a component.
to accept props inside of a component. We can just say let props and then we
We can just say let props and then we can use the props rune.
can use the props rune. And now we can paste our content.
And now we can paste our content. Now we can get add to-dos from props.
Now we can get add to-dos from props. And we can get to-do from props. Of
And we can get to-do from props. Of course, this is tedious. So we can
course, this is tedious. So we can dstructure them.
So we can say add to-do and we can say to-do. We can also specify the default
to-do. We can also specify the default value as a fallback.
value as a fallback. And if you have any other props, you can
And if you have any other props, you can just gather them and you can spread them
just gather them and you can spread them on your element. So we can do something
on your element. So we can do something like this. And this is really useful if
like this. And this is really useful if you're making something like a component
you're making something like a component library. You're making a button. So you
library. You're making a button. So you can pass whatever you want. But in this
can pass whatever you want. But in this case, we're not going to use it. So let
case, we're not going to use it. So let me just remove it.
me just remove it. And of course, let's remove props.
All right. So let's add a to-do. So we can say learn. But you're going to see
can say learn. But you're going to see nothing happens. And why that is? Well,
nothing happens. And why that is? Well, basically we're mutating this to-do from
basically we're mutating this to-do from a child component. So we have to tell
a child component. So we have to tell swelt that to-do here is bindable and
swelt that to-do here is bindable and that it's okay for the child to mutate
that it's okay for the child to mutate parent state.
parent state. So you can use the bindable rune. So we
So you can use the bindable rune. So we can say to-do equals bindable. And if
can say to-do equals bindable. And if you want, you can also pass a fallback
you want, you can also pass a fallback here. All right. So now that we've done
here. All right. So now that we've done that, we actually have to go back here.
that, we actually have to go back here. And now we can bind the value of to-do
and we can remove this. All right. So let's add a to-do. As you
All right. So let's add a to-do. As you can see, it works beautifully. What's
can see, it works beautifully. What's also really cool is that you can bind
also really cool is that you can bind the instance of this component using
the instance of this component using this and you can bind it to some
this and you can bind it to some variable like element. And now inside at
variable like element. And now inside at to-do if you have any function like
to-do if you have any function like example and you export this function now
example and you export this function now you can actually access it where you
you can actually access it where you bound it. But in this case, binding the
bound it. But in this case, binding the property isn't even necessary because we
property isn't even necessary because we can move state inside add to-do. So we
can move state inside add to-do. So we can delete to-do
and let's just add a state here. Let's say let to-do
say let to-do state and that's it. So now we can
state and that's it. So now we can invoke add to-do. We can create a
invoke add to-do. We can create a function onsubmit.
function onsubmit. So let's remove add to-do here.
And of course we need to prevent the default behavior. So we can say e
default behavior. So we can say e prevent default.
prevent default. And now we can say add to-do. And we can
And now we can say add to-do. And we can pass our to-do. And let's clear the
pass our to-do. And let's clear the to-do. All right. So we can save this.
to-do. All right. So we can save this. Let's go back here to our component. We
Let's go back here to our component. We no longer need this. Now we need to
no longer need this. Now we need to update the add to-do function to just
update the add to-do function to just accept a to-do.
accept a to-do. So this is going to be to-do. We can
So this is going to be to-do. We can delete this line
delete this line and this one. All right, that should be
and this one. All right, that should be it. All right, so let's add a to-do.
As you can see, it works the same as before.
before. Let's also do a bit of cleanup. So, we
Let's also do a bit of cleanup. So, we no longer need this piece of state. And
no longer need this piece of state. And I like to keep the import separate. All
I like to keep the import separate. All right, so next, let's work on the to-do
right, so next, let's work on the to-do list. So, let's go to our markup. Let's
list. So, let's go to our markup. Let's take this list
take this list and let's go to to-do list. All right.
and let's go to to-do list. All right. So, let's add our markup.
So, let's add our markup. Then, let's create a script block. And
Then, let's create a script block. And now we can accept some props.
All right. So, we're going to accept to-dos and remove to-do. So, in this
to-dos and remove to-do. So, in this case, we can replace filter to-dos with
case, we can replace filter to-dos with a more generic to-dos because we can
a more generic to-dos because we can pass anything, right? So, let's just
pass anything, right? So, let's just import slide. And that's it for this
import slide. And that's it for this component. All right. So, we can go back
component. All right. So, we can go back to our main component. So now we can add
to our main component. So now we can add to-do list here. Going to autoimp
to-do list here. Going to autoimp import. So now we just need to pass the
import. So now we just need to pass the to-dos. But keep in mind these are going
to-dos. But keep in mind these are going to be the filter to-dos. And we just
to be the filter to-dos. And we just need to pass remove to-do. All right. So
need to pass remove to-do. All right. So let's see if this works.
All right. So let's take this markup and this is going to be our filter to-do
this is going to be our filter to-do component.
So let's go to filter to-do or to-do filter. So let's add some state. All
filter. So let's add some state. All right. So let's dstructure these props.
So we're going to pass remaining set filter and clear completed.
set filter and clear completed. All right. So back in our component, we
All right. So back in our component, we can say to-do filter.
can say to-do filter. And now we can pass the remaining to-dos
And now we can pass the remaining to-dos the set filter function and clear
the set filter function and clear completed.
completed. All right. So let's go to our example.
All right. So let's go to our example. Let's add some to-dos.
Let's add some to-dos. So let's see if our filtering works. And
So let's see if our filtering works. And it seems it does. Beautiful.
So let's do some cleanup. We can remove this slide. And I think that's all.
this slide. And I think that's all. Let's see.
Let's see. Yeah. All right. The last component is
Yeah. All right. The last component is going to be the to-do item. So, we can
going to be the to-do item. So, we can go to to-do list. And now we can create
go to to-do list. And now we can create a to-do item. So, let's yink this
a to-do item. So, let's yink this markup. And then let's go to to-do item.
markup. And then let's go to to-do item. And we can paste it right here. So,
And we can paste it right here. So, let's get the props.
So, the props are going to be the to-do and remove to-do.
and remove to-do. Let's also add slide here. Save
Let's also add slide here. Save everything. And now back in this
everything. And now back in this component,
component, we can say to-do item. So we're going to
we can say to-do item. So we're going to import it at the top.
import it at the top. So let's pass that to-do
So let's pass that to-do and remove to-do.
and remove to-do. We can delete slide. And that's it. So
We can delete slide. And that's it. So now let's add some to-dos.
We can see that everything works as expected.
expected. All right. So the last thing to do is to
All right. So the last thing to do is to go to app.swelt. Now we're going to take
go to app.swelt. Now we're going to take everything from here. So let's go to
everything from here. So let's go to to-dos.swelt
to-dos.swelt and let's put our code here.
and let's put our code here. And now we can update this imports. This
And now we can update this imports. This is no longer lip to-dos. We can just
is no longer lip to-dos. We can just delete this part. All right. So now we
delete this part. All right. So now we can go back to app.swelt. Let's delete
can go back to app.swelt. Let's delete everything. And now we can use the
everything. And now we can use the to-dos component.
We can complete the to-do. We can filter the to-dos
the to-dos and we can clear them. Awesome. All
and we can clear them. Awesome. All right. There is one last thing I want to
right. There is one last thing I want to show you. So for example, it's really
show you. So for example, it's really troublesome how we're mutating state so
troublesome how we're mutating state so deeply in this child component. So if
deeply in this child component. So if you go to to-do list, now we're mutating
you go to to-do list, now we're mutating from this child where we have to-do
from this child where we have to-do item. And this can get you into trouble
item. And this can get you into trouble if you're not aware of it. In my
if you're not aware of it. In my opinion, binding values is perfectly
opinion, binding values is perfectly fine one or two levels deep max. But it
fine one or two levels deep max. But it can get out of hand if you have more
can get out of hand if you have more nested components. In that case, instead
nested components. In that case, instead of binding the values, we can just pass
of binding the values, we can just pass regular callbacks. So let's actually do
regular callbacks. So let's actually do that quick refactor just to show you how
that quick refactor just to show you how it looks like.
it looks like. So back in to-dos, we're going to update
So back in to-dos, we're going to update at to-do to work the same as before when
at to-do to work the same as before when we had an event. So now we have to say
we had an event. So now we have to say event prevent default.
event prevent default. So let's go pure JavaScript and we're
So let's go pure JavaScript and we're going to get the data from the form. So
going to get the data from the form. So we can say const form data equals new
we can say const form data equals new form data and we can pass it this which
form data and we can pass it this which is going to be a reference to the form
is going to be a reference to the form inside of add to-do. So here we can just
inside of add to-do. So here we can just say form data get
say form data get to-do and then we can clear the form.
to-do and then we can clear the form. All right. So, because we're not going
All right. So, because we're not going to bind the values in the to-do item
to bind the values in the to-do item component, we actually have to create
component, we actually have to create functions for toggling and updating the
functions for toggling and updating the to-do, but it's nothing complicated. So,
to-do, but it's nothing complicated. So, let's go here and let's create our
let's go here and let's create our functions. So, let's say function toggle
functions. So, let's say function toggle to-do. We're going to accept the to-do.
to-do. We're going to accept the to-do. First, we need to get the index of the
First, we need to get the index of the to-do. So, we can say to-dos find index.
to-do. So, we can say to-dos find index. So, we get the to-do item and then we
So, we get the to-do item and then we can say to-do ID equals to-do ID. All
can say to-do ID equals to-do ID. All right. So now we can update the
right. So now we can update the completed state of the to-do item. So we
completed state of the to-do item. So we can say to-dos pass in the index
can say to-dos pass in the index and we can change the completed value.
All right. So the update to do function is going to be similar. All right. So
is going to be similar. All right. So let's create the update to-do function.
So let's say update to-do. All right. So we also get the to-do
All right. So we also get the to-do index but in this case instead of
index but in this case instead of completed we just want to update the
completed we just want to update the value. So we can say text equals
value. So we can say text equals to do text and that's it. So now we just
to do text and that's it. So now we just need to update the props that we're
need to update the props that we're passing. So add to-do is going to be
passing. So add to-do is going to be unchanged. But for the to-do list now
unchanged. But for the to-do list now besides passing to-dos and remove to-do
besides passing to-dos and remove to-do we're going to pass toggle to-do and
we're going to pass toggle to-do and update to-do.
update to-do. And let's see what is this complaining
And let's see what is this complaining about. is because we didn't pass the
about. is because we didn't pass the prop. That's fine. And to-do filter is
prop. That's fine. And to-do filter is going to remain the same. All right. So,
going to remain the same. All right. So, let's update add to-do. And isn't this
let's update add to-do. And isn't this nice, friends? Deleting code sometimes
nice, friends? Deleting code sometimes feels better than writing code. So, we
feels better than writing code. So, we can just delete all of this junk.
can just delete all of this junk. Since we're not going to use bind now,
Since we're not going to use bind now, we just need to give this an identifier
we just need to give this an identifier using name. We can name it to-do. And of
using name. We can name it to-do. And of course, on submit, we're going to invoke
course, on submit, we're going to invoke add to-do.
And that's it for the add to-do component. All right. Now, we just need
component. All right. Now, we just need to update to-do item. Inside to-do list,
to update to-do item. Inside to-do list, we're going to accept toggle to-do
All right. Now let's update to-do item. So let's get to
So let's get to and update to-do.
All right. So this is going to be a bit more verbose because we're not binding
more verbose because we're not binding the value. So we have to say that the
the value. So we have to say that the checked value is equal to to-do
checked value is equal to to-do completed. And now we can use an event
completed. And now we can use an event listener on change.
listener on change. So we can say toggle to-do and then we
So we can say toggle to-do and then we can pass the to-do. So we can do the
can pass the to-do. So we can do the same thing for the text value is going
same thing for the text value is going to be to-do text and we can use on input
to be to-do text and we can use on input and we can say update to-do and we can
and we can say update to-do and we can pass the to-do. All right. So let me
pass the to-do. All right. So let me save and format. So let's try adding a
save and format. So let's try adding a to-do.
The only thing that's not working is clearing the input. So let's investigate
clearing the input. So let's investigate that. So, we can go here to our
that. So, we can go here to our component where we have add to-do.
Oh, my bad. Clear isn't a thing. This is actually dot reset. All right. So, let's
actually dot reset. All right. So, let's add a to-do.
So, let's see if we can complete a to-do, if we can filter them,
to-do, if we can filter them, and let's see if we can clear the
and let's see if we can clear the to-dos. Awesome.
to-dos. Awesome. As you can see, bindings are really
As you can see, bindings are really useful, but in most cases, you can just
useful, but in most cases, you can just pass in regular events. There's nothing
pass in regular events. There's nothing wrong with that, especially if you have
wrong with that, especially if you have deeply nested components. And later,
deeply nested components. And later, we're going to learn how we can
we're going to learn how we can communicate between components without
communicate between components without using props or events.
using props or events. All right, friends. Now that we know how
All right, friends. Now that we know how components work, let's talk about
components work, let's talk about component composition. Let's learn how
component composition. Let's learn how we can compose components in Celt by
we can compose components in Celt by using nesting and snippets to render
using nesting and snippets to render children and how to communicate between
children and how to communicate between components without using props or events
components without using props or events by making a completely customizable
by making a completely customizable accordion.
accordion. So in HTML we take it for granted that
So in HTML we take it for granted that we can just nest elements and we can
we can just nest elements and we can also slot content like in this accordion
also slot content like in this accordion item. So let's see how we can translate
item. So let's see how we can translate these concepts to swelt. All right. So,
these concepts to swelt. All right. So, let's open the sidebar and let's create
let's open the sidebar and let's create a new folder called accordion.
a new folder called accordion. So, let's oneshot the accordion
So, let's oneshot the accordion components. So, we can create
components. So, we can create accordion.swelt.
accordion.swelt. And we're also going to have an
And we're also going to have an accordion item.
And let's also create index.js so we can export our components.
export our components. So, let's close the sidebar. All right.
So, let's close the sidebar. All right. Our goal is to be able to use the
Our goal is to be able to use the accordion items like this. So we can say
accordion items like this. So we can say import accordion and accordion item. And
import accordion and accordion item. And for this we have to individually export
for this we have to individually export the components. So we can say export
the components. So we can say export default as accordion
default as accordion from.
from. And now we can say accordion.
And now we can say accordion. So let's do the same thing for the
So let's do the same thing for the accordion item.
And that's all that we have to do. All right. So now in app.swel we can import
right. So now in app.swel we can import the individual accordion components.
the individual accordion components. So we can say import
So we can say import accordion and accordion item from
accordion and accordion item from lib accordion. In this case the index.js
lib accordion. In this case the index.js file is going to be automatically picked
file is going to be automatically picked up. All right. So let's use the
up. All right. So let's use the accordion component.
accordion component. And inside of the accordion we're going
And inside of the accordion we're going to have our accordion item. All right.
to have our accordion item. All right. But how can we render these children? By
But how can we render these children? By default, any content between these
default, any content between these component tags is going to automatically
component tags is going to automatically become part of a children snippet. And
become part of a children snippet. And snippets are just regular functions that
snippets are just regular functions that let you create reusable markup and let
let you create reusable markup and let you delegate rendering to child
you delegate rendering to child components. So in this example, this is
components. So in this example, this is actually a snippet. So we can create a
actually a snippet. So we can create a snippet by oursel. If we define the
snippet by oursel. If we define the snippet here, we can say children. Let's
snippet here, we can say children. Let's close the snippet.
close the snippet. And the great thing about snippets is it
And the great thing about snippets is it can be anywhere in your component. So we
can be anywhere in your component. So we can have it here. And now we can pass it
can have it here. And now we can pass it as a prop to this component.
as a prop to this component. But if you define a snippet between
But if you define a snippet between these component tags, then it's going to
these component tags, then it's going to become a prop implicitly.
become a prop implicitly. So we can remove this and we don't even
So we can remove this and we don't even need to define a children snippet
need to define a children snippet because it's already done for us. All
because it's already done for us. All right. So let's go to the accordion
right. So let's go to the accordion component and let's render the contents.
component and let's render the contents. So we can destructure children from
So we can destructure children from props.
And now let's create an accordion element. So we can use an if block to
element. So we can use an if block to check if the children exist.
And to render a snippet we use the render tag. So we can use curly voice at
render tag. So we can use curly voice at render. So you can say children and we
render. So you can say children and we can invoke the function. And we can also
can invoke the function. And we can also provide a call back. So let's say else
and now we successfully rendered the children. All right. Instead of using
children. All right. Instead of using this if block we can also use optional
this if block we can also use optional chaining.
chaining. So again we can use the curly boys at
So again we can use the curly boys at render
render children question mark and then we can
children question mark and then we can invoke the function. So this is a
invoke the function. So this is a shorter way of doing it. As you can see
shorter way of doing it. As you can see it works the same.
it works the same. All right. So let's go back here and I'm
All right. So let's go back here and I'm going to remove this. So let's use an
going to remove this. So let's use an accordion item instead since now we can
accordion item instead since now we can nest anything. So we can say accordion
nest anything. So we can say accordion item.
item. All right. So let's pass some content
All right. So let's pass some content here and let's create a title prop.
here and let's create a title prop. So we can say item A. All right. So
So we can say item A. All right. So let's go to the accordion item and we
let's go to the accordion item and we have to do the same thing. So we can the
have to do the same thing. So we can the structure children and we also have a
structure children and we also have a title.
So let's create an accordion item. We're going to have a button which is
We're going to have a button which is going to have a name accordion heading.
going to have a name accordion heading. So let's create a div inside of it.
So let's create a div inside of it. We're going to pass the title and let's
We're going to pass the title and let's create an accordion trigger.
So let's use an emoji and then let's add an on click listener to the button.
an on click listener to the button. We can name it toggle. So let's go back
We can name it toggle. So let's go back here and let's create a piece of state
here and let's create a piece of state called open.
called open. By default it's going to be false and
By default it's going to be false and let's create this toggle function.
So we can say open is opposite of open. So we're just going to flip the value.
So we're just going to flip the value. All right. So below the button we're
All right. So below the button we're going to render the children content.
going to render the children content. So let's say if open
So let's say if open let's create a div name accordion
let's create a div name accordion content and then we can render the
content and then we can render the children. So let's use a curly boy at
children. So let's use a curly boy at render
render children.
And I'm also going to add a dynamic open class to the trigger. So you can say
class to the trigger. So you can say class open.
class open. All right. So we can go to our example.
All right. So we can go to our example. Let me bump the size up. And we can see
Let me bump the size up. And we can see that it works beautifully.
that it works beautifully. And that's basically it. We can add
And that's basically it. We can add multiple accordion items. So let's
multiple accordion items. So let's create four of them. Let's say item B,
create four of them. Let's say item B, C, and D. And now we can go to our
C, and D. And now we can go to our example. And we can see that they all
example. And we can see that they all work.
work. That being said, this has limited
That being said, this has limited composibility. And what do I mean by
composibility. And what do I mean by that? Well, let's say, for example, that
that? Well, let's say, for example, that your user now wants to change the icon.
your user now wants to change the icon. So you're going to add an icon prop and
So you're going to add an icon prop and then they can pass an emoji or whatever.
then they can pass an emoji or whatever. But maybe they also want to change the
But maybe they also want to change the icon position. So now you create another
icon position. So now you create another prop because you want to please the
prop because you want to please the user. So you say icon position. Okay.
user. So you say icon position. Okay. All right. So you have all of these
All right. So you have all of these options. But that's not a way to live
options. But that's not a way to live your life. Instead of doing this, you
your life. Instead of doing this, you should use inversion of control. So you
should use inversion of control. So you should let the user control how they
should let the user control how they want to render this content. Unless of
want to render this content. Unless of course you want a stricter API like
course you want a stricter API like this. All right. So let's remove this
this. All right. So let's remove this and let's go into the accordion item
and let's go into the accordion item component. All right. So instead of
component. All right. So instead of passing children and title, we can pass
passing children and title, we can pass a snippet. So let's pass an accordion
a snippet. So let's pass an accordion item snippet. So now we can go to the
item snippet. So now we can go to the markup and we can just yank it out of
markup and we can just yank it out of here.
here. And here we can render the snippet. So
And here we can render the snippet. So we can use the curly voice at render
we can use the curly voice at render accordion item.
And because snippets are just functions, we can pass open and toggle.
we can pass open and toggle. And now we have complete control how we
And now we have complete control how we want to render the accordion item. So we
want to render the accordion item. So we can just remove this prop since we don't
can just remove this prop since we don't need it anymore. Let's remove the
need it anymore. Let's remove the content.
content. And now we can just pass a snippet. So
And now we can just pass a snippet. So we can say curly boys cache snippet. So
we can say curly boys cache snippet. So the snippet name was accordion item.
the snippet name was accordion item. And now we can destructure the open and
And now we can destructure the open and toggle state from the accordion item.
toggle state from the accordion item. So let's close the snippet.
So let's close the snippet. And inside of the snippet, we're going
And inside of the snippet, we're going to paste the code that we copied.
to paste the code that we copied. So now we can remove this title here
So now we can remove this title here and say item A. And of course, we're not
and say item A. And of course, we're not rendering any children. So this is our
rendering any children. So this is our content.
content. And that's it. And as you can see now we
And that's it. And as you can see now we have complete control how we want to
have complete control how we want to render the accordion item. Of course you
render the accordion item. Of course you can have both in the accordion item. You
can have both in the accordion item. You can conditionally render by default the
can conditionally render by default the prop the user pass or a custom snippet.
prop the user pass or a custom snippet. All right. So let's look at our example.
All right. So let's look at our example. It works the same as before but now you
It works the same as before but now you have complete freedom how you want to
have complete freedom how you want to render this accordion item. So for
render this accordion item. So for example maybe want to move this icon
example maybe want to move this icon here. We can just render it like that.
All right friends, let me show you something really cool and that is how
something really cool and that is how you can communicate between components
you can communicate between components without using props or events. So let's
without using props or events. So let's say for example that you want to control
say for example that you want to control the open and close state of every
the open and close state of every accordion item.
accordion item. So for example, we can declare a piece
So for example, we can declare a piece of state here by saying open and then
of state here by saying open and then let's say false. But here's the problem.
let's say false. But here's the problem. Are we going to pass this piece of state
Are we going to pass this piece of state to every accordion item? That seems
to every accordion item? That seems really annoying. And if you for example
really annoying. And if you for example bind this value, how are all of the
bind this value, how are all of the children components going to get
children components going to get notified that this value changed? Well,
notified that this value changed? Well, for this we can use the context API. So
for this we can use the context API. So let me just remove this. I'm going to
let me just remove this. I'm going to keep bind open. So let's go to the
keep bind open. So let's go to the accordion component. We're going to
accordion component. We're going to accept this open prop. But remember, we
accept this open prop. But remember, we have to make this bindable.
have to make this bindable. All right. So now in the parent
All right. So now in the parent component, we can set the context. So we
component, we can set the context. So we can import the set context function from
can import the set context function from swelt. And now we have to give the
swelt. And now we have to give the context a key. So we can say accordion.
context a key. So we can say accordion. And now we can pass in here whatever you
And now we can pass in here whatever you want including reactive state. But keep
want including reactive state. But keep in mind just passing open isn't going to
in mind just passing open isn't going to work. And that is because open is just a
work. And that is because open is just a regular value as we learned before. So
regular value as we learned before. So in this case open is just going to
in this case open is just going to evaluate to false and that's it. It's
evaluate to false and that's it. It's never going to update. We need to use
never going to update. We need to use some mechanism to get the latest value
some mechanism to get the latest value of open. So you can use functions or
of open. So you can use functions or classes but in this example I'm just
classes but in this example I'm just going to use a property accessor.
going to use a property accessor. So I can just say get open
So I can just say get open and then we can return open.
and then we can return open. So now that we defined the context in
So now that we defined the context in the parent component we can access it in
the parent component we can access it in any child component and in this case
any child component and in this case it's going to be accordion item. So we
it's going to be accordion item. So we can go to the top here. All right. So
can go to the top here. All right. So let's get the accordion context. So we
let's get the accordion context. So we can say con accordion equals and now we
can say con accordion equals and now we can use the get context function from
can use the get context function from SW. So we can import that and now we can
SW. So we can import that and now we can access the context by passing the key
access the context by passing the key that we defined before
that we defined before which is accordion. All right. So now we
which is accordion. All right. So now we can turn this open state into a derived
can turn this open state into a derived and we can listen when accordion.open
and we can listen when accordion.open changes because it's reactive. All
changes because it's reactive. All right. So now let's go back
right. So now let's go back and now here we can create a button.
and now here we can create a button. let's say button outline. So let's use a
let's say button outline. So let's use a curly boy and an expression inside. So
curly boy and an expression inside. So we can say if the state is open then
we can say if the state is open then we're going to say close. Otherwise
we're going to say close. Otherwise we're going to say open. So let's add on
we're going to say open. So let's add on click handler.
And then we can just flip the value of open.
All right. Let me copy the accordion item multiple times.
All right. So now when I click open, all of the accordion items should be open.
of the accordion items should be open. So now if I close them, they're all
So now if I close them, they're all going to be closed. Most of the time
going to be closed. Most of the time you're going to want to pass props. But
you're going to want to pass props. But when you have deeply nested component or
when you have deeply nested component or you're making something interesting like
you're making something interesting like this accordion component, then the
this accordion component, then the context API is a perfect solution.
context API is a perfect solution. All right. So there's one more thing
All right. So there's one more thing that I want to show you when it comes to
that I want to show you when it comes to component composition, and that is the
component composition, and that is the module script block. It's easier to show
module script block. It's easier to show you. So I'm going to create a new file.
you. So I'm going to create a new file. So let me press control shiftp and then
So let me press control shiftp and then we can change the language mode. So we
we can change the language mode. So we can change this file to be javascript.
can change this file to be javascript. All right. So essentially cell
All right. So essentially cell components are just regular functions.
components are just regular functions. So for example we have a function called
So for example we have a function called component
component and then let's say inside of it we want
and then let's say inside of it we want to create a unique ID.
to create a unique ID. So we can say crypto random yuyu ID. And
So we can say crypto random yuyu ID. And that's great if you want a unique ID for
that's great if you want a unique ID for every component instance
every component instance because when we create a new component,
because when we create a new component, we're going to get a new random ID. So
we're going to get a new random ID. So let's say that we have four instances of
let's say that we have four instances of the same component. So we can say let A
the same component. So we can say let A equals component.
equals component. So we have A, B, C, and D. And now every
So we have A, B, C, and D. And now every component is going to have a unique ID.
component is going to have a unique ID. But let's say that you want to share the
But let's say that you want to share the same unique ID across component
same unique ID across component instances. Well, this file is actually
instances. Well, this file is actually called a module. So instead of creating
called a module. So instead of creating a unique ID inside of a component, we
a unique ID inside of a component, we can move it at the top of the module. So
can move it at the top of the module. So let's just move ID.
And now it doesn't matter how many component instances you have because
component instances you have because they're all going to reference the same
they're all going to reference the same unique ID. So that is what the module
unique ID. So that is what the module script block is for.
script block is for. All right, let's look at an example. So,
All right, let's look at an example. So, let's open the sidebar and then let's
let's open the sidebar and then let's collapse to-dos and accordion. And now
collapse to-dos and accordion. And now we're going to create a new component
we're going to create a new component inside the lip folder named
inside the lip folder named counter.swelt.
counter.swelt. So, let's collapse the sidebar. All
So, let's collapse the sidebar. All right. So, normally we would create a
right. So, normally we would create a script block and we would say count
script block and we would say count equals state zero.
equals state zero. And we can create a button say count
And we can create a button say count on click
on click count ++. But let's say that you want to
count ++. But let's say that you want to share this count state across component
share this count state across component instances. So instead of using a regular
instances. So instead of using a regular script block, we can just use a module
script block, we can just use a module script block. So we just say module and
script block. So we just say module and that's it. And of course you can have
that's it. And of course you can have both of them in the same component. So
both of them in the same component. So you can have a regular script block and
you can have a regular script block and a module script block.
But this isn't only useful for sharing data and state. You can also export
data and state. You can also export utilities and whatever else you want
utilities and whatever else you want including snippets. So for example,
including snippets. So for example, let's add a function that can reset the
let's add a function that can reset the count.
And then we can say count equals zero. All right. And let's say you have some
All right. And let's say you have some snippets. So here I have an icon
snippets. So here I have an icon snippet. And this is a really great use
snippet. And this is a really great use case for snippets. You can define your
case for snippets. You can define your SVG icons inside of a component and then
SVG icons inside of a component and then you can export them. The only caveat to
you can export them. The only caveat to when exporting snippets is that they
when exporting snippets is that they can't reference any state inside of a
can't reference any state inside of a script block. So they have to be
script block. So they have to be self-contained. And remember snippets
self-contained. And remember snippets are just regular functions
are just regular functions and we can say export
and we can say export icon. So you can export as many snippets
icon. So you can export as many snippets as you would like. All right. So now
as you would like. All right. So now inside app.swvel So we can create a
inside app.swvel So we can create a script block and we can say import
script block and we can say import counter and let's import icon and reset
counter and let's import icon and reset from
from lib/counter.sswelt.
All right. So let's use the counter component
component and let's create a reset button.
And let's also render the icon. So we can use curly voice at render. We can
can use curly voice at render. We can say icon.
say icon. So let's render one at 50 by 50 pixels,
So let's render one at 50 by 50 pixels, 100 by 100 pixels,
100 by 100 pixels, and 200 by 200 pixels. All right. So let
and 200 by 200 pixels. All right. So let me also add a container.
All right. So now in the example, we can increment count. As you can see, now
increment count. As you can see, now it's shared across the component
it's shared across the component instances. And we can also reset the
instances. And we can also reset the count. And of course, we can also see
count. And of course, we can also see our beautiful icon being rendered at
our beautiful icon being rendered at different resolutions.
different resolutions. As you can see, the module script lock
As you can see, the module script lock is very useful. You can use it for
is very useful. You can use it for anything from controlling media playback
anything from controlling media playback across component instances to just
across component instances to just exporting some utilities from the module
exporting some utilities from the module you want instead of creating a new file.
you want instead of creating a new file. All right, friends. In this section,
All right, friends. In this section, we're going to learn how to create
we're going to learn how to create delightful user interactions with swelt
delightful user interactions with swelt transitions and animations. So let's
transitions and animations. So let's look at a basic transition. Let's add a
look at a basic transition. Let's add a message element with two spans inside of
message element with two spans inside of it. And we can say hello world.
it. And we can say hello world. All right. So to add a transition, we
All right. So to add a transition, we can use the transition directive. So we
can use the transition directive. So we can say transition colon and we can use
can say transition colon and we can use one of many built-in swel transitions.
one of many built-in swel transitions. So let's say fade and let's import fade
So let's say fade and let's import fade from swel/transition.
from swel/transition. And we can also pass some animation
And we can also pass some animation options.
options. So we can see that we have multiple
So we can see that we have multiple options such as delay, duration, and
options such as delay, duration, and easing. And the options depend on the
easing. And the options depend on the type of the transition you're using. So
type of the transition you're using. So in this case, let's say duration and
in this case, let's say duration and this is going to be 600 milliseconds.
this is going to be 600 milliseconds. All right. So first I want to animate
All right. So first I want to animate this hello text during this 600
this hello text during this 600 milliseconds and then I want to animate
milliseconds and then I want to animate this world text. So we can do the same
this world text. So we can do the same thing. We can say transition fade, but
thing. We can say transition fade, but instead of a duration, let's use a delay
instead of a duration, let's use a delay and we can set it to 600 milliseconds.
and we can set it to 600 milliseconds. All right. So, transitions only run when
All right. So, transitions only run when the component is added to the DOM. So,
the component is added to the DOM. So, let's refresh the page.
let's refresh the page. And as you can see, the transition works
And as you can see, the transition works beautifully. All right. Let's make this
beautifully. All right. Let's make this more interesting. So, let's create a new
more interesting. So, let's create a new piece of state called play. So, we can
piece of state called play. So, we can say let play equals state. Let's say
say let play equals state. Let's say false.
false. All right. So, let's create an interval
All right. So, let's create an interval that's going to update the state of play
that's going to update the state of play every 2 seconds. So let's say set
every 2 seconds. So let's say set interval and then let's pass a call
interval and then let's pass a call back. So let's flip the value of play
back. So let's flip the value of play and then let's say 2 seconds.
and then let's say 2 seconds. All right. So let's add an if block. We
All right. So let's add an if block. We can use the curly boys pound if
can use the curly boys pound if we can say play. So let's close the if
we can say play. So let's close the if block
block and that's it.
You can also define custom intro and outro transitions. So for example,
outro transitions. So for example, instead of transition, we can use the
instead of transition, we can use the indirective and instead of fade, let's
indirective and instead of fade, let's import fly from swel/transition.
import fly from swel/transition. So now we have new properties to play
So now we have new properties to play with. So for example, let's say x should
with. So for example, let's say x should be -10. Let's leave the duration alone.
be -10. Let's leave the duration alone. And now we can also specify an easing.
And now we can also specify an easing. So has a bunch of custom easing that you
So has a bunch of custom easing that you can pick from, but let's pick a fun one
can pick from, but let's pick a fun one like elastic out. So we can also import
like elastic out. So we can also import that from swel/ easing and of course
that from swel/ easing and of course let's specify an altra transition. So we
let's specify an altra transition. So we can say out fade. All right. So let's do
can say out fade. All right. So let's do the same thing for the second span.
the same thing for the second span. Instead of transition let's use the
Instead of transition let's use the indirective.
indirective. Going to say fly and x is going to be
Going to say fly and x is going to be 10. And we can also use the same easing.
10. And we can also use the same easing. And let's specify the outro transition.
All right. Right. So let's do a bit of formatting.
All right. So let's go to our example and we can see that we have this fun
and we can see that we have this fun transition.
There is one important thing that you should know about transitions and that
should know about transitions and that is local versus global transitions.
is local versus global transitions. Let's say that we're looping over a
Let's say that we're looping over a bunch of items that we also want to
bunch of items that we also want to stagger. So let's create an element
stagger. So let's create an element called stagger and inside of it I'm
called stagger and inside of it I'm going to use the each block. So let's
going to use the each block. So let's use a curly voice found each. All right.
use a curly voice found each. All right. So let's create an array of 50 items.
So let's create an array of 50 items. And let's also close the each block. All
And let's also close the each block. All right. Let's loop over the 50 items.
right. Let's loop over the 50 items. So we can say I + 1. So this should give
So we can say I + 1. So this should give us 50 items. And it works. All right.
us 50 items. And it works. All right. Let's add the transition.
Let's add the transition. So let's use the indirective and we can
So let's use the indirective and we can import fade from swelt to create a
import fade from swelt to create a staggered effect. We can just use a
staggered effect. We can just use a delay and we can multiply the index by
delay and we can multiply the index by the time. So we can say 100
the time. So we can say 100 milliseconds. But this isn't going to
milliseconds. But this isn't going to work. So if you go to our example, no
work. So if you go to our example, no matter how many times we refresh the
matter how many times we refresh the page, nothing is going to happen. And
page, nothing is going to happen. And that is because transitions are local by
that is because transitions are local by default. That means that transitions
default. That means that transitions only play when the block they belong to
only play when the block they belong to is added or removed and not the parent
is added or removed and not the parent block like this each block for example.
block like this each block for example. To fix this you can use the global
To fix this you can use the global modifier. So you can use this pipe and
modifier. So you can use this pipe and you can say global. So now our example
you can say global. So now our example should work if you refresh the page.
should work if you refresh the page. As you can see now we have a beautiful
As you can see now we have a beautiful staggered animation.
staggered animation. In past versions of Selt transitions
In past versions of Selt transitions were global by default. So keep that in
were global by default. So keep that in mind if you ever encounter older SWEL
mind if you ever encounter older SWEL code.
code. All right. So we've seen that
All right. So we've seen that transitions play when the element gets
transitions play when the element gets added to the DOM. But if you're using a
added to the DOM. But if you're using a framework like Cellit, that's not the
framework like Cellit, that's not the case since the initial payload is server
case since the initial payload is server side rendered. So let's make a fade
side rendered. So let's make a fade component where we can control if the
component where we can control if the transition should play. So let's open
transition should play. So let's open the sidebar and inside of lib. Let's
the sidebar and inside of lib. Let's create a new file. So let's create a
create a new file. So let's create a transitions folder. And then let's
transitions folder. And then let's create a new fade. component inside of
create a new fade. component inside of it.
All right. So let's start by creating a script block. And now we want to
script block. And now we want to structure the children if the transition
structure the children if the transition should play and the transition options
should play and the transition options from props.
from props. And if you're using something like
And if you're using something like socitate and you just want to
socitate and you just want to automatically play the transition when
automatically play the transition when the element is added, you can just use
the element is added, you can just use an effect.
an effect. So you can just say play true when the
So you can just say play true when the element is added. But in this case, we
element is added. But in this case, we want to manually control if we can play
want to manually control if we can play the transition. All right. So, let's use
the transition. All right. So, let's use an if block. We can use the curly boys.
an if block. We can use the curly boys. So, if play is true, then we're going to
So, if play is true, then we're going to play the transition. So, let's close the
play the transition. So, let's close the if block. And inside of the if block,
if block. And inside of the if block, we're going to create a div. All right.
we're going to create a div. All right. So, we can use a transition. So, let's
So, we can use a transition. So, let's import fate from swelt/transition.
import fate from swelt/transition. And then we can pass the transition
And then we can pass the transition options. So, it should be options.
options. So, it should be options. So, inside of the div, we can render the
So, inside of the div, we can render the children. So you can use our curly boys
children. So you can use our curly boys at render and then we can render the
at render and then we can render the children. Now let's go back to
children. Now let's go back to app.swelt. All right. So now inside
app.swelt. All right. So now inside appsel we can use the fade component. So
appsel we can use the fade component. So let's just import it. So we can say
let's just import it. So we can say something like boo and let's use a
something like boo and let's use a spooky ghost.
spooky ghost. And as you can see we have a warning
And as you can see we have a warning because these props are required. But we
because these props are required. But we can actually make them optional. So if
can actually make them optional. So if we go here let's say that we don't want
we go here let's say that we don't want to play this transition by default. And
to play this transition by default. And we can also use an empty object by
we can also use an empty object by default or the transition options.
default or the transition options. All right. So now we no longer get a
All right. So now we no longer get a warning here. But of course we can
warning here. But of course we can specify the transition options. So we
specify the transition options. So we can say duration should be 2 seconds.
can say duration should be 2 seconds. All right. So we can go to our example
All right. So we can go to our example and we can see regardless how many times
and we can see regardless how many times we refresh the page the transition isn't
we refresh the page the transition isn't going to play.
going to play. But we can of course specify play.
But we can of course specify play. But this is redundant. We can just say
But this is redundant. We can just say play. And let's refresh the page. And
play. And let's refresh the page. And you're going to see it still doesn't
you're going to see it still doesn't work. And you probably already know why.
work. And you probably already know why. So if we go to the fake component, we
So if we go to the fake component, we learn that transitions are local by
learn that transitions are local by default. So we need to make this
default. So we need to make this transition global. So let's use the pipe
transition global. So let's use the pipe and say global. All right. So now our
and say global. All right. So now our transition should play when the outer
transition should play when the outer block gets removed or added. And if we
block gets removed or added. And if we refresh the page now, you're going to
refresh the page now, you're going to see we get a spooky transition.
see we get a spooky transition. All right, friends. Not only are we able
All right, friends. Not only are we able to use Swell's built-in transitions, we
to use Swell's built-in transitions, we can also specify our own custom
can also specify our own custom transitions. And a custom transition is
transitions. And a custom transition is just a simple function that returns an
just a simple function that returns an object with the transition options and a
object with the transition options and a CSS or tick function. All right, so
CSS or tick function. All right, so let's create a custom transition. So we
let's create a custom transition. So we can start by creating a function named
can start by creating a function named custom transition. We get a reference to
custom transition. We get a reference to the note and we can also pass the
the note and we can also pass the transition options. All right, so let's
transition options. All right, so let's dstructure the options and we can set
dstructure the options and we can set some default values.
some default values. So here we can say the duration should
So here we can say the duration should be 2 seconds.
be 2 seconds. There should be no delay and let's use a
There should be no delay and let's use a custom easing. So we can say elastic
custom easing. So we can say elastic out. So we can import that from Sel. And
out. So we can import that from Sel. And now we can return an object with the
now we can return an object with the transition options. All right. So now
transition options. All right. So now let's return an object with the
let's return an object with the transition options. So we can say
transition options. So we can say duration
duration delay and easing. All right. So this is
delay and easing. All right. So this is the important part. We can either return
the important part. We can either return a CSS function which is going to use CSS
a CSS function which is going to use CSS key frames to generate this transition
key frames to generate this transition or if you need to use JavaScript for
or if you need to use JavaScript for your transition, you can return a tick
your transition, you can return a tick function. So let's return a CSS
function. So let's return a CSS function. We can say CSS and we get the
function. We can say CSS and we get the T argument. So this is going to be the
T argument. So this is going to be the progress of the transition that goes
progress of the transition that goes from 0 to 1. And then we can return some
from 0 to 1. And then we can return some CSS. So let's use back tick.
CSS. So let's use back tick. So we can say color HSL. So let's use a
So we can say color HSL. So let's use a template literal. So we want to animate
template literal. So we want to animate the hue. So we can say 360 * t. And then
the hue. So we can say 360 * t. And then we can say 100% for the saturation and
we can say 100% for the saturation and 80% for the lightness.
80% for the lightness. All right. So let's also add a
All right. So let's also add a transform. So we can say transform scale
transform. So we can say transform scale and let's also use a template literal
and let's also use a template literal and then we can just say t. So we want
and then we can just say t. So we want to animate the scale from 0 to one. All
to animate the scale from 0 to one. All right. So let me briefly explain what
right. So let me briefly explain what this t means. So for example, let's say
this t means. So for example, let's say that you have a transition where an item
that you have a transition where an item goes from 0 pixels to 100 pixels over 2
goes from 0 pixels to 100 pixels over 2 seconds. So if t is a value that goes
seconds. So if t is a value that goes from zero to one, that means that if t
from zero to one, that means that if t is 0.5 for example, then the progress of
is 0.5 for example, then the progress of this transition is going to be at 50
this transition is going to be at 50 pixels. And it's really that simple. And
pixels. And it's really that simple. And besides t, we also have this u value
besides t, we also have this u value which is just the opposite. All right.
which is just the opposite. All right. So, let's use our custom transition. So,
So, let's use our custom transition. So, let's go here. Let's create a heading.
let's go here. Let's create a heading. All right. So, we can use the custom
All right. So, we can use the custom transition like any other transition.
transition like any other transition. So, we can use the indirective and we
So, we can use the indirective and we can say custom transition.
can say custom transition. All right. So, let's save this and go to
All right. So, let's save this and go to our example. And we can see it works
our example. And we can see it works beautifully. How cool is this, friends?
All right, friends. Let me show you a custom transition that uses JavaScript.
custom transition that uses JavaScript. This is really useful when you want to
This is really useful when you want to use JavaScript to control a transition
use JavaScript to control a transition such as a typewriter effect or this
such as a typewriter effect or this scrambling text effect. So I'm just
scrambling text effect. So I'm just going to copy and paste this custom
going to copy and paste this custom transition here. So if I reload the
transition here. So if I reload the page, we can see how it works and it's a
page, we can see how it works and it's a really cool effect. All right, so let's
really cool effect. All right, so let's talk through it. So here we have some
talk through it. So here we have some hackerman characters and then we just
hackerman characters and then we just have a simple function that gets a
have a simple function that gets a random character. So here is our custom
random character. So here is our custom transition named scramble text. As
transition named scramble text. As before, we get a reference to the node
before, we get a reference to the node and the options. So, we set some default
and the options. So, we set some default values here. But now, we're using
values here. But now, we're using JavaScript. So, we get the final text
JavaScript. So, we get the final text from the node text content. And we get
from the node text content. And we get the amount of characters here. All
the amount of characters here. All right. So, now we only have to return an
right. So, now we only have to return an object with the transition options. But
object with the transition options. But now, instead of CSS, we're going to use
now, instead of CSS, we're going to use this stick function to use JavaScript.
this stick function to use JavaScript. So, we're going to accumulate the result
So, we're going to accumulate the result in this output variable. Then, we're
in this output variable. Then, we're going to loop over the characters in
going to loop over the characters in this for loop. So, we're saying if T is
this for loop. So, we're saying if T is higher than I divided by length, then
higher than I divided by length, then we're going to rest the character at its
we're going to rest the character at its final position. Otherwise, we're just
final position. Otherwise, we're just going to get a random character. And
going to get a random character. And then each time we're updating the nodes
then each time we're updating the nodes text content. So, we can just assign it
text content. So, we can just assign it to output. All right. So, now in the
to output. All right. So, now in the rest of the code, we can just use this
rest of the code, we can just use this like any regular transition. We're using
like any regular transition. We're using a monospace font, so the letters have
a monospace font, so the letters have the same width. And then we can use our
the same width. And then we can use our custom transition by using the
custom transition by using the indirective. And we can specify that it
indirective. And we can specify that it should be the scramble text effect. And
should be the scramble text effect. And that's it. Now we have this wonderful
that's it. Now we have this wonderful scrambling text effect.
All right friends, let me show you something that is going to blow your
something that is going to blow your mind and that is coordinating
mind and that is coordinating transitions between different elements.
transitions between different elements. So if you're familiar with view
So if you're familiar with view transitions, basically swelt has them
transitions, basically swelt has them built in. So here I have an example that
built in. So here I have an example that I prepared for you. Here we have just a
I prepared for you. Here we have just a simple example where we're looping over
simple example where we're looping over these posts and we can archive them and
these posts and we can archive them and unarchive them. And the code is really
unarchive them. And the code is really nothing special. Here we have these
nothing special. Here we have these random posts and we have these two
random posts and we have these two functions where we can archive and
functions where we can archive and remove a post. And in the template we
remove a post. And in the template we just have two sections. The first one
just have two sections. The first one being post. So we're looping over the
being post. So we're looping over the post and we're filtering them based on
post and we're filtering them based on the ones that aren't archived. And then
the ones that aren't archived. And then we have another section which is the
we have another section which is the archive.
archive. So here we're doing the opposite. We're
So here we're doing the opposite. We're just filtering the post based on the
just filtering the post based on the ones that are archived. And that's
ones that are archived. And that's pretty much it. As I said, there's
pretty much it. As I said, there's nothing special going on here. All
nothing special going on here. All right. So what is the problem? So in
right. So what is the problem? So in this example, when we archive a post and
this example, when we archive a post and then if we unarchive it, we're going to
then if we unarchive it, we're going to see that the item just magically
see that the item just magically teleports. And in the real world, items
teleports. And in the real world, items don't behave like that. And this is
don't behave like that. And this is really a worse user experience because
really a worse user experience because it's not clear what happened. To fix
it's not clear what happened. To fix this, we can use the crossfade
this, we can use the crossfade transition.
transition. All right, so the only thing that we
All right, so the only thing that we have to do is import the crossfade
have to do is import the crossfade function from swelt/transition.
function from swelt/transition. The crossfade function creates two
The crossfade function creates two transitions named send and receive. So
transitions named send and receive. So we can destructure those
from crossfade. And we can just pass an empty object for now. All right. So the
empty object for now. All right. So the only thing that we have to do is go to
only thing that we have to do is go to an each block here where we have
an each block here where we have article.
So we can use the indirective and use the receive transition which
and use the receive transition which accepts a unique key. So we can say key
accepts a unique key. So we can say key and we can set it to the post. So swelt
and we can set it to the post. So swelt knows what items to transition. All
knows what items to transition. All right. So now we can use the out
right. So now we can use the out directive. We can use the same
directive. We can use the same transition and we also need to pass a
transition and we also need to pass a key and we can say post. All right. Now
key and we can say post. All right. Now we have to do the same thing for the
we have to do the same thing for the archive section. So we can just copy
archive section. So we can just copy this code. Let's go to the archive.
this code. Let's go to the archive. So again here where we have this each
So again here where we have this each block and this article. We can just go
block and this article. We can just go here.
here. We can copy and paste our code. So let's
We can copy and paste our code. So let's save everything. And now we can go to
save everything. And now we can go to the example and we can see the magic
the example and we can see the magic happen. So, let's archive a post. And as
happen. So, let's archive a post. And as you can see, it's no longer going to
you can see, it's no longer going to teleport.
teleport. How magical is this, friends?
And we can also specify some crossfade options.
options. As you can see, we can pass a delay,
As you can see, we can pass a delay, duration, easing, and a fallback
duration, easing, and a fallback transition. For example, we can base the
transition. For example, we can base the duration on the element distance. So,
duration on the element distance. So, let's use a duration function, and we
let's use a duration function, and we can get the distance. And now we can say
can get the distance. And now we can say math square root.
math square root. And now we can multiply the distance by
And now we can multiply the distance by 200.
200. And you can also provide a fallback
And you can also provide a fallback transition if no match is found. So we
transition if no match is found. So we can say fall back. And we get a
can say fall back. And we get a reference to the node with the options.
reference to the node with the options. So we can return a custom transition
So we can return a custom transition object. We can use the CSS function. We
object. We can use the CSS function. We get access to team. We can use back.
get access to team. We can use back. So let's say transform
So let's say transform scale and then we can use template
scale and then we can use template literals. We can just pass T and we can
literals. We can just pass T and we can also animate the opacity
and that's it. All right. So now if we go to the example we can see that the
go to the example we can see that the duration is based on the distance. How
duration is based on the distance. How cool is that?
cool is that? All right friends let's talk about flip
All right friends let's talk about flip animations. Currently there's a problem
animations. Currently there's a problem with our transition. So let me show you
with our transition. So let me show you that if we remove this fallback, let me
that if we remove this fallback, let me set a duration to something more obvious
set a duration to something more obvious like 2 seconds. So let's go to our
like 2 seconds. So let's go to our example. So when I press archive on this
example. So when I press archive on this post, you're going to see that we have
post, you're going to see that we have this empty space here. So when the
this empty space here. So when the transition is done, the elements are
transition is done, the elements are going to snap back in. And this looks
going to snap back in. And this looks janky. So we can see it again. So let's
janky. So we can see it again. So let's archive the second post. It's empty. And
archive the second post. It's empty. And then the items snap in. And we can see
then the items snap in. And we can see the same thing if we unarchive the post.
All right. So to fix this, we can use the flip function from swelt. So back in
the flip function from swelt. So back in our code, the only thing that we have to
our code, the only thing that we have to do is import flip from
do is import flip from swelt /an animate. All right. So now
swelt /an animate. All right. So now back in our template where we have the
back in our template where we have the each blocks.
each blocks. So we can go here. We can use a new
So we can go here. We can use a new directive called animate which only
directive called animate which only works inside each blocks. and then we
works inside each blocks. and then we can use flip. And of course, you can
can use flip. And of course, you can also pass in some options here such as
also pass in some options here such as delay, duration, and easing. But in this
delay, duration, and easing. But in this case, we're going to ignore it. All
case, we're going to ignore it. All right. So now we have to do the same
right. So now we have to do the same thing for the second container.
thing for the second container. So here we have article. We can say
So here we have article. We can say animate flip. And that's it. All right.
animate flip. And that's it. All right. So now if we go back to the example, we
So now if we go back to the example, we can archive a post. And you're going to
can archive a post. And you're going to see that the items are going to animate
see that the items are going to animate gracefully.
How cool is that? Let's archive the second post. We can also unarchive the
second post. We can also unarchive the post.
And of course, this also works if you delete a post.
And that is the power of flip animations.
animations. And flip animations don't depend on
And flip animations don't depend on crossfit transitions, but as you can
crossfit transitions, but as you can see, they work great together. All
see, they work great together. All right, friends. Just like with custom
right, friends. Just like with custom transitions, you can also make custom
transitions, you can also make custom animations. All right, so let's look at
animations. All right, so let's look at an example.
an example. So here I have a simplified version of
So here I have a simplified version of the flip animation. As you can see, we
the flip animation. As you can see, we get a reference to the node. We get the
get a reference to the node. We get the before and after state and we also have
before and after state and we also have some animation options. So in this case,
some animation options. So in this case, we're calculating the delta for X and Y,
we're calculating the delta for X and Y, and then we're calculating the scale
and then we're calculating the scale based on the width and height. And just
based on the width and height. And just like with custom transitions, we can
like with custom transitions, we can return this animation options including
return this animation options including a CSS function. And then we can do some
a CSS function. And then we can do some math and we can apply a transform. And
math and we can apply a transform. And here we have a simple shuffle function.
here we have a simple shuffle function. And we're creating 10 items, same as in
And we're creating 10 items, same as in the GF flip example. In fact, we're
the GF flip example. In fact, we're using the same markup from that example.
using the same markup from that example. So here we're going to loop over a bunch
So here we're going to loop over a bunch of items. As you can see, we can shuffle
of items. As you can see, we can shuffle the items, but I also want to animate
the items, but I also want to animate them. So going back to our code here
them. So going back to our code here inside of the each block, we can use the
inside of the each block, we can use the animate directive and we can just say
animate directive and we can just say flip. So now if we go back to the
flip. So now if we go back to the example, we can see that we can flip the
example, we can see that we can flip the items.
items. Now that's magical.
Now that's magical. And we can even log the value of the
And we can even log the value of the before and after state.
before and after state. So you can say console log.
So you can say console log. So let's say from to. So now if we open
So let's say from to. So now if we open the developer tools
the developer tools and let's shuffle the items, you're
and let's shuffle the items, you're going to see we get the before and after
going to see we get the before and after state for every item. So now using the
state for every item. So now using the animate directive and the flip function,
animate directive and the flip function, we can animate the difference in their
we can animate the difference in their position.
Let's talk about tween values and springs. Imagine if you could take the
springs. Imagine if you could take the CSS animation engine, but you can
CSS animation engine, but you can interpolate any number including objects
interpolate any number including objects and arrays. This is where swelt's tween
and arrays. This is where swelt's tween and spring classes come in. All right,
and spring classes come in. All right, let's look at an example. So let's
let's look at an example. So let's create a value named size. And instead
create a value named size. And instead of defining this with state, we can say
of defining this with state, we can say new. And if we start typing tween, let's
new. And if we start typing tween, let's import tween from swelt/motion.
import tween from swelt/motion. And if you're wondering, because you're
And if you're wondering, because you're animating between two values, that is
animating between two values, that is what tween means. All right. So we can
what tween means. All right. So we can pass the target value of 50. So this is
pass the target value of 50. So this is going to animate this value from 0 to
going to animate this value from 0 to 50. And then we can pass some animation
50. And then we can pass some animation options. So we have a couple of options.
options. So we have a couple of options. We can pass the delay, duration, easing,
We can pass the delay, duration, easing, and even a custom interpolation
and even a custom interpolation function. So if you want, you can
function. So if you want, you can interpolate between colors and anything
interpolate between colors and anything else. I recommend checking out the D3
else. I recommend checking out the D3 interpolate library, which gives you a
interpolate library, which gives you a bunch of interpolation functions out of
bunch of interpolation functions out of the box. All right, but in this case,
the box. All right, but in this case, we're going to specify a duration 300
we're going to specify a duration 300 milliseconds. And I'm also going to use
milliseconds. And I'm also going to use an easing. So let's say cubic in out. So
an easing. So let's say cubic in out. So we can import that from swelt/ easing.
we can import that from swelt/ easing. And that's it. So now we can define two
And that's it. So now we can define two functions. The first function is going
functions. The first function is going to be called on mouse down.
to be called on mouse down. And tween has a couple of properties on
And tween has a couple of properties on it. So we can look at size dot. We can
it. So we can look at size dot. We can see we get current. So this is what we
see we get current. So this is what we can use in the template to get the
can use in the template to get the value. We can use a set method. So for
value. We can use a set method. So for example, we can say 200. And then we can
example, we can say 200. And then we can override the animation options if you
override the animation options if you want. And this is also a promise. So you
want. And this is also a promise. So you can await this if you want and make this
can await this if you want and make this async. But in this case,
async. But in this case, we can just say size dot target and we
we can just say size dot target and we can say 150. And this is the quickest
can say 150. And this is the quickest way to update the value. All right. So
way to update the value. All right. So let's copy over this function. So
let's copy over this function. So instead of mouse down, this is going to
instead of mouse down, this is going to be mouse up. And we can use the default
be mouse up. And we can use the default value. All right. So let's create an SVG
value. All right. So let's create an SVG with a circle.
with a circle. So we can say the width and the height
So we can say the width and the height are going to be 400.
are going to be 400. And then we can specify the viewbox. And
And then we can specify the viewbox. And you can think of a viewbox like a camera
you can think of a viewbox like a camera for the SVG. So for example here we can
for the SVG. So for example here we can say the X and Y coordinates should be 0
say the X and Y coordinates should be 0 0. And we can also specify what the
0. And we can also specify what the camera sees. So this is going to be 400x
camera sees. So this is going to be 400x 400.
400. All right. So let's create a circle.
All right. So let's create a circle. So let's pass the event handlers.
So let's pass the event handlers. So we can say on mouse down and this is
So we can say on mouse down and this is going to be on mouse up. All right. So
going to be on mouse up. All right. So let's specify the circle coordinates.
And for the radius we can say size dotcurren.
dotcurren. And let's also add a fill color.
And let's also add a fill color. We can say orange red. And that's it.
We can say orange red. And that's it. And we can even disable this
And we can even disable this accessibility warning. So we can go to
accessibility warning. So we can go to quick fix and we can just disable it.
quick fix and we can just disable it. All right. So let's go to the example.
All right. So let's go to the example. And now when I hold the mouse down on
And now when I hold the mouse down on the circle is going to grow larger. But
the circle is going to grow larger. But when I release the mouse is going to go
when I release the mouse is going to go back to the original position.
How cool is that? All right. So besides the twin class, there is also a spring
the twin class, there is also a spring class. So you can use spring physics
class. So you can use spring physics based on Hook's law. So here where we
based on Hook's law. So here where we define the tween instead of twin we can
define the tween instead of twin we can say spring and we can also import spring
say spring and we can also import spring from swelt/motion.
from swelt/motion. So spring physics are based on hooks law
So spring physics are based on hooks law and they don't have a duration. Instead
and they don't have a duration. Instead you can specify stiffness, damping and
you can specify stiffness, damping and precision. So for example we can go here
precision. So for example we can go here and instead of using these values we can
and instead of using these values we can say that stiffness should be 0,
say that stiffness should be 0, damping 0.25 25 and precision should be
damping 0.25 25 and precision should be 0.1. So we don't need this easing and
0.1. So we don't need this easing and let's remove the tween.
let's remove the tween. All right. So now let's go to the
All right. So now let's go to the example.
example. So when I hold the mouse button down,
So when I hold the mouse button down, it's going to grow larger. And when I
it's going to grow larger. And when I release the mouse, it's going to go back
release the mouse, it's going to go back to the original position. As you can
to the original position. As you can see, it feels a lot more natural and
see, it feels a lot more natural and springy.
All right, friends. In this section, we're going to learn how we can use
we're going to learn how we can use third-party JavaScript libraries in SWL.
third-party JavaScript libraries in SWL. So, if a specific SWL package isn't
So, if a specific SWL package isn't available, you have the entire
available, you have the entire JavaScript ecosystem at your fingertips.
JavaScript ecosystem at your fingertips. Unfortunately, third party JavaScript
Unfortunately, third party JavaScript libraries usually require direct access
libraries usually require direct access to the DOM and they don't understand
to the DOM and they don't understand reactivity. So, in this example, we're
reactivity. So, in this example, we're going to use the popular GP animation
going to use the popular GP animation library in Swelt. All right. So, let's
library in Swelt. All right. So, let's say that you've read the GE
say that you've read the GE documentation and you want to try out
documentation and you want to try out their example. So we can create this box
their example. So we can create this box element and then we can just simply
element and then we can just simply create an animation. Let's import gap
create an animation. Let's import gap and then we can use this two method to
and then we can use this two method to create a twin animation and then we can
create a twin animation and then we can specify the target which is going to be
specify the target which is going to be the box class and we can specify some
the box class and we can specify some animation options. So we can say
animation options. So we can say rotation 360°
rotation 360° the X position should animate 200 pixels
the X position should animate 200 pixels and the duration should be 2 seconds.
and the duration should be 2 seconds. All right. So let's go to our example.
All right. So let's go to our example. But you're going to see that nothing
But you're going to see that nothing happens. All right. So let's open the
happens. All right. So let's open the developer tools for any clues. So we can
developer tools for any clues. So we can see the warning from gap target.box not
see the warning from gap target.box not found.
found. And this is because when this line of
And this is because when this line of code runs, box doesn't exist in the DOM
code runs, box doesn't exist in the DOM yet. So we can use the onmount life
yet. So we can use the onmount life cycle function.
cycle function. So if we say onmount, we can import on
So if we say onmount, we can import on mount from swelt. And let's pass a
mount from swelt. And let's pass a callback function.
callback function. and we can place our animation inside of
and we can place our animation inside of it. And let's also organize the imports.
it. And let's also organize the imports. So, let's go back to the example. And
So, let's go back to the example. And when I reload the page, the animation
when I reload the page, the animation should play.
should play. Awesome. In this example, we're saying
Awesome. In this example, we're saying dotbox, which is just a query selector
dotbox, which is just a query selector under the hood, but of course, we can
under the hood, but of course, we can pass a reference to the element instead.
pass a reference to the element instead. So, let's create a target variable,
So, let's create a target variable, and then we can bind the value of this
and then we can bind the value of this element using this
element using this And then let's bind it to the target.
And then let's bind it to the target. All right. So instead of saying dotbox,
All right. So instead of saying dotbox, we can just pass the target.
we can just pass the target. And we can also say const
And we can also say const tween. So we can return a cleanup
tween. So we can return a cleanup function. So we can go here and we can
function. So we can go here and we can say return.
say return. And we can say tween.kill.
And of course if we reload the page, everything works the same as before. And
everything works the same as before. And of course, instead of using onmount, you
of course, instead of using onmount, you can use an effect. So, we can remove the
can use an effect. So, we can remove the onmount import. And instead of on mount,
onmount import. And instead of on mount, we can just use an effect. And this
we can just use an effect. And this works the same. But keep in mind that
works the same. But keep in mind that effects aren't life cycle functions. An
effects aren't life cycle functions. An effect life cycle depends on the value
effect life cycle depends on the value inside of them updating. So, in this
inside of them updating. So, in this case, if you make target reactive and
case, if you make target reactive and update it at any point, then this effect
update it at any point, then this effect is going to rerun. There is no right or
is going to rerun. There is no right or wrong way here. If you don't care about
wrong way here. If you don't care about tracking values, then you can just use
tracking values, then you can just use onmount. The more important thing is
onmount. The more important thing is that you don't treat effects like life
that you don't treat effects like life cycle functions. So if you understand
cycle functions. So if you understand how effects work, then you're not going
how effects work, then you're not going to run into problems. All right, we got
to run into problems. All right, we got this gap example working. But now let's
this gap example working. But now let's look at how we can bend it to our will
look at how we can bend it to our will and create a declarative component out
and create a declarative component out of it.
of it. So let's take this code and then let's
So let's take this code and then let's open the sidebar and inside of lib I'm
open the sidebar and inside of lib I'm going to create a new component called
going to create a new component called tween.swel.
tween.swel. All right. So in our new component let's
All right. So in our new component let's paste the code. Then let's go to the
paste the code. Then let's go to the top. I don't want target to be reactive.
top. I don't want target to be reactive. So I'm going to remove this. All right.
So I'm going to remove this. All right. So for the props we want to the
So for the props we want to the structure tween which is going to be a
structure tween which is going to be a reference to this animation so we can
reference to this animation so we can control it. And we're going to make this
control it. And we're going to make this bindable. And then we want the animation
bindable. And then we want the animation options. I'm going to name this vase
options. I'm going to name this vase because that's what GUB calls them. So
because that's what GUB calls them. So for example, if we go here to two, you
for example, if we go here to two, you can see GE has targets and varss. I
can see GE has targets and varss. I don't know why it names its but it is
don't know why it names its but it is what it is. And of course, we want to
what it is. And of course, we want to accept the children because we want to
accept the children because we want to be able to animate anything.
All right. So now instead of defining twin here, we can just reassign it and
twin here, we can just reassign it and then we can remove this part and we can
then we can remove this part and we can use our animation options. And the last
use our animation options. And the last thing that we have to do is render the
thing that we have to do is render the children.
children. So we can use the curly boys at render
So we can use the curly boys at render children.
children. And that's it. All right. So now let's
And that's it. All right. So now let's go back to app.swelt and let's use the
go back to app.swelt and let's use the tween component.
tween component. So we can import tween from
So we can import tween from lib/ween.swelt.
lib/ween.swelt. And now we can get a reference to the
And now we can get a reference to the animation by binding tween
animation by binding tween to animation. And we can create it here.
All right. So, let's pass the animation options. So, we can say VS
options. So, we can say VS rotation 3060,
rotation 3060, X should be 200 and duration should be 2
X should be 200 and duration should be 2 seconds. All right. So, we can animate
seconds. All right. So, we can animate anything that we want. So, let's create
anything that we want. So, let's create a button with a box class. We can say
a button with a box class. We can say play. And because we have a reference to
play. And because we have a reference to this animation,
this animation, we can say on click
we can say on click and we can say animation restart. And
and we can say animation restart. And this is just a built-in gap method. All
this is just a built-in gap method. All right. So let's do a bit of cleanup.
right. So let's do a bit of cleanup. And inside of tween, we can also remove
And inside of tween, we can also remove this box class.
And that's it. So now when you go to the example, we can press play and the
example, we can press play and the animation is going to play.
So far, we learned that we can use onmount to get a reference to an
onmount to get a reference to an element. This can be a bit tedious and
element. This can be a bit tedious and boilerplate tip when you want a quick
boilerplate tip when you want a quick reference to an element. So, what if
reference to an element. So, what if instead of component level life cycle
instead of component level life cycle functions, you had element level life
functions, you had element level life cycle functions. In that case, you would
cycle functions. In that case, you would have attachments. Attachments are just
have attachments. Attachments are just regular functions that you can attach to
regular functions that you can attach to regular elements that run when the
regular elements that run when the element is added to the DOM or when
element is added to the DOM or when state inside of them updates. So let's
state inside of them updates. So let's look at the same gap example using
look at the same gap example using attachments. All right. So I'm going to
attachments. All right. So I'm going to start with the box and then let's format
start with the box and then let's format this a bit.
So we can say curly boys at and the attach keyword. So now we get our
attach keyword. So now we get our reference to the node element but you
reference to the node element but you can name this however you want. So let's
can name this however you want. So let's name this box and then let's create a
name this box and then let's create a function. So let's import gap
function. So let's import gap and now we can say dot2. So now we can
and now we can say dot2. So now we can pass the target and the animation
pass the target and the animation options. So let's say rotation 360 x is
options. So let's say rotation 360 x is going to be 200 and the duration is
going to be 200 and the duration is going to be 2 seconds. All right. So now
going to be 2 seconds. All right. So now we can look at our example. So now if I
we can look at our example. So now if I reload the page, the animation should
reload the page, the animation should work. As you can see, this is a lot more
work. As you can see, this is a lot more convenient. All right. How do we create
convenient. All right. How do we create a tween function that we can reuse
a tween function that we can reuse across components similar to the tween
across components similar to the tween component that we created earlier? All
component that we created earlier? All right. So the first thing that we have
right. So the first thing that we have to do is create a tween function which
to do is create a tween function which accepts the animation options and an
accepts the animation options and an optional ref callback. So we get a
optional ref callback. So we get a reference to the tween.
reference to the tween. So inside of the function we can say let
So inside of the function we can say let tween and because attachments are just
tween and because attachments are just regular functions we can just return an
regular functions we can just return an attachment. So let's return an
attachment. So let's return an attachment.
attachment. And of course here we get our reference
And of course here we get our reference to the target element. And inside the
to the target element. And inside the function we can reassign tween to be gap
function we can reassign tween to be gap 2 to with the target and animation
2 to with the target and animation options.
options. And if you need a reference to the
And if you need a reference to the animation, we can invoke the call back.
That's it. So now in the markup, instead of using an inline attachment,
instead of using an inline attachment, we can use the attachment that we made.
we can use the attachment that we made. So let's use the curly voice at attach.
So let's use the curly voice at attach. So let's use the tween attachment that
So let's use the tween attachment that we created.
we created. So let's pass the animation options.
So let's pass the animation options. So we can say rotation 300 is 60, x is
So we can say rotation 300 is 60, x is going to be 200 and the duration is
going to be 200 and the duration is going to be 2 seconds.
going to be 2 seconds. And we can use the optional callback to
And we can use the optional callback to get a reference to the animation. So we
get a reference to the animation. So we can get a reference to the tween. And
can get a reference to the tween. And now we can assign it to animation.
now we can assign it to animation. So let's create animation.
All right, friends. This is the coolest part. So now instead of div, we can turn
part. So now instead of div, we can turn this into a button.
this into a button. And let's say play inside of it.
And now we can say on click animation.
All right. So now if we go to the example and if we press play, we can see
example and if we press play, we can see that our animation works. How cool is
that our animation works. How cool is this?
this? All right, let me show you another cool
All right, let me show you another cool thing about swelt and that is special
thing about swelt and that is special elements. So swelt has special elements
elements. So swelt has special elements you can use at the top level of your
you can use at the top level of your component. Let's say that we want to
component. Let's say that we want to listen to the window scroll position. So
listen to the window scroll position. So let's create a script block and then we
let's create a script block and then we can say let scroll y equals state and
can say let scroll y equals state and let's say zero. All right. So now we
let's say zero. All right. So now we need a handle scroll function.
So we can update scroll Y to equal window scroll Y. All right. So let's use
window scroll Y. All right. So let's use onmount.
So we can add an event listener to the window. We can say window add event
window. We can say window add event listener. Let's listen to scroll. And
listener. Let's listen to scroll. And then we can invoke our handle scroll
then we can invoke our handle scroll function. And let's return a cleanup
function. And let's return a cleanup function. So we can say window remove
function. So we can say window remove event listener. We want to remove the
event listener. We want to remove the scroll event. And we need to pass our
scroll event. And we need to pass our handle scroll function. All right. So
handle scroll function. All right. So now let's create a div element named
now let's create a div element named scroll. And then we can say scroll y and
scroll. And then we can say scroll y and we can say pixels. And that should be
we can say pixels. And that should be it. This is what it would usually take
it. This is what it would usually take to listen to an event and update the
to listen to an event and update the value. So now if we go to the example
value. So now if we go to the example and if we scroll, we're going to see
and if we scroll, we're going to see that the scroll position is going to be
that the scroll position is going to be updated.
updated. Thankfully there's a better way to do
Thankfully there's a better way to do this in swelt. So instead of using
this in swelt. So instead of using onmount where we also have to do the
onmount where we also have to do the cleanup we can use a special element
cleanup we can use a special element instead. So let's remove onmount
and then at the top level of the component we can use swelt colon window.
component we can use swelt colon window. So we can say on scroll and we can use
So we can say on scroll and we can use our handle scroll function and swelt
our handle scroll function and swelt also takes care of the cleanup. So now
also takes care of the cleanup. So now if you go to our example it works the
if you go to our example it works the same as before.
We can make this even simpler. Instead of using events, we can use bindings for
of using events, we can use bindings for properties like the scroll position. So
properties like the scroll position. So in this case, we don't even need the
in this case, we don't even need the handle scroll function
handle scroll function and we can just remove this. So the only
and we can just remove this. So the only thing that we have to do is bind the
thing that we have to do is bind the value. So we can bind scroll Y. And now
value. So we can bind scroll Y. And now if we go to the example, it works the
if we go to the example, it works the same as before.
Believe it or not, we can make this even simpler. Swelt also exports reactive
simpler. Swelt also exports reactive window values from reactivity/ window.
window values from reactivity/ window. So you don't even have to use a special
So you don't even have to use a special element. So we can remove this. And now
element. So we can remove this. And now in the script block, we can import
in the script block, we can import scroll y from swelt/reactivity/
scroll y from swelt/reactivity/ window. And now in the template, the
window. And now in the template, the only thing that we have to change is to
only thing that we have to change is to say scrolly do.curren. And that's it.
say scrolly do.curren. And that's it. Now our example should work the same as
Now our example should work the same as before.
Awesome. All right, friends. Let's talk about
All right, friends. Let's talk about Soel's reactive data structures and
Soel's reactive data structures and utilities. All right, so here I have a
utilities. All right, so here I have a simple Pokémon search example. So here
simple Pokémon search example. So here we have a search query which is called
we have a search query which is called name and then we're storing Pokémon in
name and then we're storing Pokémon in this map cache. So here inside of this
this map cache. So here inside of this get Pokémon function, we can just check
get Pokémon function, we can just check if the Pokémon exists inside of the map.
if the Pokémon exists inside of the map. If that's the case, we can just return
If that's the case, we can just return early. Otherwise, we're going to fetch
early. Otherwise, we're going to fetch the details for the Pokemon. And then
the details for the Pokemon. And then when we get the data, we can just add
when we get the data, we can just add the Pokemon. And of course, we're using
the Pokemon. And of course, we're using an effect to get the Pokémon. And inside
an effect to get the Pokémon. And inside our template, we're just binding the
our template, we're just binding the value to the name. And then here, we're
value to the name. And then here, we're looping over the Pokémon. Since it's a
looping over the Pokémon. Since it's a map, we can just structure the name and
map, we can just structure the name and the details. And then here, we're going
the details. And then here, we're going to use the details element with a
to use the details element with a summary. And then we can just stringify
summary. And then we can just stringify the details. And that's it.
the details. And that's it. And we also have a button to clear the
And we also have a button to clear the map. All right, so trick question. Is
map. All right, so trick question. Is this going to work? As you can see,
this going to work? As you can see, nothing is showing in the example. All
nothing is showing in the example. All right, so how do we fix this? Well,
right, so how do we fix this? Well, maybe we can pass this map to state. I
maybe we can pass this map to state. I don't know. Let's try it.
don't know. Let's try it. All right, at least the example is
All right, at least the example is showing. But if you search for something
showing. But if you search for something like Pikachu, nothing works. And that is
like Pikachu, nothing works. And that is because of course this still isn't
because of course this still isn't reactive.
because there is no way for sale to know that this method is going to be
that this method is going to be reactive. But thankfully, swelt has
reactive. But thankfully, swelt has reactive versions of some built-in
reactive versions of some built-in JavaScript objects like set map and so
JavaScript objects like set map and so on.
on. So let's go here where we define the map
So let's go here where we define the map and instead of using set or new map, we
and instead of using set or new map, we can say new swelt map and we can import
can say new swelt map and we can import this from swelt/reactivity.
this from swelt/reactivity. All right. So now if you go to the
All right. So now if you go to the example, let's search for Pikachu. And
example, let's search for Pikachu. And you can see it's reactive. So we can see
you can see it's reactive. So we can see all the details for Pikachu.
all the details for Pikachu. All right, let's search for Charizard.
All right, let's search for Charizard. And you're going to see now we have
And you're going to see now we have Charizard details.
Charizard details. And we can also clear the Pokémon.
And we can also clear the Pokémon. Awesome. You can find even more reactive
Awesome. You can find even more reactive built-ins in the Swell documentation. So
built-ins in the Swell documentation. So here you have a media query class for
here you have a media query class for example if that's something that you
example if that's something that you need. We have swel date so you have
need. We have swel date so you have reactive dates. Here you have swel map
reactive dates. Here you have swel map which we just used. You have swel set
which we just used. You have swel set which is really great. You have swel for
which is really great. You have swel for working with urls.
working with urls. Then there's also swel search params
Then there's also swel search params and so on. You can read more in the
and so on. You can read more in the swell documentation. So you can use any
swell documentation. So you can use any of these in your project. All right
of these in your project. All right friends. This is a more advanced topic,
friends. This is a more advanced topic, but I think it's useful to know whenever
but I think it's useful to know whenever you're trying to make an external
you're trying to make an external event-based system reactive in swelt.
event-based system reactive in swelt. And an external event is any event you
And an external event is any event you can subscribe to and listen for changes.
can subscribe to and listen for changes. In this example, we're going to create a
In this example, we're going to create a gap timeline. And our goal is going to
gap timeline. And our goal is going to be to synchronize the timeline with an
be to synchronize the timeline with an input. So, let's start with a basic
input. So, let's start with a basic timeline. In this example, I have a
timeline. In this example, I have a simple class called timeline. And here I
simple class called timeline. And here I have a reference to the GSAP timeline.
have a reference to the GSAP timeline. When I create this timeline, I'm going
When I create this timeline, I'm going to invoke this method create timeline.
to invoke this method create timeline. So, this is going to create the timeline
So, this is going to create the timeline when the component mounts. And this is
when the component mounts. And this is just so we have a nicer API when we
just so we have a nicer API when we create this timeline. So, we can just
create this timeline. So, we can just pass in an array of arrays for the
pass in an array of arrays for the animation key frames
and then we add it to the gap timeline. And in the template, we just have two
And in the template, we just have two items, box one and box two, and an
items, box one and box two, and an input. So we can go to the example and
input. So we can go to the example and when I reload the page you're going to
when I reload the page you're going to see that we have a simple animation
see that we have a simple animation here. Our goal is going to be to
here. Our goal is going to be to synchronize this input with the gap
synchronize this input with the gap timeline.
timeline. All right. So let's start with a naive
All right. So let's start with a naive approach here at the top where we define
approach here at the top where we define our class below timeline. We can specify
our class below timeline. We can specify a new reactive variable called time. So
a new reactive variable called time. So this is just going to be state. And then
this is just going to be state. And then inside of the constructor we can use an
inside of the constructor we can use an effect to update it.
effect to update it. So let's create an effect provide a
So let's create an effect provide a callback. So we need to reference the
callback. So we need to reference the gap timeline. So we can say this
gap timeline. So we can say this timeline and we can invoke the seek
timeline and we can invoke the seek method. So we can update the timeline
method. So we can update the timeline playhead each time this time updates.
playhead each time this time updates. Now we just need to create the getter
Now we just need to create the getter and setter. So we can bind the value
and we can say get time. So we can return time and then let's
So we can return time and then let's create a setter. So we can say set
create a setter. So we can say set time the new value that we're going to
time the new value that we're going to receive and then let's update time to
receive and then let's update time to the new value. So now in our template we
the new value. So now in our template we can bind this value to the input. So we
can bind this value to the input. So we can say bind value
can say bind value TL for timeline and then we can pick
TL for timeline and then we can pick time. All right. So let's save and
time. All right. So let's save and format the document. So, if we go to our
format the document. So, if we go to our example, we can reload the page to see
example, we can reload the page to see our animation and we can now control the
our animation and we can now control the timeline, but you're going to see that
timeline, but you're going to see that it's still not synchronized. So, if I
it's still not synchronized. So, if I let go, you're going to see nothing is
let go, you're going to see nothing is going to happen. All right. So, how do
going to happen. All right. So, how do we synchronize the timeline? And this is
we synchronize the timeline? And this is where using events comes in. So, we can
where using events comes in. So, we can subscribe to Gap's on update event and
subscribe to Gap's on update event and then we can update time which is going
then we can update time which is going to trigger the effect. So, we can
to trigger the effect. So, we can synchronize the input with the GSAP
synchronize the input with the GSAP timeline. All right, back in our code.
timeline. All right, back in our code. Let's go to the effect. So now we can go
Let's go to the effect. So now we can go here.
here. Let's reference the timeline and then we
Let's reference the timeline and then we can use gap's event call back API. So we
can use gap's event call back API. So we can subscribe to on update and then we
can subscribe to on update and then we can pass a call back function. All
can pass a call back function. All right. So each time the animation
right. So each time the animation updates, we're going to update the time.
updates, we're going to update the time. So we can say this time and now we need
So we can say this time and now we need to reference the timeline. So you can
to reference the timeline. So you can say this timeline and we need to get the
say this timeline and we need to get the latest time by using gap's time
latest time by using gap's time function. Now when this updates is going
function. Now when this updates is going to trigger this effect which is going to
to trigger this effect which is going to synchronize the timeline and return the
synchronize the timeline and return the latest value of time. Now in our example
latest value of time. Now in our example we can change the input and you're going
we can change the input and you're going to see it's synchronized with the
to see it's synchronized with the timeline.
And that's awesome. But there's a simpler way. All right. Let me show you
simpler way. All right. Let me show you a simpler way how to make reactive
a simpler way how to make reactive events using the create subscriber
events using the create subscriber function. So we can delete this effect
function. So we can delete this effect and this code below it. And then we can
and this code below it. And then we can say create subscriber. So let's import
say create subscriber. So let's import that from swelt. As you can see it's
that from swelt. As you can see it's imported from swelt/reactivity.
imported from swelt/reactivity. And we can pass a callback function to
And we can pass a callback function to create subscriber where we get this
create subscriber where we get this update function.
update function. This is going to let us create
This is going to let us create subscribers.
subscribers. So we can just say this timeline and we
So we can just say this timeline and we can say event call back we can subscribe
can say event call back we can subscribe to on update but in this case we can
to on update but in this case we can just pass the update function and we can
just pass the update function and we can also return a cleanup function. So let's
also return a cleanup function. So let's say return
say return this timeline
this timeline event call back
event call back on update and we can say null. Of
on update and we can say null. Of course, this way of doing cleanups is
course, this way of doing cleanups is specific to GSAP, but the method remains
specific to GSAP, but the method remains the same for any event that you can
the same for any event that you can subscribe to. All right. So now, instead
subscribe to. All right. So now, instead of having this extra variable time, we
of having this extra variable time, we can just create a subscriber. We can
can just create a subscriber. We can just say subscribe and then we can store
just say subscribe and then we can store the reference to the function that's
the reference to the function that's returned from create subscriber. So we
returned from create subscriber. So we can say this subscribe equals to create
can say this subscribe equals to create subscriber.
subscriber. Now we can subscribe to the timeline
Now we can subscribe to the timeline updating.
updating. So we can go to our getter and this
So we can go to our getter and this makes things a lot simpler. The only
makes things a lot simpler. The only thing that you have to do is say this
thing that you have to do is say this dossubscribe.
dossubscribe. So this makes the time value reactive
So this makes the time value reactive when it's read inside of an effect. The
when it's read inside of an effect. The best part is that you don't need any
best part is that you don't need any extra state because now you can just
extra state because now you can just return the value from the timeline. So
return the value from the timeline. So we can say timeline dot time and of
we can say timeline dot time and of course we can update the timeline. So we
course we can update the timeline. So we can go here and we can say this dot
can go here and we can say this dot timeline seek and we can pass the new
timeline seek and we can pass the new value. But of course don't forget to
value. But of course don't forget to invoke the subscribe method. So let's
invoke the subscribe method. So let's see if the example works. So if I reload
see if the example works. So if I reload the page the animation should play. And
the page the animation should play. And as you can see the input is synchronized
as you can see the input is synchronized with the timeline.
As you can see, using create subscriber can make your code a lot simpler. And
can make your code a lot simpler. And not only that, but you can control when
not only that, but you can control when you want to run this update method. The
you want to run this update method. The create subscriber API is great whenever
create subscriber API is great whenever you're trying to make an external
you're trying to make an external event-based system reactive in SEL. That
event-based system reactive in SEL. That can be anything from browser APIs to
can be anything from browser APIs to random JavaScript libraries. you can
random JavaScript libraries. you can subscribe to and listen for changes.
subscribe to and listen for changes. All right, friends, without a doubt, at
All right, friends, without a doubt, at some point you're going to run into
some point you're going to run into legacy Swelt code. So, Swelli was a
legacy Swelt code. So, Swelli was a large shift from previous versions of
large shift from previous versions of Swelt that introduced a new system of
Swelt that introduced a new system of reactivity with runes and snippets
reactivity with runes and snippets replacing slots among other things. So,
replacing slots among other things. So, if you ever need a quick overview, you
if you ever need a quick overview, you can find the legacy API section in the
can find the legacy API section in the Swelt documentation. And there are even
Swelt documentation. And there are even other things that aren't listed here
other things that aren't listed here such as swelt stores. In the past,
such as swelt stores. In the past, stores were required to have reactive
stores were required to have reactive state outside swel components. The
state outside swel components. The reason I didn't cover stores in this
reason I didn't cover stores in this course is because I don't think that you
course is because I don't think that you no longer need them because now you have
no longer need them because now you have universal reactivity with runes. But if
universal reactivity with runes. But if you ever run into stores, then you can
you ever run into stores, then you can read this section in the swell
read this section in the swell documentation.
documentation. There is one more thing worth mentioning
There is one more thing worth mentioning when it comes to legacy swell. By
when it comes to legacy swell. By default, cell components are in legacy
default, cell components are in legacy mode unless you use runes in your
mode unless you use runes in your component. And this is worth noting
component. And this is worth noting because you might run into unexpected
because you might run into unexpected behavior when you're using legacy
behavior when you're using legacy components. So there's two ways that you
components. So there's two ways that you can ensure that your component is in
can ensure that your component is in runes mode. The first method is just
runes mode. The first method is just using runes. So you can say let count
using runes. So you can say let count equal state and now your component is
equal state and now your component is automatically in runes mode. The other
automatically in runes mode. The other method is using this special element to
method is using this special element to specify some compiler options for swelt.
specify some compiler options for swelt. So we can say swelt colon options
So we can say swelt colon options and we can say runes equals true. You
and we can say runes equals true. You can also specify the swel compiler
can also specify the swel compiler options for the entire project. And this
options for the entire project. And this is what I've done for this entire course
is what I've done for this entire course so we don't run into any problems. So if
so we don't run into any problems. So if we go into the swell config you can see
we go into the swell config you can see under the compiler options I enabled
under the compiler options I enabled runes by default. And in the future
runes by default. And in the future versions of Selt, this is going to be
versions of Selt, this is going to be the default.
the default. All right, friends. In the last section,
All right, friends. In the last section, I want to talk about using Selt with AI.
I want to talk about using Selt with AI. To be completely honest, I'm not a big
To be completely honest, I'm not a big AI user, but I know that this is
AI user, but I know that this is important to a lot of people. Newer AI
important to a lot of people. Newer AI models seem to be getting better at
models seem to be getting better at supporting the latest SW syntax, but
supporting the latest SW syntax, but it's still not perfect, and it's often
it's still not perfect, and it's often going to hallucinate features that don't
going to hallucinate features that don't exist with overwhelming confidence. So,
exist with overwhelming confidence. So, if you're using AI and want the latest
if you're using AI and want the latest SWEL syntax suggestions, SWEL has LLM
SWEL syntax suggestions, SWEL has LLM friendly documentation you can feed to
friendly documentation you can feed to an AI context window for more accurate
an AI context window for more accurate suggestions. All right, friends, that's
suggestions. All right, friends, that's it. I hope that you enjoyed this felt
it. I hope that you enjoyed this felt course and I'm going to catch you in the
course and I'm going to catch you in the next one. Peace.
Click on any text or timestamp to jump to that moment in the video
Share:
Most transcripts ready in under 5 seconds
One-Click Copy125+ LanguagesSearch ContentJump to Timestamps
Paste YouTube URL
Enter any YouTube video link to get the full transcript
Transcript Extraction Form
Most transcripts ready in under 5 seconds
Get Our Chrome Extension
Get transcripts instantly without leaving YouTube. Install our Chrome extension for one-click access to any video's transcript directly on the watch page.
Works with YouTube, Coursera, Udemy and more educational platforms
Get Instant Transcripts: Just Edit the Domain in Your Address Bar!
YouTube
←
→
↻
https://www.youtube.com/watch?v=UF8uR6Z6KLc
YoutubeToText
←
→
↻
https://youtubetotext.net/watch?v=UF8uR6Z6KLc