0.6.28 • Published 2 years ago

nova-frontend v0.6.28

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Nova

An alternative lightweight Front-End Library

What is Nova?

Nova is an alternative to all those gigantic front-end frameworks, that often do more than is necessary when it comes to building simple UIs. Pure Vanilla Javascript is performance-wise the best way to build your front-end in a SPA, but it can be hard to organize it properly and as the project grows, it might end up very messy. This is where Nova comes in, being a lightweight library packed with functionality for creating and structuring UIs more easily.

Features

Nova comes with most of the needed built-in features for handling a single-page application. Features like easily generating html, routing and state-management.

Nova is built solely on classes which are a perfect fit to handle context by storing the temporary data in a few places as possible. The topics that are necessary to understand are:

  • Elements
  • Components
  • The Generator
  • Groups
  • State
  • Router

API

Classes

Component

Kind: global class

new Component()

The component is a wrapper for Elements. A component is basically a block of Elements. The best way to create a Component is to use the Generator. You can also supply it with an array of Elements.

Example

import { Generator } from 'nova';
const generator = new Generator();
const header = generator.createTree(`
  header className: 'header'
    h1 className: 'header__title' innerText: 'Hello World!'
    h2 className: 'header__subtitle' innerText: 'This is my site.'
end`)

header.render(); //header is the component

component.elements ⇒ ArrayOfElements

Kind: instance property of Component

component.setProps(propsObject) ⇒ void

Set props of a generated component using Generator. When generating the component, you need to put the value where you want to set the props as '{{whatever}}'. Then when supplying the propsObject to the setProps function, you set the value by { whatever: your-value }

Kind: instance method of Component

ParamType
propsObjectObject

Example

const task = generator.createTree(`
article className: 'task' id: '{{id}}'
  h2 className: 'task__title' innerText: '{{title}}'
  p className: 'task__description' innerText: '{{description}}'
  button className: 'task__remove-button' innerText: 'X'
 end`)

 task.setProps({
 id: 1, 
 title: 'Buy Milk', 
 description: 'With chocolate taste',
})

component.setState(state) ⇒ void

A clever way to set state directly to elements properties using Generator. It works similarily to setProps but with some modifications. To fully understand how this function works, it's recommended to read the docs about State and Generator first. When generating the component like setProps, you need to put the value where you want to set the state as '{{workerName.whateverProp}}' note the DOT '.'.

When supplying the initial state to State, you should supply it as an object with the key name of the worker with the preferred value, f.e { whateverWorker: { whateverField: 'whateverValue' }} (See example below for clarification). The field is the name you supply when generating the elements (Check generator example below for clarification).

The worker needs to return an object with all fields specified in the generator, else it will replace the state with undefined. Everytime the worker returns the object with the specified field, it will automatically update the value you supplied in the generator.

This method is very useful when you want the state to be managed by the library instead of supplying custom functions to update the text.

NOTE: The following example below is not using the intended project structure used for state, and should preferable be splitted into different files, but it's just a simple demonstration of how setState works.

Kind: instance method of Component

ParamType
stateObject

Example

const whateverWorker = (state, action) => {
 switch (action.type) {
   case 'WHATEVER_ACTION':
 return { whateverText: state[action.field] + action.appendText };
 default:
   return state;
 }
};

const initState = { whateverWorker: { whateverText: 'yo' } };
const workers = State.mergeWorkers({ whateverWorker });
const state = new State(workers, initState);
state.createAction('whateverAction', { type: 'WHATEVER_ACTION' });

const generator = new Generator();
const header = generator.createTree(`
 header
   div
     h1 innerText: '{{whateverWorker.whateverText}}'
end`);

header.setState(state);
state.subscribe(header);

//Gets the div as in the order supplied to generator
header.elements[1].addEventListener('click', () => {
 state.dispatch(state.getAction('whateverAction', { appendText: 'HELLO', field: 'whateverText' }));
})

header.render();

