Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bahrus/xtal-decor
Enables attaching ES6 proxies onto other DOM elements.
https://github.com/bahrus/xtal-decor
custom-elements es6-proxy web-component web-components webcomponents
Last synced: about 1 month ago
JSON representation
Enables attaching ES6 proxies onto other DOM elements.
- Host: GitHub
- URL: https://github.com/bahrus/xtal-decor
- Owner: bahrus
- License: mit
- Created: 2019-05-29T15:34:32.000Z (over 5 years ago)
- Default Branch: baseline
- Last Pushed: 2023-03-04T04:34:13.000Z (almost 2 years ago)
- Last Synced: 2024-09-30T23:16:20.509Z (3 months ago)
- Topics: custom-elements, es6-proxy, web-component, web-components, webcomponents
- Language: TypeScript
- Homepage:
- Size: 271 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# xtal-decor [deprecated]
xtal-decor is now deprecated. [be-decorated](https://github.com/bahrus/be-decorated) replaces it.
[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/xtal-decor)
## Syntax
xtal-decor provides a base class which enables attaching ES6 proxies onto other "Shadow DOM peer citizens" -- native DOM or custom elements in the same Shadow DOM realm.
xtal-decor provides a much more "conservative" alternative approach to enhancing existing DOM elements, in place of the controversial "is"-based customized built-in element [standard-ish](https://bkardell.com/blog/TheWalrus.html).
Like [xtal-deco](https://github.com/bahrus/xtal-deco), properties "init", "on", "actions" and "finale" allow us to define the behavior of the ES6 proxy with a minimum of fuss. And the property "virtualProps" is also supported, which allows us to define properties that aren't already part of the native DOM element or custom element we are enhancing.
Use of virtualProps is critical if you want to be guaranteed that your component doesn't break, should the native DOM element or custom element be enhanced with a new property with the same name.
xtal-decor provides the base class and web component. Like xtal-deco, we can avoid having to inherit from this class, instead "informally" defining a new behavior by using an inline script via something like [nomodule](https://github.com/bahrus/nomodule):
```html
const decoProps = {
actions: [
({count}) => {
window.alert(count + " butterbeers sold");
}
],
on: {
click: ({self}, event) => {
self.count++;
}
},
init: ({self}) =>{
self.count = 0;
},
finale: ({self}, elementBeingRemoved) => {
console.log({self, elementBeingRemoved});
}
}
Object.assign(selfish.parentElement, decoProps);Click me to Order Your Drink
Set count to 2000
function setCount(){
butterBeerCounter.setAttribute('be-a-butterbeer-counter', '{"count": 2000}');
}```
A more "formal" way of defining new behavior is to extend the base class XtalDecor, and to set the "virtualProps", "actions", "on" and/or "init" properties during field initialization or in the constructor. You can then define a custom element with any name you want using your extended class.
An instance of your custom element needs to be added somewhere in the shadowDOM realm where you want it to affect behavior (or outside any Shadow DOM Realm to affect elements outside any Shadow DOM).
The attributes of your instance tag needs to define what element (optional - use * for all elements) and attribute (required) to look for.
For example:
```html
#shadow-root (open)
...
```## Setting properties of the proxy externally
Just as we need to be able to pass property values to custom elements, we need a way to do this with xtal-decor. But how?
The tricky thing about proxies is they're great if you have access to them, useless if you don't.
### Approach I. Programmatically (Ugly)
If you need to modify a property of a proxy, you can do that via the xtal-decor element, or the element extending xtal-decor:
```html
...
Click me to Order Your Drink
...function setCount(newCount){
if(decor.targetToProxyMap === undefined || !decor.targetToProxyMap.has(butterBeerCounter)){
setTimeout(() => setCount(newCount), 50);
return;
}
const proxy = decor.targetToProxyMap.get(butterBeerCounter);
proxy.count = newCount;
}```
### Approach II. Setting properties via the controlling attribute:
A more elegant solution, perhaps, which xtal-decor supports, is to pass in properties via its custom attribute:
```html
...
-
Zorse
-
Aardvark
```
After list-sorter does its thing, the attribute "be-sorted" switches to "is-sorted":
```html
-
Aardvark
-
Zorse
```
You cannot pass in new values by using the is-sorted attribute. Instead, you need to continue to use the be-sorted attribute:
```html
-
Aardvark
-
Zorse
list.setAttribute('be-sorted', JSON.stringify({direction: 'desc'}))
```
A [vscode plug-in](https://marketplace.visualstudio.com/items?itemName=andersonbruceb.json-in-html) is available that makes editing JSON attributes like these much less susceptible to human fallibility.
## Approach III. Proxy Forwarding with a Light Touch
A reusable component, [https://github.com/bahrus/proxy-decor](proxy-decor) serves as a useful companion to xtal-decor. Whereas xtal-decor can have specialized logic (either via prop setting or class extension), proxy-decor is very light-weight and generic. Think of it as a very [thin client](https://www.dell.com/premier/us/en/RC1378895?gacd=9684689-1077-5763017-265940558-0&dgc=st&gclid=9f0071f121cb1a930be2117f5bd9e116&gclsrc=3p.ds&msclkid=9f0071f121cb1a930be2117f5bd9e116#/systems/cloud-client-computing) that easily connects to / switch between different remote, fully loaded desktop/server/VMs, sitting in some well-ventilated server room.
proxy-decor not only allows properties to be passed in to the proxy, it also raises custom events after any property of the proxy changes.
proxy-decor uses a "for" attribute, similar to the "for" attribute for a label.
Sample syntax:
```html
const decoProps = {
actions: [
({count, self}) => {
window.alert(count + " butterbeers sold");
}
],
on: {
'click': ({self}) => {
console.log(self);
self.count++;
}
},
init: ({self}) =>{
self.count = 0;
}
}
Object.assign(selfish.parentElement, decoProps);
Click Me to Order Your Drink
drinks sold.
Set count to 2000
function setCount(){
const bbc = (proxyDecor.aButterbeerCounter ??= {});
bbc.count = 2000;
}
```
proxy-decor:
1. Does an id search within the shadow dom realm (like label for).
2. Multiple proxies can be "fronted" by a single proxy-decor tag.
3. Event names are namespaced only for virtual properties.
## Approach IV. Integrate with other decorators -- binding decorators -- that hide the complexity
[WIP](https://github.com/bahrus/be-observant#inserting-dynamic-settings-todo)
## [Demo](https://codepen.io/bahrus/pen/XWpvmZr)
## API
This web component base class builds on the provided api:
```JavaScript
import { upgrade } from 'xtal-decor/upgrade.js';
upgrade({
shadowDOMPeer: ... //Apply trait to all elements within the same ShadowDOM realm as this node.
upgrade: ... //CSS query to monitor for matching elements within ShadowDOM Realm.
ifWantsToBe: // monitor for attributes that start with be-[ifWantsToBe],
}, callback);
```
API example:
```JavaScript
import {upgrade} from 'xtal-decor/upgrade.js';
upgrade({
shadowDOMPeer: document.body,
upgrade: 'black-eyed-peas',
ifWantsToBe: 'on-the-next-level',
}, target => {
...
});
```
The API by itself is much more open ended, as you will need to entirely define what to do in your callback. In other words, the api provides no built-in support for creating a proxy.
## For the sticklers
If you are concerned about using attributes that are prefixed with the non standard be-, use data-be instead:
```html
...
-
Zorse
-
Aardvark
```
## Viewing example from git clone or github fork:
Install node.js. Then, from a command prompt from the folder of your git clone or github fork:
```
$ npm install
$ npm run serve
Open http://localhost:3030/demo/dev.html
```