Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
You love reusable web-components, but googles polymer just doesn't look right to you? Then you have come to the right place.
The aim of CeriJS is to make development and maintenance of custom elements v1 as easy as possible.
I want to use a component built with ceri
I want to build a component with ceri
I want to build a mixin for ceri
Lets face it, the API of your framework of love will change - if its vue, react or angular. Within a single project this is no problem, but as soon as you have several projects with sharing code, maintenance caused by API change can get tedious.
So as a rule of thumb: use ceri if you plan to use your component across projects, if it is a project specific one use the framework of the project and keep it homogenous.
You have to install and use the lightweight custom-element polyfill:
npm install --save-dev document-register-element
then call it somewhere in your app
require("document-register-element/pony")(global,"force")
// force is required for now, as native custom elements requires
// ES6 classes which are not widely supported
Afterwards you can register a component easily:
// the name should contain at least one hyphen
window.customElements.define("ceri-component", require("ceri-component"))
// and create a element programatically
el = document.createElement("ceri-component")
or use it in your markup
<ceri-component></ceri-component>
first have a look at ceri-boilerplate
npm install --save-dev ceri
# main file of your component
ceri = require "ceri"
module.exports = ceri class ComponentName extends HTMLElement
mixins:[
require "ceri/lib/watch"
require "ceri/lib/structure"
]
structure: template 1, """
<div :text="textprop"></div>
<slot></slot>
"""
data: ->
textprop: "someText"
watch:
textprop: -> console.log "textprop changed"
style
attributesAll official reactions of all mixins will be merged into your component, with exception of constructor
.
For setup code use created
instead.
All created
callbacks will be called infront of the first connectedCallback
.
This can be problematic if you want to manipulate the component after creation, but before inserting.
Alternatively you can call all created
callbacks manualy in your constructor:
ceri class SomeClass extends HTMLElement
constructor: ->
super()
@_created = true # so they wont get called again
for fn in @_c2Cb
fn.call(@)
Name | Links | Short description |
---|---|---|
class | doc src | helper functions to interact with element classes |
classes | doc src | manage the classes of your element structure |
combined | doc src | helper function to create a computed property which combines a prop, data and computed obj |
computed | doc src | adds computed property |
events | doc src | adds basic events management |
path | doc src | helper functions to move on objects |
props | doc src | adds props with attributes reflection |
structure | doc src | adds core element structure creation |
style | doc src | helper functions to interact with element style |
styles | doc src | manage the styles of your element structure |
svg | doc src | adds svg creation to structure |
tests | doc src | call unit test on ceri-views |
util | doc src | some basic helper functions |
watch | doc src | adds reactive data |
Name | Links | Short description |
---|---|---|
#ref | doc src | saves the element on your instance |
#text, :text | doc src | sets the textContent of the element |
#if | doc src | toggle element |
Used with structure mixins and template compiler of ceri-compiler or ceri-loader.
<!-- as expected -->
<div attr="value"></div>
<!-- binds attr to the reactive prop @propName -->
<div :attr="propName"></div>
<!-- binds the property prop of the div to the reactive prop @propName -->
<div $prop="propName"></div>
<!-- adds an eventListener on the div which will call the fn @fnName-->
<div @click="fnName"></div>
<!-- use capture mode -->
<div @click.capture="fnName"></div>
<!-- only when target == @ -->
<div @click.self="fnName"></div>
<!-- only when not prevented -->
<div @click.notPrevented="fnName"></div>
<!-- call preventDefault() -->
<div @click.prevent="fnName"></div>
<!-- call stopPropagation() -->
<div @click.stop="fnName"></div>
<!-- remove eventListener once it got called -->
<div @click.once="fnName"></div>
<!-- adds an function @focusDiv which will call focus on the div -->
<div ~focus="focusDiv"></div>
<!-- emit an event "focus" instead -->
<div ~focus.event="focusDiv"></div>
Helper functions to interact with element classes
mixins: [ require("ceri/lib/class") ]
# usage
@$class.set(el, {someClass: true}) # set class on el to "someClass", el defaults to @
@$class.strToObj("someClass") # {someClass: true}
@$class.objToStr({someClass: true}) # "someClass"
@$class.setStr(el, "someClass") # set class on el to "someClass"
Manage the classes of multiple elements, imperativly and declerativly
mixins: [ require("ceri/lib/classes") ]
# usage with structure & props
props: class:
type: String
name: "_class" #rename prop, as class is already taken on HTMLElement
structure: template(1,"""<div #ref="someDiv"></div>""")
data: -> @classToggled: true
classes:
this: # to target the instance
computed: -> someClass: @classToggled # someClass will be removed on @classToggled = false
data: -> someOtherClass: true # can be accessed: @classes.this.someOtherClass = false
prop: "_class" # bind to a prop to pass through a user given class
someDiv: # to target a ref
data: -> classForSomeDiv: true
Helper function to create a computed property which combines a prop, data and computed obj into one.
mixins: [ require("ceri/lib/combined") ] # used in classes and styles
# usage
@$combined({
path: "somePath"
value:
someName:
data: -> # should return object, will be accessible under @somePath.someName
computed: -> # should return object
prop: # name of a prop to watch
parseProp: (propValue) -> # optional, should convert the value to an object
normalize: (obj) -> # optional, should return a normalized object
cbFactory: (name) -> [(val) ->
# name will be "someName"
# the cbs will be called whenever the combined object changes
]
})
Used to lazily recompute a value whenever a dependend, reactive value changes
mixins: [ require("ceri/lib/computed") ]
# usage
data: -> someDependency: true
computed:
# @computed.someData will be updated when @someDependency changes and its getter is called
someData: ->
return @someDependency*1
# when a callback is attached, the computed property will be evaluated
# as soon as a dependency changes
# to attach a callback:
@$watch.path path:"computed.someData", initial: true, cbs: [(newVal) ->
# do something with newVal
]
adds basic events management
mixins: [ require("ceri/lib/events") ]
# usage
events:
someEvent: (e) -> # attaches an eventListener on @
#to issue a custom event
@$emit el, "someEvent", "someOptions" # el defaults to @
@$emit "someEvent", "someOptions" # options will be accessible on e.detail
helper functions to move on objects
mixins: [ require("ceri/lib/path") ]
# usage
data: -> some: path: true
@$path.toValue(path:"some.path") # {path:"some.path",value:true}
@$path.setValue(path:"some.path",value:false) # @some.path == false
@$path.toNameAndParent(path:"some.path") # {path:"some.path",name:"path",parent:@some}
adds props with attributes reflection.
mixins: [ require("ceri/lib/props") ]
# usage
props:
someProp: String # will be connected with "some-prop" attribute
someProp2:
type: Boolean # will be casted to boolean
name: "_someProp2" # will be accessible as @_someProp2 instead of @someProp2
someProp3: Number # will be casted to number
watch:
someProp: (val, old) -> # props are reactive
adds core element structure creation. Looks for directives.
mixins: [ require("ceri/lib/structure") ]
# usage
# adds <div attr=value><p></p></div>
# as a child of your custom element
structure: ->
return @$el "div", {"":{attr:"value"}}, [@$el "p"]
# alternative with ceri-compiler / ceri-loader
structure: template 1, """<div attr=value><p></p></div>"""
Helper functions to interact with element styles
mixins: [ require("ceri/lib/style") ]
# usage
@$style.set(el, {position:"absolute"}) # el defaults to @
@$style.normalize("position") # will find vendor prefixes
@$style.normalizeObj({position:"absolute"}) # normalize all keys
@$style.setNormalized(el, {position:"absolute"}) # same as set, but will not call normalize on obj
Manage the styles of multiple elements, imperativly and declerativly
mixins: [ require("ceri/lib/styles") ]
# usage with structure & props
props: style:
type: String
name: "_style" #rename prop, as style is already taken on HTMLElement
structure: template(1,"""<div #ref="someDiv"></div>""")
data: -> height: 10
styles:
this: # to target the instance
computed: -> height: @height + "px"
data: -> position: "absolute" # can be accessed: @styles.this.position = "relative"
prop: "_style" # bind to a prop to pass through user given style
someDiv: # to target a ref
data: -> position: "absolute"
adds svg creation to structure
mixins: [ require("ceri/lib/svg") ]
# allows this:
structure: template 1, """<svg></svg>"""
Unit test within a ceri view. This shouldn't be used in your component.
mixins: [ require("ceri/lib/tests") ]
# usage
tests: (el) ->
describe "your compontent", ->
it "should exist", ->
should.exist(el)
Some basic helper functions
mixins: [ require("ceri/lib/util") ]
# usage
@util.noop #empty function
# returns an array wrapping the argument, if it isn't already one
@util.arrayize({}) # [{}]
@util.isString
@util.isArray
@util.isObject
@util.isFunction
@util.isElement
@util.camelize("test-test") # testTest
@util.capitalize("test") # Test
@util.hyphenate("testTest") # test-test
Adds reactive data
mixins: [ require("ceri/lib/watch") ]
# usage
data: -> someData: true
watch:
someData: (val,old) -> # will be called when @someData is set
saves the element on your instance
mixins: [ require("ceri/lib/structure") ]
# usage
structure: template 1, """<div #ref="someDiv"></div>"""
# accessible under @someDiv
sets the textContent of the element
mixins: [ require("ceri/lib/structure") ]
# usage
structure: template 1, """<div #text="someText"></div>"""
# will result in <div>someText</div>
# use :text to bind to a reactive var instead
structure: template 1, """<div :text="someText"></div>"""
data: ->
someText: "content"
# will result in <div>content</div> and will be updated on change of @someText
toggle an element
mixins: [ require("ceri/lib/#if") ]
# usage with structure and watch
structure: template 1, """<div #if=visible></div>"""
data: ->
visible: true
All sorts of mixins can be submitted, make sure to include a unit test and a proper documentation.
Try to restrict your mixin to a namespace with the help of _rebind
.
# simple example
module.exports =
_name: "someMixin"
_v: 1
_rebind: "$someMixin"
mixins: [
# add the mixins you depend on
# these will be flattend on runtime
]
methods:
$someMixin:
anArray: [] # will be cloned to the instance
anObject: {} # shallow cloned to the instance
aFunction: -> # will be bound to the instance
Copyright (c) 2017 Paul Pflugradt Licensed under the MIT license.
FAQs
Custom Elements enRIched
The npm package ceri receives a total of 21 weekly downloads. As such, ceri popularity was classified as not popular.
We found that ceri demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.