component.retrieve(input) ⇒ Element

A fluid function that returns the elements searched for in a component based on id, class or tag. It checks for # to find a id and in taht case returns the element directly. For tags and classes, it will always return an array of the found elements.

Kind: instance method of Component

ParamType
inputString

Example

const header = generator.createTree(`
 div id: 'hello'
   h1 innerText: 'Yo!'
 div
   h2 innerText: 'Welcome.' 
end`)

const divWithIdHello = header.retrieve('#hello')
const bothDivs = header.retrieve('div');

component.changeParent(newParent)

Changes the components grandparent to another element supplied.

Kind: instance method of Component

ParamType
newParentElement

Example

const generator = new Generator();

  const aNewParent = new Element('article', root, {}, true);

  const header = generator.createTree(`
    div id: 'grandparent'
      h1 innerText: 'Welcome!'
      div
        h2 innerText: 'To my page...'
        div 
        div
  end`)

  header.changeParent(aNewParent);
  header.render();

component.render()

Calls node.appendChild for every node inside the elements of the component.

Kind: instance method of Component

component.unrender()

Calls node.removeChild for every node inside the elements of the component.

Kind: instance method of Component

component.deleteByIndex(index)

Discards element inside component based on index, either from array supplied or the order from generator.createTree. Calling this before render has undefined behavior. Note that index 0 will remove the whole component.

Kind: instance method of Component

ParamType
indexNumber

component.deleteById(id)

Deletes element based on ID, doesn't need any #. Else the same applies to this function as deleteByIndex.

Kind: instance method of Component

ParamType
idString

Element

Kind: global class

new Element(type, parent, elementObject, init)

The fundamental building block in Nova is the Element, which most other things in the library are built upon. The element is just a shell of the normal javascript node but adds extra functionality and shorter syntax to access and manipulate a node.

Returns: void

ParamTypeDescription
typestringAn htmlTag, for example 'div' or 'button'.
parentElement | nodeThe parent in the DOM you want the element to belong to.
elementObjectobjectAn object containing the javascript props like: { innerText: 'helo' }
initbooleanA boolean to indicate if you want to render the element now (default: false).

Example

import { Element, root } from 'nova';
const h1 = new Element('h1', root, { innerText: 'Hello World' }, true);

element.node ⇒ node

Return the node of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { innerText: 'Hello World' }, true);
console.log(h1.node) //returns node

element.type ⇒ type

Return the type of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { innerText: 'Hello World' }, true);
console.log(h1.type) //returns 'h1'

element.parent ⇒ parent

Return the parent of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { innerText: 'Hello World' }, true);
console.log(h1.parent) //returns node of root

element.value ⇒ value

Return the value of the element

Kind: instance property of Element
Example

const input = new Element('input', root, { type: 'text', value: 'some text' }, true);
console.log(h1.value) //returns 'some text'

element.id ⇒ id

Return the id of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { id: 'title', innerText: 'Welcome!' }, true);
console.log(h1.id) //returns 'title'

element.text ⇒ text

Return the text of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { id: 'title', innerText: 'Welcome!' }, true);
console.log(h1.text) //returns 'Welcome!'

element.html ⇒ html

Return the innerHTML of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { id: 'title', innerText: 'Welcome!' }, true);
console.log(h1.html) //returns '<h1 id="title">Welcome!</h1>'

element.siblings ⇒ nodeArray

Return the siblings of the element

Kind: instance property of Element
Example

const h1 = new Element('h1', root, { id: 'title', innerText: 'Welcome,' }, true);
const h2 = new Element('h2', root, { id: 'subtitle', innerText: 'To an awesome page!' }, true);
console.log(h1.siblings) //returns a nodeArray of h1 and h2.

element.updateNode(elementObject) ⇒ void

Dynamically updates the element by passing an object containing the props you want to update

Kind: instance method of Element

ParamTypeDescription
elementObjectobjectAn object containing the javascript props like: { innerText: 'helo' }

