Simple

A very Simple front-end ibrary

Usage no npm install needed!

<script type="module">
  import Simple from 'https://cdn.skypack.dev/Simple';
</script>

README

Simple

Under Development. Fast Release Cycle on NPM. API might change
created by Yiyi Wang (shd101wyy)

Introduction

Simple is a very Simple front-end library without any extra dependencies.
It is extremely small and blazingly fast (maybe).
The idea of this library is from React and Atom Editor space-pen

let Demo = Simple.Component(function(message) {
  return this.div(message)
})

Simple.render(Demo('Hello World'), document.getElementById('app'))

Component

View contains many Components

How Simple View Layer Works

Core of Simple mainly consists of 3 parts:

Component <= SimpleDOM <= SimpleElement
  • SimpleElement
    Low level abstraction for fast DOM manipulation.
    You can regard SimpleElement as a kind of Virtual DOM, which helps improve DOM rendering speed.
  • SimpleDOM
    Many native DOM element such as div, button, p SimpleElement are already wrapped by SimpleDOM for you.
    It offers many basic prototype functions such as getDefaultProps, etc.
  • Component
    Inherited from SimpleDOM, Component is user-defined and highly flexible.

Component Lifecycle

  1. init()
    Invoked only once before the element is rendered. You should put all your initialization here.

  2. mount()
    Invoked only once immediately after the element is rendered.

  3. update()
    Invoked every time when state or props is updated or forceUpdate is called.
    Invoked immediately after the element is done with updating rendering.
    This is not called for the initial render.

  4. unmount()
    Invoked immediately right before a component is unmounted from the DOM.

Use wrapped native DOM elements

<div> Hello World </div>

<div class="my-div"> This is my div </div>

<div style="background-color: #454545">
  <h1 style="font-size: 48px;"> This is a Heading </h1>
  <p> Very Cool </p>
</div>

Using Simple, we can rewrite that as


this.div('Hello World')

this.div({class: 'my-div'}, 'This is my div')

this.div({style: 'background-color: #454545'},
  this.h1({style: {fontSize: '48px'}}, 'This is a Heading')  // you can also define style as Object
  this.p('Very Cool'))

Basically, it is in the format of

this.tagName([attributes], [...children]) // attributes, children can be omitted

Create your own Component

let MyComponent = Simple.Component({            
    render: function() {               // render function has to be defined.
      return this.div({class: 'my-component'}, 'Hello World')
    }
})

Simple.render(MyComponent(), document.body)

Create Stateless Component

let Greetings = Simple.Component(function(name) {
  return this.div(`Hello ${name}!`)
})

Simple.render(Greetings('Sexy Aaron'), document.body)

Bind Event for Component

Simple supports all native browser events such as click, input, and so on
The example below shows how to bind click event to our button, so that each time we click the button, the p will update its content

let EventComponent = Simple.Component({
  init: function() {
    this.state = {count: 1}
  },
  render: function() {
    return this.div(
              this.p(this.state.count + ' seconds 🐸'),
              this.button({'click': this.onClick.bind(this)}, '+1s'))
  },
  onClick: function() {
    let count = this.state.count
    this.setState({'count': count+1})   // setState function will render the element again
  }
})

Embed Component inside another Component

We can use our defined Component inside another Component
For example:

let TodoItem = Simple.Component(function(todo) {
  return this.div({style: {width: '400px', height: '16px', marginBottom: '6px'}},
            todo)
})

let TodoList = Simple.Component({
  getDefaultProps: function() {
    return {title: 'No title defined',
                        data: ['Too young too simple', 'Sometimes native']}
  },
  render: function() {
    return this.div({class: 'todo-list'},
              this.h2(this.props.title),
              this.props.data.map(todo => TodoItem( todo )))
  }
})

let todoList = TodoList({title: 'My TODO List. (I don\'t like the default one)'})
Simple.render(todoList, document.getElementById('app'))

The rendered result is like below
screen shot 2016-04-18 at 4 15 23 pm

Emitter

Emitter is the Simple library event layer.
Each emitter object should contain a state that is used to store your application data.

How to use Emitter

let emitter = Simple.createEmitter({count: 1})  // define a emitter with initial state

emitter.on('add', function(num) {
    let count = this.state.count // get count that is stored in state
    this.state.count += num      // update count
})

emitter.emit('add', 2)         // emit 'add' event with data '2'
emitter.emit('add', 3)         // ...

emitter.state						 //  => {count: 6}

Combine Component with Emitter

For the most of time, it is not recommended that a Component has state.
Instead, we use a Emitter to store the state and control the Component.

TODO Example using Component and Emitter

let emitter = Simple.createEmitter(function() {
    this.state = {
        todos: ['TODO Item 1', 'TODO Item 2']  // initial state
    }
})
emitter.on('delete-todo', function(offset, component) {
  let todos = this.state.todos
  todos.splice(offset, 1)
  component.setProps({todos})
})

emitter.on('add-todo', function(todo, component) {
  let todos = this.state.todos
  todos.push(todo)
  component.setProps({todos})
})

let TodoItem = Simple.Component({
  render: function() {
    return this.div({style: 'clear: both; padding: 12px;', key: this.props.key},
              this.p({style: 'float: left; margin: 0 24px 0 0; margin-right: 24px;' }, this.props.text),
              this.button({click: this.deleteTodoItem.bind(this)}, 'x'))
  },
  deleteTodoItem: function() {
    this.props.remove(this.props.key)
  },
  unmount: function() {
    console.log('unmount component: ', this.props)
  }
})

let Todo = Simple.Component({
  emitter: emitter,
  getDefaultProps: function() {
    return {todos: this.emitter.state.todos}
  },
  render: function() {
    return this.div({class: 'todo'},
              this.h2({class: 'todo-title'}, this.props.title),
              this.div({class: 'add-item-container'},
                this.input({placeholder: 'add new item here', ref: 'inputBox'}),
                this.button({click: this.clickAddItem.bind(this)}, 'Add Item')),
              this.props.todos.map((d, i) => TodoItem({text: d, 'key': i, remove: this.removeItem.bind(this) })))
  },
  clickAddItem: function() {
    this.emit('add-todo', this.refs.inputBox.value)
  },
  removeItem: function(offset) {
    this.emit('delete-todo', offset)
  }
})

let todo = Todo({title: 'This is TODO'})
Simple.render(todo, document.getElementById('app'))

emitter.emit('add-todo', 'This is new TODO item', todo)  // emitter.emit([name], [data], [component])
// or
todo.emit('add-todo', 'This is another ner TODO item')

With Component and Emitter, we can build well-structured web applications ;)

How to use this library

I haven't published this library on npmjs yet since this library is still under development.
The only way to use this library right now is to download it and include the Simple.js file in html file.

<head>
  <script src="blablabla/Simple.js"> </script>
</head>

Thanks

MIT License
仅以此库祭奠我逝去的青春 eru pusai kongguruu