Class driven component framework
classcaps
is a framework for creating UI Component based on HTML classes.
classcaps
encourages the use of MVP design pattern. Components work as Presenter and Dom Elements work as (Passive) View of MVP. See the below for details.
classcaps
doesn't encourage the use of virtual dom for updating the dom tree, rather it recommends updating dom using native DOM API.
Features
- It's an UI framework.
- Works well with real DOM APIs. Plays nice with
jQuery
orUmbrella
. - no virtual dom, no template, no rendering
- small APIs: 5 apis & 4 decorators
- small size: 1.2KB gzipped
The timer
The timer example:
timer.js:
See the working demo.
The concept
A class-component
(or classcaps component) is a combination of element
and coelement
:
where:
element
is the usual dom element.<span class="timer"></span>
in the timer example
coelement
is JavaScript class which defines the behaviour of the special functions of the class-component.class Timer {...}
in the timer example.
classcaps
is responsible for the transition from the usual dom to a class-component
.
Register your class-component
You can register the class-component of the given name like this:
cc
By the above call, dom elements which have class="component-name"
are automatically initialized with ComponentClass.
What happens when a class-component is initialized
The followings are exact steps when a class-component is initialized.
const coelem = // The constructor is called with the element. // Sets the element to the coelementcoelemel = el // Adds event listenersel // for each event/listener pair // Adds initialized markelclassList // The element is marked `initialized`. el'__coelement:' + componentName = coelem // The coelement is stored in the element.
where el
is the dom element which is initialized, ComponentClass
is the registered coelement class and componentName
is the registered component name.
this.el
this.el
is HTMLElement which is associated with the coelement.
💿 Install
Via npm
npm install --save classcaps
then:
const cc =
Via file
Download classcaps.min.js Then:
APIs
const cc =
cc.def(name, constructor)
- Registers class-component.
cc.init(name[, element])
- Initializes class-component on the range.
cc.el(name, element)
- Initializes the element with the class-component of the given name.
cc.get(name, element)
- Gets the coelement instance from the given element.
$dom.cc(name)
- Initializes the element as class-component.
$dom.cc.get(name)
- Gets the coelement of the element.
$dom.cc.init(name)
deprecated- Initializes the element as a class-component.
cc
namespace
cc.def(name, constructor)
- @param {string} name The class name of the component
- @param {Function} constructor The constructor of the coelement of the component
This registers constructor
as the constructor of the coelement of the class component of the given name name
. The constructor is called with a jQuery object of the dom as the first parameter and the instance of the coelement is attached to the dom. The instance of coelement can be obtained by calling elem.cc.get(name)
.
Example:
// ...behaviours... cc
cc.init([name], [element])
- @param {string} [name] The class-component name to intialize
- @param {HTMLElement} [element] The range to initialize
This initializes the class components of the given name in the given element. If the element is omitted, it initializes them in the entire page. If the name is omitted, then it initializes all the registered class components.
cc.el(name, element)
- @param {string} name The class-component name to initialize
- @param {HTMLElement} element The element to initialize
Initializes the element as the class-component.
cc
The above initializes dom
as timer
class-component.
cc.get(name, element)
- @param {string} name The class-component name to get
- @param {HTMLElement} element The element
- @return The coelement instance
Gets the coelement instance from the element.
const timer = cc
The above gets Timer
class instance (coelement) from dom. In this case, dom need to be initialized as timer
class-component before this call.
$dom.cc
namespace
These APIs are available via jQuery selection object's .cc
property like $('<div />').cc('timer')
or $('#main').cc.get('app')
.
$dom.cc(name)
- @param {string} name The class-component name to initialize
- @return {jQuery}
This initializes the class-compenents of the given name on the element and returns the element itself.
The above example creates a div
element, initializes it as timer
and modal
class components, and appends it to the body.
$dom.cc()
This initializes all the class component on the element which it already has. This returns the the element (jquery-wrapped) itself.
Example:
The above example is the same as the previous one.
Example:
const div = classes div
The above example creates a div
element and initializes all the classes in classes
variable on in.
$dom.cc.get(name)
- @param {string} name The class name of the component
This gets the coelement of the component of the given name if exists. It throws if none.
const todoItem = $domcc; todoItem;
$dom.cc.init(name)
(deprecated)
This initializes the $dom as a class component of the given name. It throws an error if the class component of the given name isn't available.
This returns the instance of class-component class, not a dom element itself. If you want to get the dom element (jquery wrapped), use $.fn.cc.up(classNames)
- @param {string} name - The class name of the component
// Creates `todo-app` in #maincc
In the above example, <div>
is appended and it is initialized as todo-app
class-component. (todo-app
class is automcatically added)
Decorators
There are 4 decorators.
@component
- optionally
@component(name)
- optionally
@on(event, {at})
@emit(event)
- optionally
@emit.last(event)
- optionally
@wire
- optionally
@wire(name, [selector])
- optionally
@component(className)
cc.component(className) is class decorator. With this decorator, you can regiter the js class as class component.
This is a shorthand of $.cc('component', Component)
.
const component = cc @ ...definitions...
The above registers Timer
class as timer
component.
@component
cc.component is similar to the above. This decorator registers the js class as the class component of the same name. If the js class is in CamelCase
, then the component name is made kebab-cased
.
const component = cc @component {} // This registers Timer class as `timer` component @component {} // This registers FooBar class as `foo-bar` component
@on(eventName)
cc.on
is a method decorator. With this decorator, you can register the method as the event handler of the element.
const on = cc @ { ...definitions... } cc
The above binds onClick
method to its element's 'click' event automatically.
The above is equivalent of:
{ thisel } { ...definitions... } cc
@on(name, { at: selector })
cc.on(name, { at: selector })
is a method decorator. It's similar to cc.on
, but it only handles the event from selector
in the component.
const on = cc @ { ...definitions... } cc
In the above example, onBtnClick
method listens to the click event of the .btn
element in the Btn
's element.
@emit(startEvent)
cc.emit()
is a method decorator. This decorator makes the method trigger the given event at the start of the method. The first parameter of the method is passed as event.detail object.
const emit = cc @ { ...definitions... } cc
The above start
method automatically triggers manager.started
event at the begining of the method process.
The above is equivalent of:
{ this$el ...definitions... } cc
@emit.last(eventName)
cc.emit.last(eventName)
is similar to cc.emit()
, but it triggers the event at the last of the method.
const emit = cc @emit { ...definitions... } cc
In the above example, start
method triggers the manager.ended
event when it finished. The returns value of the method is passed as the second arguments of the event handler.
If the method returns a promise, then the event is triggered after the promise is resolved.
const emit = cc @emit { ...definitions... return promise } cc
In the above example, manager.ended
event is triggered after promise
is resolved. The resolved value of the promise is passed as the second argument of the event handler.
@wire
@wire
is a getter decorator. If a getter is decorated by this, it returns the class component of the name of the decorated method.
const wire component = @component @wire {} { thisbar } @component { console }
In the above situation, the getter bar
of Foo class is wired to bar
component inside the foo component. Technically accessing bar
property almost equals to the call of this.$el.find('.bar').cc.get('bar')
. With the above settings you can call the following:
cc
And the above prints processing bar!
.
When the decorated getter name is in CamelCase
, then it's replaced by the kebab-cased
version. For example, the expression @wire get primaryButton
wires to primary-button
component, not to primaryButton
component. If you need to wire it to primaryButton
component, then use the one below.
@wire(className)
This is also a getter decorator. The difference is that @wire(className)
specify the wired class component name explicitly (className
).
const wire component = @component @ {} @component { console }
With the above settings, you can call the following:
ccit
And this prints processing long name component
.
@wire
and @wire(name)
decorators are convenient when you nest the class components and parents ask children do the jobs.
License
MIT
History
- 2017-01-17 v0.1.1 Rename to classcaps. Add plugin system.
History of class-component.js (former project)
- 2017-01-02 v13.0.0 Add init instead of init.
- 2017-01-01 v12.1.1 Fix bug of event bubbling.
- 2017-01-01 v12.1.0 Remove @emit.first. Use native dispatchEvent.
- 2016-12-31 v12.0.0 Remove cc_init feature. Add init feature.
- 2016-09-30 v10.7.1 Refactor @emit.last decorator
- 2016-09-11 v10.7.0 Add @on(event, {at}) @emit.first and @emit.last
- 2016-08-22 v10.6.2 Refactor the entrypoint.
- 2016-08-22 v10.6.1 Improved the event listener registration process.
- 2016-08-20 v10.6.0 Cleaned up some private APIs.
- 2016-08-20 v10.5.0 Cleaned up codebase and made the bundle smaller. Remove some private APIs.
- 2016-08-17 v10.4.1 Made built version smaller.
- 2016-08-16 v10.4.0 Switched to babel-preset-es2015-loose.
- 2016-08-16 v10.3.0 Modified bare @wire decorator.
- 2016-08-02 v10.2.0 Added bare @component decorator.
- 2016-07-21 v10.1.0 Added @wire decorator.
- 2016-06-19 v10.0.0 Removed deprecated decorators
@event
and@trigger
, use@on
and@emit
instead. - 2016-06-09 v9.2.0 Fixed bug of
@emit().last
decorator.
The user projects
The projects which uses class-component.js.
- class-component-todomvc
- Implementation of TodoMVC in class-component.js, 100% unit tested
- multiflip
- multiflip-bubble
- puncher
- event-hub
- spn
- view-todo
- long-dream
- The Long Dream is the first user and absolute inspiration of classcaps
- classcaps is basically created for developing this project.
Notes
The name
classcaps = class + capsule.
Why 'coelement'
co-
means the dual or the other aspect of something like cosine
to sine
cotangent
to tangent
etc. Coelement is the other aspect of element
and it works together in the 1-to-1 relationship and in the same lifecycle with the element.