Example

const h1 = new Element('h1', root, { id: 'welcome', innerText: 'Hello World!' }, true);
h1.updateNode({ id: 'goodbye', innerText: 'Goodbye World...' })

element.toggleNode() ⇒ void

Toggles node on and off

Kind: instance method of Element
Example

const h1 = new Element('h1', root, { id: 'welcome', innerText: 'Hello World!' }, true); //On with true
h1.toggleNode() //Off
h1.toggleNode() //On

element.addNode() ⇒ void

Appends node to parent.

Kind: instance method of Element
Example

const h1 = new Element('h1', root, { id: 'welcome', innerText: 'Hello World!' }); //Off
h1.addNode() //On

element.removeNode() ⇒ void

Removes node from parent.

Kind: instance method of Element
Example

const h1 = new Element('h1', root, { id: 'welcome', innerText: 'Hello World!'}, true); //On
h1.removeNode() //Off

element.changeParent(newParentNode) ⇒ void

Appends node to new parent.

Kind: instance method of Element

ParamType
newParentNodeElement | node

Example

const div = new Element('div', root, { className: 'container' }, true);
const h1 = new Element('h1', root, { id: 'welcome', innerText: 'Hello World!'}, true); //Appends to root
h1.changeParent(div); //Now h1 is appended to div instead.

element.addEventListener(event, callback) ⇒ void

Calls addEventListener on node.

Kind: instance method of Element

ParamTypeDescription
eventevent//f.e 'click' Any javascript supported event.
callbackfunctionCallback function to be invoked when event happens.

Example

Check https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

element.addStyle(property, css) ⇒ void

Dynamically adds css styles to Element.

Kind: instance method of Element

ParamTypeDescription
propertystringA string containing what you want to change, for example 'color'
cssstringThe css value to use, for example 'red'

element.createComponent()

Creates a component putting the element inside

Kind: instance method of Element

element.beforeSibling() ⇒ void

Moves node one step up the tree, changing place with it's previous sibling.

Kind: instance method of Element

element.afterSibling() ⇒ void

Moves node one step down the tree, changing place with it's next sibling.

Kind: instance method of Element

element.after(reference) ⇒ void

Appends node after a reference sibling

Kind: instance method of Element

ParamType
referenceElement

element.before(reference) ⇒ void

Appends node before a reference sibling

Kind: instance method of Element

ParamType
referenceElement

Generator

Kind: global class

new Generator()

The generator is a powerful way to generate HTML without writing actual HTML! It's meant to be very straightforward and to give your SPA a nice structure. No more angle brackets!

Example

import { Generator } from 'nova';
const generator = new Generator();
const header = generator.createTree(`
  header className: 'header'
    h1 className: 'header__title' innerText: 'Hello World!'
    h2 className: 'header__subtitle' innerText: 'This is my site.'
end`)

header.render();

generator.createTree(input) ⇒ Component

'createTree' is the method you can use to generate HTML stored in a Component as Elements. The string has to be in a certain format where indentations are very important. Indentations are what dictates if an element is a parent/child. Always use even indentations, 2 spaces per child. The structure is always the same: [indentation][htmlTag][property]: '[value]'. Note that you need to to use only one grandparent for all the element generated, else it will throw an error!. like:

Kind: instance method of Generator

ParamType
inputstring

Example

`  h1 innerText: 'helo'`
Valid properties are for specific a htmlTag. For example, you can use 'type' on 'input' but not on 'h1'

Example

` form
    input type: 'text'
end`

Indentation dictates children/parent

Example

`
  div className: 'grandparent'
    main className: 'parent'
      p className: 'child' innerText: 'I am a child of main'    
end`  

Always end the string on a new line with the word 'end'
 
Full example

Example

