![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
hyper-element
Advanced tools
Combining the best of hyperHTML and Custom Elements!
Your new custom-element will be rendered with the super fast hyperHTML and will react to tag attribute and store changes.
function
to other custom hyper-elements via there tag attributedocument.registerElement("my-elem", class extends hyperElement{
render(Html){
Html`hello ${this.attrs.who}`
}// END render
})// END my-elem
If using webpack
const hyperElement from "hyper-element"
To use your element in brower
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/webcomponentsjs@latest/lite.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hyperhtml@latest/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hyper-element@latest/source/bundle.min.js"></script>
</head>
<body>
<my-elem who="world"></my-elem>
</body>
<html>
Output
<my-elem who="world">
hello world
</my-elem>
There are 2 functions. render
is required and setup
is optional
This is what will be displayed with in your element. Use the Html
to define your content
The primary operation is to describe the complete inner content of the element.
render(Html,store){
Html`
<h1>
Lasted updated at ${new Date().toLocaleTimeString()}
</h1>
`
}// END render
The Html
has a primary operation and two utilities: .wire
& .lite
The .wire
is for creating reusable sub-element
The wire can take two arguments Html.wire(obj,id)
Example of displaying a list of users from an array
Html`
<ul>
${users.map(user => Html.wire(user,":user_list_item")`<li>${user.name}</li>`)}
</ul>
`
An anti-pattern is to inline the markup as a string
BAD example: ✗
Html`
<ul>
${users.map(user => `<li>${user.name}</li>`)}
</ul>
`
This will create a new node for every element on every render. The is have a Negative impact on performance and output will Not be sanitized. So DONT do this!
The .lite
is for creating once off sub-element
Example of wrapping the jQuary date picker
onSelect(dateText, inst){
console.log("selected time "+dateText)
} // END onSelect
Date(lite){
const inputElem = lite`<input type="text"/>`
$(inputElem).datepicker({onSelect:this.onSelect});
return {
any: inputElem,
once:true
}
} // END Date
render(Html){
Html` Pick a date ${{Date:Html.lite}} `
} // END render
The setup
function wires up an external data-source. This is done with the attachStore
argument that binds a data source to your renderer.
Example of re-rendering when the mouse moves. Will pass mouse values to render
// getMouseValues(){ ... }
setup(attachStore){
// the getMouseValues function will be call before each render and pass to render
const onStoreChange = attachStore(getMouseValues)
// call next on every mouse event
onMouseMove(onStoreChange)
// cleanup logic
return ()=> console.warn("On remove, do component cleanup here")
}// END setup
Example of re-rendering every second
setup(attachStore){
setInterval(attachStore(), 1000);
}// END setup
Example of hard coding an object that will be used on every render
setup(attachStore){
attachStore({max_levels:3})
}// END setup
Any logic you wish to run when the element is removed from the page should be returned as a function from the setup
function
// listen to a WebSocket
setup(attachStore){
let newSocketValue;
const onStoreChange = attachStore(()=> newSocketValue);
const ws = new WebSocket("ws://127.0.0.1/data");
ws.onmessage = ({data}) => {
newSocketValue = JSON.parse(data);
onStoreChange()
}
// Return way to unsubscribe
return ws.close.bind(ws)
}// END setup
render(Html,incomingMessage){
// ...
}// END render
Returning a "teardown function" from setup
address's the problem of needing a reference to the resource you want to release.
If the "teardown function" was a public function. We would need to store the reference to the resource somewhere. So the teardown can access it when needed.
With this approach there is no leaking of references.
setup(attachStore){
const onStoreChange = attachStore(user);
mobx.autorun(onStoreChange); // update when changed (real-time feedback)
setInterval(onStoreChange, 1000); // update every second (update "the time is now ...")
}// END setup
<my-elem min="0" max="10" />
= { min:0, max:10 }
Number
<my-elem>Hi!</my-elem>
= "Hi!"
data-*
set on the element.
Object
, Array
, Number
& Boolean
dataset
is a live reflection. Changes on this object will update matching data attribute on its element.
<my-elem data-users='["ann","bob"]'></my-elem>
to this.dataset.users // ["ann","bob"]
dataset
works by reference. To update an attribute you must use assignment on the dataset
this.dataset.user.name = ""
✗this.dataset.user = {name:""}
✓Being able to set attributes at run-time should be the same for dealing with a native element and ones defined by hyper-element.
⚠ To support dynamic attributes on custom elements YOU MUST USE customElements.define
which requires native ES6 support! Use the native source /source/hyperElement.js
NOT /source/bundle.js
This is what allows for the passing any dynamic attributes from parent to child custom element! You can also pass a function
to a child element(that extends hyperElement).
Example:
In you document:
<script src="https://cdn.jsdelivr.net/npm/hyper-element@latest/source/hyperElement.js"></script>
<users-elem />
Implementation:
window.customElements.define("a-user",class extends hyperElement{
render(Html){
const onClick = () => this.attrs.hi("Hello from "+this.attrs.name);
Html`${this.attrs.name} <button onclick=${onClick}>Say hi!</button>`
}
})
window.customElements.define("users-elem",class extends hyperElement{
onHi(val){
console.log("hi was clicked",val)
}
render(Html){
Html`<a-user hi=${this.onHi} name="Beckett" />`
}
})
Output:
<users-elem>
<a-user update="fn-bgzvylhphgvpwtv" name="Beckett">
Beckett <button>Say hi!</button>
</a-user>
</users-elem>
You can declare markup to be used as a template within the custom element
To enable templates:
Example:
In you document:
<my-list template data-json='[{"name":"ann","url":""},{"name":"bob","url":""}]' >
<div>
<a href="{url}">{name}</a>
</div>
</my-list>
Implementation:
document.registerElement("my-list",class extends hyperElement{
render(Html){
Html`
${this.dataset.json.map(user => Html.template(user))}
`
}// END render
})// END my-list
Output:
<my-list template data-json='[{"name":"ann","url":""},{"name":"bob","url":""}]' >
<div>
<a href="">ann</a>
</div>
<div>
<a href="">bob</a>
</div>
</my-list>
Fragments are pieces of content that can be loaded asynchronously.
You define one with a class property starting with a capital letter.
To use one within your renderer. Pass an object with a property matching the fragment name and any values needed.
The fragment function should return an object with the following properties
false
. The fragment function will be run on every render!and one of the following as the fragment's result:
Example:
Implementation:
document.registerElement("my-friends",class extends hyperElement{
FriendCount(user){
return {
once:true,
placeholder: "loading your number of friends",
text:fetch("/user/"+user.userId+"/friends")
.then(b => b.json())
.then(friends => `you have ${friends.count} friends`)
.catch(err => "problem loading friends")
}// END return
}// END FriendCount
render(Html){
const userId = this.attrs.myId
Html`<h2> ${{FriendCount:userId}} </h2>`
}// END render
})// END my-friends
Output:
<my-friends myId="1234">
<h2> loading your number of friends </h2>
</my-friends>
then
<my-friends myId="1234">
<h2> you have 635 friends </h2>
</my-friends>
You can use the template syntax with in a fragment
e.g. assigning values to template from with in the fragment function
Foo(values){ return{ template:"<p>{txt}</p>", values:{txt:"Ipsum"} }}
Html`${{Foo:{}}}`
or assigning values to template from with in the render function
Foo(values){ return{ template:"<p>{txt}</p>" }}
Html`${{Foo:{txt:"Ipsum"}}}`
Note: the different is whether or not a "values" is returned from the fragment function
output
<p>Ipsum</p>
Example:
Implementation:
document.registerElement("click-me",class extends hyperElement{
Button(){
return {
template:`<button type="button" class="btn"
onclick={onclick}>{text}</button>`
}// END return
}// END Button
render(Html){
Html`Try ${{Button:{
text:"Click Me",
onclick:()=>alert("Hello!")
}}}`
}// END render
})// END click-me
Output:
<click-me>
Try <button type="button" class="btn">Click Me</button>
</click-me>
You can also return a promise as your template
property.
Rewritting the my-friends example
Example:
Implementation:
document.registerElement("my-friends",class extends hyperElement{
FriendCount(user){
const templatePromise = fetch("/user/"+user.userId+"/friends")
.then(b => b.json())
.then(friends => ({
template:`you have {count} friends`,
values:{count:friends.count}
})
}) // END .then
.catch(err=>({ template:`problem loading friends` })
return {
once: true,
placeholder: "loading your number of friends",
template: templatePromise
} // END return
}// END FriendCount
render(Html){
const userId = this.attrs.myId
Html`<h2> ${{FriendCount:userId}} </h2>`
}// END render
}) //END my-friends
In this example, the values returned from the promise are used. As the "values" from a fragment function(if provided) takes priority over values passed in from render.
Output:
<my-friends myId="1234">
<h2> you have 635 friends </h2>
</my-friends>
Supports an object as the style attribute. Compatible with React's implementation.
Example: of centering an element
render(Html){
const style= {
position: "absolute",
top: "50%", left: "50%",
marginRight: "-50%",
transform: "translate(-50%, -50%)"
}//END style
Html`<div style=${style}> center </div>`
}//END render
var user = new (Backbone.Model.extend({
defaults: {
name: 'Guest User',
}
}));//END Backbone.Model.extend
document.registerElement("my-profile", class extends hyperElement{
setup(attachStore){
user.on("change",attachStore(user.toJSON.bind(user)));
// OR user.on("change",attachStore(()=>user.toJSON()));
}//END setup
render(Html,{name}){
Html`Profile: ${name}`
}//END render
})//END my-profile
const user = observable({
name: 'Guest User'
})//END observable
document.registerElement("my-profile", class extends hyperElement{
setup(attachStore){
mobx.autorun(attachStore(user));
}// END setup
render(Html,{name}){
Html`Profile: ${name}`
}// END render
})//END my-profile
document.registerElement("my-profile", class extends hyperElement{
setup(attachStore){
store.subcribe(attachStore(store.getState)
}// END setup
render(Html,{user}){
Html`Profile: ${user.name}`
}// END render
})// END my-profile
FAQs
hyperHTML + WebComponents
We found that hyper-element 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
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.