PolymerElements / paper-scroll-header-panel

Fancy scrolling effects where the header animates between tall and condensed states
24 stars 29 forks source link

Composability problems when using custom child elements #50

Closed kristianmandrup closed 9 years ago

kristianmandrup commented 9 years ago

Trying to compose my main index.html file into smaller parts to be managed independently. My first naive attempt, extracting a drawer-nav element from the Starter kit template.

<paper-scroll-header-panel class="Drawer" drawer fixed>
  <!-- Drawer Toolbar -->
  <paper-toolbar class="Drawer-header">
    <span class="Drawer-title">Menu</span>
  </paper-toolbar>
  <drawer-nav route="{{route}}"/>
</paper-scroll-header-panel>
<dom-module id="drawer-nav">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>

    <!-- Drawer Content -->
    <!-- Navigation -->
    <nav>
      <h1>{{route}}</h1>
      <paper-menu class="Drawer-widget Navigation list" attr-for-selected="data-route" selected="[[route]]">
...
</dom-module>

However this falls flat on its face. Looks like paper-scroll-header-panel is hardcoded to except certain child elements, and won't even allow a wrapper (custom element) as a child for proper display.

<content id="mainContent" select=":not(paper-toolbar):not(.paper-header)"></content>
<content id="headerContent" select="paper-toolbar, .paper-header"></content>`

Please make this more generic for easier/better composability. Instead of selecting on exact matching tag (element), select instead on class name. Something like this:

<content id="headerContent" select=".panel-header"></content>`
<content id="mainContent" select=".panel-content"></content>

So I tried, this...

<paper-scroll-header-panel class="Drawer" drawer fixed>
  <!-- Drawer Toolbar -->
  <paper-toolbar class="Drawer-header panel-header">
    <span class="Drawer-title">Menu</span>
  </paper-toolbar>
  <drawer-nav route="{{route}}"/>
<nav>
  <paper-menu class="Drawer-widget Navigation list panel-content"
  ...

But I get a blank screen and a console error:

Uncaught TypeError: Illegal invocation

Still can't figure out how to debug Polymer in these cases :(

Thanks.

kristianmandrup commented 9 years ago

Your current Starter kit index.html is a ~200 lines "monstrosity". Please allow us to break it up into smaller logical chunks without breaking the Polymer elements. Thanks :)

addyosmani commented 9 years ago

Thanks for the feedback. Where possible, I would separate out feedback specific to paper-scroll-header-panel and Starter Kit on their respective issue trackers :)

On Starter Kit's index: we're aware of the current length issues and plan to investigate alternative patterns that balance ergonomics, size and what is easiest for beginners to grok when first looking at the project.

kristianmandrup commented 9 years ago

Thanks for the quick reply. Trying to find some way to break up the main parts: Now trying to extract the full drawer: main-drawer

      <!-- Main Area id="mainContainer" -->
      <paper-scroll-header-panel class="Main" main condenses keep-condensed-header>
        <main-drawer/>
        <!-- Main Toolbar -->
        <paper-toolbar class="Main-header tall">

But for some reason, as soon as I deviate from the standard layout, there is no element 'mainContainer' as required by the default router code.

  app.scrollPageToTop = () => {
    let mainContainer = document.getElementById('mainContainer');
    if (mainContainer) {
      mainContainer.scrollTop = 0;
    } else {
      console.error('missing element ID = mainContainer'); /// WTF!?
    }
  };

This would normally be controlled by paper-scroll-header-panel, so it looks like it is super fragile and still breaks for this scenario...??

  <template>
    <div id="mainContainer">
kristianmandrup commented 9 years ago

Would also be nice if each component contained brief instructions on development/contribution guidelines:

or even just a reference to a general contribution guidelines page ;)

kristianmandrup commented 9 years ago