import { Generator } from 'nova';
const generator = new Generator();
const header = generator.createTree(`
  header className: 'header'
    h1 className: 'header__title' innerText: 'Hello World!'
    h2 className: 'header__subtitle' innerText: 'This is my site.'
    nav id: 'menu'
      ul className: 'menu__items'
        li innerText: 'First item'
        li innerText: 'Second item'
  end`)

Group

Kind: global class

new Group(arrayOfComponents, parent)

A group is a wrapper for components where it's possible to do bulk operations. This is very usefuly when you want a group of components to have the same parent. In a situation where you want to append new components, for example in a todo-list, it's highly recommended to wrap them all in a group so they share the same grandparent.

ParamTypeDescription
arrayOfComponentsArray.<Components>An array of components, every element will be automatically converted to a component.
parentElementElement used to wrap the components, changing the grandparent node.

Example

const taskOne = generator.createTree(`
 ...
`)

const taskTwo = ...


const taskWrapper = new Element('section', root, { className: 'task-wrapper' });
const tasks = new Group([taskOne, taskTwo], taskWrapper);
tasks.render();

group.components ⇒ Array.<Component>

Returns an array of components

Kind: instance property of Group

group.render()

Calls render on all Components inside Group. Same as Component.render().

Kind: instance method of Group

group.add(component)

Adds a new component to the group dynamically. This also has the effect of assigning the wrapper grandparent to the added component. Very useful when you are adding new components dynamically to the DOM, like more todos in a list.

Kind: instance method of Group

ParamType
componentComponent

group.update(arrayOfComponents)

Replaces the components in the group with a new array of components.

Kind: instance method of Group

ParamType
arrayOfComponentsArray.<Component>

group.unrender()

Calls unrender on all components. Same as Component.unrender().

Kind: instance method of Group

group.retrieve(id) ⇒ Array.<elements>

Retrieve a component in a group. At the moment only supports ids.

Kind: instance method of Group

ParamType
idString

group.deleteById(id)

Deletes a component in a group by id.

Kind: instance method of Group

ParamType
idString

Router

Kind: global class

new Router(path, componentArray)

To get the full SPA feel the router is here for rendering different groups or components based on the url.

ParamTypeDescription
pathStringThe path bound to this route. All components applied will be rendered only when the URI is the same.
componentArrayArray.<Components>Array of components. If you want to supply an element you can do Element.createComponent();

Example

import { Router, Group, Element, Generator, root } from '../../';

 const wrapper = new Element('div', root, { id: 'wrapper' }, true);

 const generator = new Generator;
 const component = generator.createTree(`
   div
     h1 innerText: 'Router example.'
     button innerText: 'Click it'
 end`)

 component.retrieve('button')[0].addEventListener('click', () => {
   Router.changePath('/about');
 })

 const about = new Element('h1', root, { innerText: 'Hello there!'}).createComponent();
 const group = new Group([component], wrapper);

 new Router('/', [group])
 new Router('/about', [about]);

Router.getPath() ⇒

Returns current url path

Kind: static method of Router
Returns: current path

Router.changePath(newPath)

A static mathod that uses history.pushState to set new url location.

Kind: static method of Router

ParamType
newPathString

Example

Router.newPath('/contact');

State

Kind: global class

new State()

State management system for Nova. Heavily inspired by Redux with a similar system but in a way, more compact.

Example

const whateverWorker = (state, action) => {
 switch (action.type) {
   case 'WHATEVER_ACTION':
     return { whateverText: state[action.field] + action.appendText };
     default:
   return state;
 }
};

const initState = { whateverWorker: { whateverText: 'yo' } };
const workers = State.mergeWorkers({ whateverWorker });
const state = new State(workers, initState);
state.createAction('whateverAction', { type: 'WHATEVER_ACTION' });

const generator = new Generator();
const header = generator.createTree(`
 header
   div
     h1 innerText: '{{whateverWorker.whateverText}}'
end`);

header.setState(state);
state.subscribe(header);

