Starcounter / starcounter-include

Custom Element to include HTML partials/templates from Starcounter
MIT License
0 stars 0 forks source link

Add support for declarative shadow dom composition given by the host view #102

Closed tomalec closed 6 years ago

tomalec commented 6 years ago

We would like to provide a solution that addresses the use cases like https://github.com/Starcounter/RebelsLounge/issues/53 when an application developer would like to provide a default presentation for a list of UI elements provided by partials included in his/her view (host view).

As discussed on a meeting with @warpech yesterday (2018.06.14)


Scenario

Consider a solution of 3 apps: Timeline, Calendar, Notes, Zuber. Every app, processes events in some sense. Calendar, Notes, and Zuber provides a views to create an event (<Event>, "/timeline/event-creation", ["menu", "create"])

Then Timeline app in a view for some subject wants to include this "create event menu" view aside to the list of all events.

timeline.NewEventActions = Self.GET<Event>("/timeline/event-creation", ["menu", "create"]);
<template>
    <h2>Timeline</h2>
    <p>here is the list of events for {{model.Subject}}</p>
    <timeline-custom-element></timeline-custom-element>
    <starcounter-include slot="timeline/new-events" view-model="{{model.NewEventActions}}"></starcounter-include>

    <template is="dom-repeat" items="{{model.Events}}">
        <div slot="timeline/event">
            <img src={{item.EventIcon}}>
            <div class="event-detail">
                <starcounter-include view-model={{item.EventDetail}}></starcounter-include>
            </div>
        </div>
    </tempalte>

    <template is="declarative-shadow-dom">
        <slot name="timeline/new-events"></slot>
        <div class="events-container">
            <slot name="timeline/event"></slot>
        </div>
    </template>
</template>

Now Timeline app developer would like to provide a proposed, default presentation for inserted list of "create event" elements, regardless of what was proposed as default presentation for individual ones, also without a need to act as a solution owner every time and ship custom composition to the database, crafted for predefined set of apps.

For example, to render all of them as child nodes of <paper-list> or <uni-xyz-menu>.

Usually this presentation should be capable of rendering lists, or menus of different elements but in consistent fashion.

Naturally, it should still leave the last word to the solution owner, so he/she could totally change it and handcraft profiled presentation.

@malx122, @jwillmer I would really appreciate you coment, if the above description fits any of your use cases.

tomalec commented 6 years ago

Solution

Currently we have two types or ranks of shadow dom compositions (presentation layer of a view):

We can introduce third type/rank of composition. Name is TO BE DECIDED, we can call it host's composition. This composition, provided by the host view, will ignore and overwrite default compositions provided by inserted views, but could still be overwritten, by the custom composition given by solution owner. We can reason, that the solution is always a host to any view of any app, while an app's view is a host only to the view's it explicitely includes - via starcounter-include.

This new TBD "host's composition" will be provided in the host's view, in content part, as a content of <starcounter-include> in question.

(related: https://github.com/Juicy/imported-template/issues/2)

Example:

<template>
    <h2>Timeline</h2>
    <p>here is the list of events for {{model.Subject}}</p>
    <timeline-custom-element></timeline-custom-element>
    <starcounter-include slot="timeline/new-events" view-model="{{model.NewEventActions}}">
        <!--
        starcounter-include takes as shadow root:
        merged `template is="declarative-shadow-dom"`s < `<template is="declarative-shadow-dom" TBD-host>` content < .CompositionProvider.Composition$ (`<template is="..." solution>`)
        -->
        <template is="declarative-shadow-dom" TBD-host>
            <uni-magic-menu><slot slot="*"></slot></uni-magic-menu>
        </template>
        <!--
        Content that will be loaded from the merged view:

        <a href='' slot="calendar/new">New event</a>
        <a href='' slot="calendar/newrec">New recurring event</a>
        <template is="declarative-shadow-dom" >
            <paper-menu>
                <slot name="calendar/new"></slot>
                <slot name="calendar/newrec"></slot>
            </paper-menu>
        </template>
        <button onclick=""></button>
        <note-widget slot="notes/new"></note-widget>
        <template is="declarative-shadow-dom" default>
            <ul>
                <li>
                    <slot name="notes/new"></slot>
                </li>
            </ul>
        </template>
        -->
    </starcounter-include>

    <template is="dom-repeat" items="{{model.Events}}">
        <div slot="timeline/event">
            <img src={{item.EventIcon}}>
            <div class="event-detail">
                <starcounter-include view-model={{item.EventDetail}}></starcounter-include>
            </div>
        </div>
    </tempalte>

    <template is="declarative-shadow-dom">
        <slot name="timeline/new-events"></slot>
        <div class="events-container">
            <slot name="timeline/event"></slot>
        </div>
    </template>
</template>

Rationale, We think content is a good place, as host's presentation layer should contain oln, well..., host's presentation, not the presentation of included views (not to break modularity). A the same time we would like to keep the presentation close to the source of including view. Also this states host's app developer opinion on other apps, and does not have to be changed outside of the app, as it is still overwrittable by solution one.

Proposed attribute sytnax makes it possible to still use this apprach without breaking our ideas to flattening blended pages to server-side render partials. As we can still load those different types of compositions into static markup, and let <starcounter-include> pick the right one.

Besides the implementation, we will also need to make sure the docs are clean and understandable. How to explain to our customers when and where

tomalec commented 6 years ago

Speaking of a "TBD-host" name, as we discussed at https://github.com/Starcounter/RebelsLounge/issues/369#issuecomment-399351628 We could eventually call it:

(Renaming element itself is out of the scope of this issue, but we could decide on an attribute name that would last longer and not require renaming soon.) //cc @warpech

tomalec commented 6 years ago

Released in https://github.com/Starcounter/StarcounterClientFiles/pull/104