Made a pull, learned a few things from the tests, but still... Looks like the PSK uses a nested layout, where main-drawer is yet another nested paper-scroll-header-panel

      <paper-scroll-header-panel class="Main" main condenses keep-condensed-header>
        <main-drawer/>
        <!-- Main Toolbar -->
        <paper-toolbar class="Main-header tall paper-header">
        <!-- Main Content -->
        <iron-pages class="Main-content paper-content" attr-for-selected="data-route" selected="{{route}}">
    </paper-scroll-header-panel>

That should ideally also be covered by the tests. I'm not sure if you are just "lucky" or if it is currently "designed" to handle such scenarios. In my case, taking a small step from the "golden path" caused this pyramid to come crumbling down... but maybe I just didn't use it right, with respect to assigning helper classes appropriate places. But in any case, this should be better documented.

kristianmandrup commented 9 years ago

Trying to help out by adding more tests... please help out whenever one of you has some spare time. Thanks.

kristianmandrup commented 9 years ago

Trying a different approach:

      </paper-scroll-header-panel>

      <!-- Main Area -->
      <paper-scroll-header-panel main condenses keep-condensed-header>

        <main-toolbar class="paper-header"></main-toolbar>
        <!-- Main Content -->
        <main-content route="{{route}}"></main-content>

      </paper-scroll-header-panel>
    </paper-drawer-panel>

This causes NO console errors, and displays both the header and the content area. However, when I scroll, the top just stays put without sliding back like it normally does...

<dom-module id="main-toolbar">
  <template>
    <!-- Main Toolbar -->
    <paper-toolbar id="mainToolbar" class="tall">
kristianmandrup commented 9 years ago

What I get in the DOM is this:

<paper-scroll-header-panel main="" condenses="" keep-condensed-header="">

        <main-toolbar class="paper-header"></main-toolbar>
        <!-- Main Content -->
        <main-content></main-content>

      </paper-scroll-header-panel>

Then elsewhere in the DOM, those custom elements are inserted.

<div id="main" class="style-scope paper-drawer-panel" style="left:256px;">
        <paper-scroll-header-panel main="" condenses="" keep-condensed-header="" class="x-scope paper-scroll-header-panel-0">
    <div id="mainContainer" class="style-scope paper-scroll-header-panel" style="padding-top: 0px;">

  <main-content> // <---------- WTF!?

    <div class="content style-scope main-content">
      <iron-pages attr-for-selected="data-route" class="style-scope main-content">
        <section data-route="home" class="style-scope main-content iron-selected">
          <paper-material elevation="1" class="style-scope main-content x-scope paper-material-0">
         ...    
  </main-content>
    <div id="headerContainer" class="style-scope paper-scroll-header-panel">
      <div class="bg-container style-scope paper-scroll-header-panel">
        <div id="condensedHeaderBg" class="style-scope paper-scroll-header-panel"></div>
        <div id="headerBg" class="style-scope paper-scroll-header-panel"></div>
      </div>

      <main-toolbar class="paper-header"> // <---------- WTF!?
    <!-- Main Toolbar -->
    <paper-toolbar id="mainToolbar" class="tall style-scope main-toolbar x-scope paper-toolbar-0" role="toolbar">
    ...
  </paper-toolbar>
  </main-toolbar>
    </div>
  </paper-scroll-header-panel>
        <div id="scrim" class="style-scope paper-drawer-panel"></div>
      </div>

Why so mysteriously complicated!? There must be a simpler way or a way around all these limitations built into this complex architecture!?

kristianmandrup commented 9 years ago

After some debugging, I found this major problem:

    get header() {
      var hdContent = this.$.headerContent;

      var dm = Polymer.dom(hdContent);
      console.log('hdContent', hdContent, dm);
      var nodes = dm.getDistributedNodes();
      console.log('nodes', nodes);
      return dm.getDistributedNodes()[0];
    },

nodes return an empty list, so it can never set a header to calculate scrolling offset from. I wonder what getDistributedNodes does?

getDistributedNodes: function () {
  return this.node._distributedNodes || [];
},