//Gets the div as in the order supplied to generator
header.elements[1].addEventListener('click', () => {
 state.dispatch(state.getAction('whateverAction', { appendText: 'HELLO', field: 'whateverText' }));
})

state.getState() ⇒ Object

Returns the state object.

Kind: instance method of State
Returns: Object - state object
Example

const initState = { whateverWorker: { title: 'Yo!', desc: 'Hello there...' } };
const state = new State(workers, init);

const whateverWorkerState = state.getState().whateverWorker;

state.createAction(name, deps)

Creates the action for the worker, which you can access from the action argument in the callback. The name supplied as the first argument needs to be unique for every action.

Kind: instance method of State

ParamTypeDescription
nameStringunique name for action.
depsObjectobject containing prop "type".

Example

state.createAction('actionName', { type: 'ACTION' })

state.getAction(name, deps) ⇒ Objectt

This function is used to set new dependencies to a specific action. Prefarably called together with dispatch as the argument. The dependency can contain an optional property for use when setting up state together with "setState". See Component for more info regarding the optional property.

Kind: instance method of State
Returns: Objectt - - returns the dependencies.

ParamTypeDescription
nameStringthe name of the action.
depsObjectthe dependencies that will be accessible through the action argument in the worker.

Example

state.dispatch(state.getAction('actionName', { someText: 'helo', optionalProperty: 'title' })); 

state.subscribe(listener) ⇒ function

The subscribe function takes 3 different listeners as an argument. If you use "setState" together with a component, you will supply the component as the argument. Generelly when not using "setState", you want to supply an object with the action type and function. This will make sure that the function only gets called when the specific action is set, see example. If you supply a function directly, that one will get called every time you use dispatch, which is generelly unnecessary.

Kind: instance method of State
Returns: function - . unsubscribe function, call it to remove listener.

ParamType
listenerComponent | Object | function

Example

state.subscribe(header); //Component
state.subscribe({ type: 'TASK_ADD', func: addTask }); //Only called when "TASK_ADD" is dispatched.
state.subscribe(addTask); //Called every dispatch.

state.dispatch(action)

Dispatch is what you call to update state. It's preferable to call it together with "getAction". It first calls the worker to get the state and modifications. Then it will call the listener you supplied with subscribe. How it will call the listener depends on what type of listener you called subscribe with.

Kind: instance method of State

ParamTypeDescription
actionObjectthe dependencies supplied, see "getAction".

Example

state.dispatch(state.getAction('actionName', { someText: 'helo', optionalProperty: 'title' })); 

State.mergeWorkers(workers) ⇒ Object

MergeWorkers is a static method that should always be used before supplying workers to state initialization.

Kind: static method of State
Returns: Object - state object

ParamTypeDescription
workersObjecttakes and object that have the function as a key-value pair with same name

Example

const exampleWorkerOne = (state, action) => {
  switch(action.type) {
    case 'ACTION': 
     return state.someText + 'hello again!';
    default:
      return state;
  }
}

const exampleWorkerTwo = (state, action) => {
 ...
}

const initState = { exampleWorkerOne: { someText: 'hello, '}, exampleWorkerTwo: ... } 
const workers = State.mergeWorkers({ exampleWorkerOne, exampleWorkerTwo });
const state = new State(workers, initState);
0.5.94

2 years ago

0.5.93

2 years ago

0.6.28

2 years ago

0.6.25

2 years ago

0.6.27

2 years ago

0.6.26

2 years ago

0.6.2

2 years ago

0.6.1

2 years ago

0.6.0

2 years ago

0.5.8

2 years ago

0.5.7

2 years ago

0.5.92

2 years ago

0.5.81

2 years ago

0.5.9

2 years ago

0.5.4

2 years ago

0.5.91

2 years ago

0.5.3

2 years ago

0.5.6

2 years ago

0.5.5

2 years ago

0.5.2

2 years ago

0.5.1

2 years ago

0.4.21

2 years ago

0.4.2

2 years ago

0.4.1

2 years ago