@flux-js/core
v1.0.5
Published
FluxJS is a JavaScript component framework written in TypeScript. It was built with performance in mind, and allows you to create beautiful UI with ease!
Downloads
4
Readme
FluxJS Component API
FluxJS is a JavaScript component
framework written in TypeScript
. It was built
with performance in mind, and allows you to create beautiful UI
with ease!
Sections
- Creating an FluxJS Application
- Root Component
- Mounting the App
- Loading External Libraries
- Component Template Files
- Imports in Template Files
- Routing
- HTML Interpolation
- Registering Children Components
- Passing Props
- Slots
- Declaring Reactive State
- List Rendering
Creating an FluxJS Application
Every FluxJS application starts by creating a new App Instance
with the createApp
method:
// import
import { createApp } from "@flux-js/core";
// initialization
await createApp(/* root component */, /* render element */)
Note*
unfortunately there is no way (at the moment) to have multipleinstances
of an FluxJS application running in oneDOM
Root Component
The root
component is just a component which contains other children. How do we get/import
a component to pass to createApp
?
// import
import { createApp, Component } from "@flux-js/core";
// component
const App = Component(/* component name */, /* template file */)
// initialization
await createApp(/* root component */, /* render element */)
As you see in the example above, we just use the Component
method that is exposed to
you from the FluxJS import
. This method will fetch your template component file, and
convert it into a usable component which can now be passed to the createApp
function.
Mounting the App
As you can see the createApp
method's second argument expects a "container" argument.
This needs to be an actual DOM element.
// import
import { createApp, Component } from "@flux-js/core";
// component
const App = Component('App', './App.html')
// initialization
await createApp(App, document.querySelector('#app'))
Loading External Libraries
Flux-js exports a method called Use
. This allows you to load any external
libraries into flux-js.
// imports
import { Use } from '@flux-js/core'
// other library
const library = {/***/}
// load into flux-js
Use("key", library)
To get your loaded items out from flux-js, you can use the Import
method.
// imports
import { Import } from '@flux-js/core'
// get from flux-js
const value = Import("key")
const nestedVal = Import("key/nestedVal")
Component Template Files
FluxJS component templates
are HTML files which will represent a component in a
readable way. It allows us to encapsulate the template, logic, and styling of an FluxJS
component in a single file.
<script>
// imports
const { Setup } = Import("@flux-js")
// onMounted
await Setup('App', async (context) => {
// variables
const heading = "Hello World"
const object = {foo: 'bar'}
// expose to template below
return { heading, object }
})
</script>
<template>
<h1>{ heading }</h1>
<h1>{ object.foo }</h1>
</template>
<style>
.heading {
color: red;
font-weight: bold;
}
</style>
As we can see, FluxJS component templates
are a natural extension of the classic trio of HTML,
CSS and JavaScript. The <template>
, <script>
, and <style>
blocks encapsulate and colocate the view,
logic and styling of a component in the same file.
Imports in Template Files
Native JavaScript
imports will not work properly inside of template files
. Instead, you will need to use
the exported Import
method (with the @flux-js
namespace) to get access to flux-js exports eg: (Setup
, Component
, Reactive
)
Note*
the 'Import' method isglobally
accessible inside the script tags
<script>
// get all exports
const { Setup, Component, Reactive } = Import('@flux-js')
// only import specific export
const method = Import('@flux-js/Setup')
</script>
Routing
In order to have multiple root
components (Main pages in your application) you
will need to incorporate the Router
.
import { router } from "@flux-js/core"
// @ts-ignore
export const $router = new router([
{ path: '/', name: 'App', component: './App.html' },
{ path: '/about-us', name: 'AboutUs', component: './AboutUs.html' },
{ path: '/contact-us', name: 'ContactUs', component: './ContactUs.html' },
])
As you can see above, each route has 3 main properties: (path
, name
, component
).
The path
property is the url needed to be requested for the component to mount. The
name
property is the name you registered
the component with in the Setup
method.
And lastly, the component
property is the directory/url to the component template
.
HTML Interpolation
The most basic form of data binding is html interpolation
using the Mustache
syntax (single curly braces):
// template
<p> Message: { msg }</p>
The mustache tag will be replaced with the value of the msg property from the corresponding component exposed data. It will also be updated whenever the msg property changes.
Registering Children Components
To use a child component, we need to import it in the parent component.
Assuming we created a component template
called ButtonCounter.html
, we
now need to use the Component
method exported to you by FluxJS.
<script>
// imports
const { Setup, Component } = Import("@flux-js")
// import child
await Component('ButtonCounter', './ButtonCounter.html')
// onMounted
await Setup('App', async (context) => {/* parent logic */})
</script>
<template>
<!-- child component -->
<ButtonCounter></ButtonCounter>
</template>
Note*
TheComponent
method will import on aframework
level. Meaning if you have already imported a child, you no longer need to reference an import for that child inside other component/children.
Passing Props
In FluxJS you are able to pass data between a Parent
& Child
component. This
will allow for multiple uses of a component, but different data for each one. To pass a prop
to a child
component, we must add an attribute
to the component Element
, prefixed
with a #
.
<template>
<!-- child component -->
<ButtonCounter #foo="bar" #hello="world"></ButtonCounter>
</template>
In the example above you can see 2
props being passed to our ButtonCounter
component.
These are just String
values though. So how would we pass a defined variable from the logic?
<script>
// import libraries
const { Setup, Component } = Import("@flux-js")
// import child
await Component('ButtonCounter', './ButtonCounter.html')
// onMounted
await Setup('App', async (context) => {
const items = []
const click = () => console.log("I was clicked")
const user = {firstname: 'John', lastname: 'Doe'}
return {
customVariable: 'Hello World',
items,
click,
user
}
})
</script>
<template>
<!-- child component -->
<ButtonCounter
#user.firstname
#customVariable
#items
#click
></ButtonCounter>
</template>
As you can see above, we first define the variable
and return it from the component
logic
. Then we define the prop on the child the same as before, only we don't need
to assign a value
to the prop.
Accessing props passed to a child
component is as easy as pulling them out of the
context
object passed to every component.
await Setup('App', async (context) => {
const { props } = context
})
Slots
In some cases, we may want to pass a template fragment to a child component,
and let the child component render the fragment within its own template. For
example, we may have a <FancyButton>
component that supports usage like this:
<FancyButton>
Click me! <!-- slot content -->
</FancyButton>
The template of looks like this:
<button class="fancy-btn">
<slot></slot> <!-- slot outlet -->
</button>
The <slot>
element is a slot outlet that indicates where the parent-provided
slot content should be rendered.
Note*
You can only haveone
slot element per component.
Declaring Reactive State
In some instances you will want to create some piece of reactive data which is displayed to the user and
whenever the property is updated
, the value shown to the user is changed
too. This is where Reactive()
comes into play.
<script>
// import
const { Setup, Reactive } = Import("@flux-js")
// onMounted
await Setup('App', async (context) => {
// primitives
const string = Reactive("foo") // { value: 'foo' }
const number = Reactive(0) // { value: 0 }
// objects
const user = Reactive({ name: 'John', age: 21 }) // { name: 'John', age: 21 }
// expose properties to the template
return { string, number, user }
})
</script>
As you can see in the example above, we declare a few variables as reactive properties. The properties can now be used in the template and will keep up to date with the latest changes to said property.
<template>
<p>String Value: { string.value }</p>
<p>Number Value: { number.value }</p>
<p>Object Value: { user.name } - { user.age }</p>
</template>
Turns into
<template>
<p>String Value: foo</p>
<p>Number Value: 0</p>
<p>Object Value: John - 21</p>
</template>
List Rendering
We can use the @for
directive to render a list of items in an array.
The directive uses a special syntax in the form of item in items
,
where item
is the alias for the array element and items
is the Array.
const items = [ { label: 'Foo' }, { label: 'Bar' } ]
<li @for="item in items">{ item.label }</li>
1. Foo
2. Bar
As you can see in the example above, the element gets scope to what item
is
during the render of the <li>
.
Adding an event to the element is as easy as just using the default syntax in HTML
.
<li @for="item in items" onclick="item.action()">{ item.label }</li>
List Component Rendering
The @for
directive can also be placed on a child
component. This will template
the registration
of a child, allowing you to pass data as props directly from the Array
. Lets take a look
at an example below.
await Setup('App', async (context) => {
const cards = [
{ header: 'Card 1', content: 'This is for card 1' },
{ header: 'Card 2', content: 'This is for card 2' },
]
return { cards }
})
<!--
Passing a direct reference of (header, content)
to the Card component as props
-->
<Card
@for="card in cards"
#card.header
#card.content
></Card>