So, I guess it tries to find the nodes linked to this content element <content id="headerContent" select="paper-toolbar, .paper-header"></content>

From accessing-the-dom-inside-a-content-tag

Not every node passed as a child to a Polymer element gets
distributed into the element's DOM. To get the nodes that are distributed, call
`getDistributedNodes()` on a `<content>` tag in a Polymer element.
For example, `<my-element>` let's you in distribute nodes with `class` 'crucial':
    <content id="crucial" select=".crucial"></content>
You can get the nodes distributed through the above `<content>` tag
like this:
    this.$.crucial.getDistributedNodes();
kristianmandrup commented 9 years ago

Finally I think I understand the problem:

"Note: select can only select elements which are immediate children of the host node. That is, you cannot select descendants"

http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/#toc-separation-separate

kristianmandrup commented 9 years ago

The only way I can see a solution currently then, would be to use inheritance. But that is no longer supported :(

https://www.polymer-project.org/1.0/docs/migration.html#inheritance

Could be done via behaviors I guess https://www.polymer-project.org/1.0/docs/devguide/behaviors.html

Looks like it hit the current limit of the Polymer architecture on my first try at "real-life" compositioning...

I think the real solution would be to compose most of the built in elements from behaviours which can then foster reuse by higher level elements.

robdodson commented 9 years ago

For what it's worth, the layout elements are currently being redone to make them easier to use (https://github.com/PolymerLabs/app-layout). These are not ready for production yet, but I wanted to let you know that we're working on it.

kristianmandrup commented 9 years ago

Thanks Rob :) Looks like it will be Xmas again this year!!! Thumbs up! I would love to contribute, in fact I'm planning to move to San Francisco pretty soon... Please leverage the Behaviour mechanism on steroids. Much more flexible than old school inheritance :) But I'm sure I don't need to tell you that :P Cheers!!

PS: Looking forward to more polycast episodes. Perhaps delve into how to use the special <content> element for composing custom elements :)

robdodson commented 9 years ago

:+1: I talked about <content> a looooong time ago (https://youtu.be/GAjpaM4HcCQ?t=1m25s) but yeah I should do an update. That video is from back when we were using Polymer 0.5

kristianmandrup commented 9 years ago

Cool :) I watched all the episodes, but somehow I missed or forgot that :P Information overload!!

kristianmandrup commented 9 years ago

I made this nifty little tool https://github.com/kristianmandrup/gulp-link-imports to make link imports declarative via lists in plan .yaml files. Since elements.html quickly looks like a "disaster", trying to parse the hrefs in order to get an overview of what elements are included.

robdodson commented 9 years ago

oh cool :sparkles: Yeah I'm not a big fan of the giant elements file. That's sort of a byproduct of using a big dom-bind element :\

kristianmandrup commented 9 years ago

Where do you prefer to discuss Polymer related stuff in private? Currently you can use behaviours to achieve mixins for functionality, but style is still fully private to each elements, or is there a way to make styles mixin as well?

Ah yes @apply(--mixin-name); but this is what I was looking for :)

To share style declarations between elements, you can package a set of style declarations inside a element. In this section, a holding styles is called a style module for convenience.

A style module declares a named set of style rules that can be imported into an element definition, or into a custom-style element.

Awesome!

robdodson commented 9 years ago

Usually just on the slack channel (polymer-slack.herokuapp.com)

On Tue, Sep 29, 2015 at 12:19 PM, Kristian Mandrup <notifications@github.com

wrote:

Where do you prefer to discuss Polymer related stuff in private?

— Reply to this email directly or view it on GitHub https://github.com/PolymerElements/paper-scroll-header-panel/issues/50#issuecomment-144161144 .

kristianmandrup commented 9 years ago

Ah, of course. Been experimenting with custom Polymer mixin functionality, in order to "simulate" some sort of convenient fine-grained "inheritance"... Now I hope to use it to achieve in essence what I set out to do, having custom elements composed/inserted via content insertion targets.

https://github.com/kristianmandrup/polymer-ext