npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@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

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 multiple instances of an FluxJS application running in one DOM

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 is globally 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* The Component method will import on a framework 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 have one 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>