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

Property Applicators for VNodes #811

@agubler

Description

@agubler

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions