infinnie / infinnie.github.io

https://infinnie.github.io/
Apache License 2.0
0 stars 1 forks source link

The renderer API design #3

Open infinnie opened 8 years ago

infinnie commented 8 years ago

Another template syntax:

<!-- What is required in the template should also be included in the require attribute of the script element. -->

<script
    require="jQuery, lib/makecomponent, lib/combineclassnames, ../childcomponent"
    params="$, MakeComponent, CombineClassNames, ChildComponent">
    var componentDecorator = MakeComponent(function (component) {
        // Do something...
    });
</script>

<template param="{
    paragraphClass,
    people,
    match,
    currentValue,
    id
}" decorator="componentDecorator" export="path/to/MyComponent">
    <div class="thing thing--light" data-enterprise-component="thing" data-model-id="@id">
        <p class="@CombineClassNames("thing__paragraph", paragraphClass)">
            Hello, world
            <span class="thing__span" role="presentation">Some text</span>
        </p>
        <a href="#" class="btn btn--primary" data-component="thing-linkBtn">Click me</a>
        @people.filter(function (person) {
            return new RegExp(match).test(person.name);
        }).map(function (person) {
            return <@ChildComponent $arguments="[{ person: person, children: [ <p>Hello,</p> ] }]" />;
        });
        <input $value="@currentValue" class="input input--bordered ui--radius" data-component="thing-textBox"></input>
    </div>
</template>

would be transpiled to (assuming AMD):

define("path/to/MyComponent",
    ["jQuery", "lib/makecomponent", "lib/combineclassnames", "../childcomponent"],
    function ($, MakeComponent, CombineClassNames, ChildComponent) {
    // generated from <script>
    var componentDecorator = MakeComponent(function (component) {
        // Do something...
    });

    // generated from <template>
    return componentDecorator(function (_tempArg) {
        var paragraphClass = _tempArg.paragraphClass,
            people = _tempArg.people,
            match = -tempArg.match,
            currentValue = _tempArg.currentValue,
            id = _tempArg.id;
        return {
            // generate the return value from the template...
        };
    });
});

Template syntax:

<script>
var componentDecorator = MakeComponent(function (component) {
    return component.hooks({
        // Options. (Optional)
        created: function () {
            // Custom lifecycle hooks go here
        }
    }).events("click", "[data-component=thing-linkBtn]", function (e, model) {
        RunTransform({
            action: "thingtoggle",
            id: model.id,
            value: {
                toggled: !model.itemToggled
            }
        });
        return false;
    }).events("input", "[data-component=thing-textBox]", function (e, model) {
        RunTransform({
            action: "thingdraftchange",
            id: model.id,
            value: $(this).val()
        });
    });
});
</script>

<template param="model" decorator="componentDecorator" export="MyComponent">
    <div class="thing thing--light" data-enterprise-component="thing">
        <p class="@CombineClassNames("thing__paragraph", model.paragraphClass)">
            Hello, world
            <span class="thing__span" role="presentation">Some text</span>
        </p>
        <a href="#" class="btn btn--primary" data-component="thing-linkBtn">Click me</a>
        @model.people.filter(function (person) {
            return new RegExp(model.match).test(person.name);
        }).map(function (person) {
            return <@ChildComponent person="@person">
                <p>Hello,</p>
            </@ChildComponent>;
        });
        <input $value="@model.currentValue" class="input input--bordered ui--radius" data-component="thing-textBox" />
    </div>
</template>

Prev update:

// User dependencies:
// Components: ChildComponent
// Other: Model

// Library dependencies: jQuery, CombineClassNames, MakeComponent, RunTransform

var MyComponent = MakeComponent(function (component) {
    return component.hooks({
        // Options. (Optional)
        created: function () {
            // Custom lifecycle hooks go here
        }
    }).events("click", "[data-component=thing-linkBtn]", function (e, model) {
        RunTransform({
            action: "thingtoggle",
            id: model.id,
            value: {
                toggled: !model.itemToggled
            }
        });
        return false;
    }).events("input", "[data-component=thing-textBox]", function (e, model) {
        RunTransform({
            action: "thingdraftchange",
            id: model.id,
            value: $(this).val()
        });
    });
})(function (model) {
    return {
        tagName: "div",
        className: "thing thing--light",
        attrs: {
            "data-enterprise-component": "thing"
        },
        children: [
            {
                tagName: "p",
                className: CombineClassNames("thing__paragraph", model.paragraphClass)
                children: [
                    "Hello, world",
                    {
                        tagName: "span",
                        role: "presentation",
                        className: "thing__span"
                        children: ["Some text"]
                    }
                ]
            }, {
                tagName: "a",
                className: "btn btn--primary",
                attrs: {
                    "data-component": "thing-linkBtn"
                },
                children: ["Click me"]
            }
        ].concat(model.people.filter(function (person) {
            return new RegExp(model.match).test(person.name);
        }).map(function (person) {
            return ChildComponent({ person: person, children: [
                tagName: "p",
                children: ["Hello,"]
            ]});
        })).concat({
            tagName: "input",
            className: "input input--bordered ui--radius",
            attrs: {
                "data-component": "thing-textBox"
            }
        })
    };
});

Alt:

// User dependencies:
// Components: ChildComponent
// Other: Model

// Library dependencies: jQuery, CombineClassNames, MakeComponent, RunTransform

var MyComponent = MakeComponent(function (model) {
    return {
        tagName: "div",
        className: "thing thing--light",
        attrs: {
            "data-enterprise-component": "thing"
        },
        children: [
            {
                tagName: "p",
                className: CombineClassNames("thing__paragraph", model.paragraphClass)
                children: [
                    "Hello, world",
                    {
                        tagName: "span",
                        role: "presentation",
                        className: "thing__span"
                        children: ["Some text"]
                    }
                ]
            }, {
                tagName: "a",
                className: "btn btn--primary",
                attrs: {
                    "data-component": "thing-linkBtn"
                },
                children: ["Click me"]
            }
        ].concat(model.people.filter(function (person) {
            return new RegExp(model.match).test(person.name);
        }).map(function (person) {
            return ChildComponent.render(person);
        })).concat({
            tagName: "input",
            className: "input input--bordered ui--radius",
            attrs: {
                "data-component": "thing-textBox"
            }
        })
    };
}).hooks({
    // Options. (Optional)
    created: function () {
        // Custom lifecycle hooks go here
    }
}).events("click", "[data-component=thing-linkBtn]", function (e, model) {
    RunTransform({
        action: "thingtoggle",
        id: model.id,
        value: {
            toggled: !model.itemToggled
        }
    });
    return false;
}).events("input", "[data-component=thing-textBox]", function (e, model) {
    RunTransform({
        action: "thingdraftchange",
        id: model.id,
        value: $(this).val()
    });
});

Original version:

var myComponent = Renderer({
    // Options. (Optional)
    created: function () {
        // Custom lifecycle hooks go here
    }
})(function (model) {
    return {
        tagName: "div",
        attrs: {
            "class": "some-class-name and-another"
        }, styles: {
            backgroundColor: model.get("someProp.background")
        }, events: {
            mouseenter: doSomething // basically any jQuery event
        }, children: [{
            tagName: "p",
            children: [model.get("content")]
        }, Button(model.get("buttonText"))]
    };
});