Skip to content
This repository has been archived by the owner on Jul 30, 2018. It is now read-only.

Property Applicators for VNodes #811

Open
agubler opened this issue Dec 23, 2017 · 0 comments
Open

Property Applicators for VNodes #811

agubler opened this issue Dec 23, 2017 · 0 comments
Assignees

Comments

@agubler
Copy link
Member

agubler commented Dec 23, 2017

Enhancement

The meta functionality has evolved from its initial concept of being a mechanism that provides access to simply get information from a DOM node to being used more generally for both reading information and also writing/adding information to DOM nodes created by the virtual DOM system.

For reading information, such as Dimensions and IntersectionObserver using this.meta during the render lifecycle seems to provides adequate ergonomics and functionality.

render() {
    const inView = this.meta(IntersectionObserver).get('root');
    const properties = inView ? { src: 'image/src' } : {};

    return v('img', properties);
}

However, when used to "set" properties or "add" functionality to a DOM node it feels clunky to need to do this in a decoupled programmatic fashion and not declaratively when using v() for the required node.

By adding a concept of an applicator, it will enable declaring meta functionality directly on the node(s) that they are needed.

render() {
    return v('div', {
        focus: meta(Focus, true)
    });
}

The VDom applicators are not limited to just metas, but will enable consumers to write other extended functionality to hook into the vdom rendering system, for example, custom application (or diffing strategy) for a specific attribute or property.

// Only adds classes to the Node (example only)
function classes(classes: string[]) {
    return {
        apply(domNode: Element, previousProperties: VNodeProperties, properties: VNodeProperties) {
            domNode.classList.add(classes);
        }
    };
}

// usage
render() {
    return v('div', { 
        classes: classes([ 'classOne', 'classTwo', this.them(themeClassOne) ]) 
    });
}

Another possible use-case would be to support specific bags for properties, attributes, with custom applicators:

// example attributes implementation
function attributes(...attrs: { [index: string]: string }[]) {
    return {
        apply(domNode: Element, previousProperties: VNodeProperties, properties: VNodeProperties) {
            Object.keys(properties).forEach((propertyKey) => {
                if (previousProperties[propertyKey] !== properties[propertyKey]) {
                    domNode.setAttribute(propertyKey, properties[propertyKey]);
                }
            });
        }
    };
}

// example properties implementation
function properties(...props: { [index: string]: any }[]) {
    return {
        apply(domNode: Element, previousProperties: VNodeProperties, properties: VNodeProperties) {
            Object.keys(properties).forEach((propertyKey) => {
                if (previousProperties[propertyKey] !== properties[propertyKey]) {
                    domNode[propertyKey] = properties[propertyKey];
                }
            });
        }
    };
}

// usage
render() {
    return v('div', { 
        attributes: attributes({ href: 'href' }),
        properties: properties({ 'some-properties': { foo: 'bar' } })
    });
}

It would be nice to be able to restrict the key used by an applicator implementation, but this could prove challenging, if possible at all.

@agubler agubler self-assigned this Jan 2, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant