Send to Kindle

Tuesday, August 26, 2014

Git Subcommand to Sort by Last Modified Date


OK, it's time to get serious about updating Patterns in Polymer and finishing the screencasts. But where to start? I know what needs to be done for the screencasts: record them (the upcoming long US weekend should help there). But how best to focus my efforts on the chapters in the book?

Working through each chapter based on last modified date seems the best bet, but all of the chapter files on my filesystem have the same last modified timestamp:
$ ls -l *asc
...
-rw-r--r-- 1 chris chris 13163 Jun 28 10:06 i18n.asc
-rw-r--r-- 1 chris chris  5213 Jun 28 10:06 live_reload.asc
-rw-r--r-- 1 chris chris 10713 Jun 28 10:06 mdv.asc
-rw-r--r-- 1 chris chris  7917 Jun 28 10:06 plain_old_forms.asc
-rw-r--r-- 1 chris chris 12495 Jun 28 10:06 polymer.asc
-rw-r--r-- 1 chris chris   794 Jun 28 10:06 strategy.asc
Either I made a very large commit on June 28 at 10:06 or that was the last time that I checked these files out fresh (either from a new clone or switching from a sparse branch).

In fact, the last time that I updated the i18n chapter was back in April (yikes!):
$ git log i18n.asc | head -5
commit 030968dff38794ba7e20fa3ae839fc62a999eee2
Author: Chris Strom 
Date:   Sun Apr 20 23:39:09 2014 -0400

    Fix up i18n copy and code
So how do I go about sorting by the last-modified-in-git date? That turns out to be tricky. Thankfully, there is a nice Stack Overflow post on the subject.

The date timestamp from that article will not help sorting, but ISO 8601 will. Happily, git-log supports logging with ISO 8601:
$ git log -1 --date=iso --format="%ad" i18n.asc 
2014-04-20 23:39:09 -0400
It have the feeling that I would like to use this again, so I will create a git subcommand: git-lslt (similar to the usual ls -lt). Git subcommands are trivial—I need only a script prefixed with git-. So I create $HOME/bin/git-lslt as:
#!/bin/sh

ls | \
  while read filename; do
    echo "$(git log -1 --date=iso --format="%ad" -- $filename) $filename"
  done | \
  grep '^2' | \
  sort
Most of that is from the Stack Overflow article. The sort is self-explanatory. The grep '^2' selects only entries with date stamps—meaning that files not tracked by git will be ignored.

The output looks like:
$ git lslt
2013-11-16 16:26:38 -0500 about.asc
2013-11-16 16:26:38 -0500 chapter_1.asc
2013-11-16 17:51:48 -0500 getting_help.asc
2014-01-14 19:58:38 -0500 book_dart.asc
2014-01-14 19:58:38 -0500 book_js.asc
2014-02-12 02:52:49 -0500 copyright.asc
...
Most of that is boilerplate code that never needs an update. I suspect that the "about" file has since been absorbed into the introduction and can be deleted.

After grepping the output a bit more, I find a few surprises:
$ git lslt | \
   grep .asc | \
   grep -v 'chapter_1\|contents\|copyright\|book.*.asc\|bibliography'
...
2014-02-14 01:13:27 -0500 parent_events.asc
2014-02-15 01:16:04 -0500 parent_child.asc
2014-02-15 01:16:04 -0500 svg.asc
2014-02-15 16:12:16 -0500 configuration.asc
...
I am surprised that the parent events and parent-child chapters have not been updated. I could have sworn that I got (and incorporated) feedback on at least one of those. The configuration chapter has since been removed (possibly permanently), so that is no surprise. But I have learned a ton about SVG since February—I am quite surprised that I have not included any of that knowledge in that chapter.

My new git lslt subcommand has already paid some nice dividends. I know where I need to focus my initial update/rewrite efforts. Starting tomorrow.


Day #164

Monday, August 25, 2014

At the Bottom of the Rabbit Hole, I Find Polyfill-Next-Selector


The more I investigate styling and theming Polymer elements, the less a grasp I feel like I have on it. The core-style continues to vex. Beyond that, I am also having difficulty applying consistent CSS styles on my elements.

I am unsure if my current problems are with Polymer or with the Core Elements and Paper Elements built on top of Polymer. The most recent issue that I find is that the <paper-button> inside of a sample Polymer element that I am trying to create do not share styles. Specifically, the border is not included on all paper-buttons:



Both the top buttons and the dialog buttons are <paper-button> elements. Both should be covered by my core-style CSS:
<polymer-element name="lorem-dialog">
  <template>
    <paper-button label="Bottom" on-tap="{{toggleDialog}}"></paper-button>
    <paper-button label="Center" on-tap="{{toggleDialog}}"></paper-button>

    <paper-dialog heading="Bottom Dialog" transition="paper-dialog-transition-bottom">
      <!-- ... -->
      <paper-button label="Accept" affirmative autofocus></paper-button>
    </paper-dialog><
    <!-- ... -->
    <core-style id="theme">
      :host /deep/ paper-button {
        color: {{g.primaryColor}};
        border: 5px solid {{g.secondaryColor}};
        padding: 2px 5px;
      }
    </core-style>
    <core-style ref="theme"></core-style>
  </template>
  <script>
    Polymer('lorem-dialog', {/* ... */});
  </script>
</polymer-element>
The core-style CSS is applied with the /deep/ CSS modifier. My understanding of /deep/ is that my styles should penetrate any shadow DOMs that are under the current element. And it kinda/sorta does what I expect. The primary color, themed from the containing page, is set to orange and it does apply to all paper-button elements. But darn it, why are the borders not in place for the paper-buttons in the dialogs?

My first thought is that perhaps this is a native shadow DOM vs. polyfill issue, so I load the demo page up in Firefox. This only makes things worse:



The borders are applied to all paper-buttons, but none of the core-style global settings are in place. Bleh.

Taking a step back, I know from last night that core-style does not like the way that I am using it. I take that out of the equation by removing the id/ref core-style pair of tags, replacing them with a straight forward <style> tag:
<polymer-element name="lorem-dialog">
  <template>
    <!-- ... -->
    <style>
      :host /deep/ paper-button {
        color: orange;
        border: 5px solid green;
        padding: 2px 5px;
      }
    </style>
  </template>
  <script>
    Polymer('lorem-dialog', {/* ... */});
  </script>
</polymer-element>
That solve my Firefox problem. The polyfills now correctly style my paper-button elements:



But this remains unchanged in Chrome (stable through unstable). On the surface, it would seem that Polymer styles are just broken at this point, but I refuse to indulge in select-is-broken thoughts. At least not yet.

If I peek at one of the paper-button elements in the Chrome inspector, I find that my border style is being overridden:



But what is that double-colon content thingy? I have no idea how that applies to my paper-button elements, let alone is more specific (in a CSS selector sense) than my /deep/ paper-button selector. Furthermore, I am hindered by the odd lack of file and line number for this selector. How can I understand and work around the darn thing if I cannot even find it?

To the ack machine Robin!

Amazingly, that actually finds something:
$ ack -l ::content                                                  
bower_components/platform/platform.js
bower_components/platform/platform.js.map
bower_components/paper-dialog/paper-dialog.css
bower_components/core-style/elements.html
bower_components/core-component-page/core-component-page.html
Only one of those is a CSS file and just so happens to be the element (paper-dialog) that is wrapping my misbehaving paper-buttons. Taking a look at the offending CSS, I find:
polymer-next-selector { content: ':host > *'; }
::content > * {
  font: inherit;
  border: 0;
}
That is exactly the definition of the culprit that I found in the DOM inspector. A quick review of the other matching files reveals that none of them have the same style definition. So the question becomes… what the heck is a polymer-next-selector? More importantly, how do I override it?

The answer to the first question seems to be that polymer-next-selector is also known as polyfill-next-selector. It seems to be a way to apply styles in the polyfills, but which work natively with the shadow DOM if present. Only, the precedence on these things is crazy high.

Try as I might, I cannot target the distributed nodes of the paper-dialog from my custom element that tries to use paper-dialog. I am surprised that targeting the distributed nodes of paper-dialog has no effect:
<polymer-element name="lorem-dialog">
  <template>
    <!-- ... -->
    <style>
      :host /deep/ paper-button {
        color: orange;
        border: 5px solid green;
        padding: 2px 5px;
      }

      paper-dialog::content > * {
        border: 5px dashed blue;
      }
    </style>
  </template>
  <script>
    Polymer('lorem-dialog', {/* ... */});
  </script>
</polymer-element>
In the end, I give up trying to work with ::content and simply add an !important to the border style:
<polymer-element name="lorem-dialog">
  <template>
    <!-- ... -->
    <style>
      :host /deep/ paper-button {
        color: orange;
        border: 5px solid green !important;
        padding: 2px 5px;
      }
    </style>
  </template>
  <script>
    Polymer('lorem-dialog', {/* ... */});
  </script>
</polymer-element>
That does the trick:



But it feels like a cheat.

I cannot figure out why the ::content distributed node selector has such high precedence or why my attempts to influence it failed. I am probably overlooking some selector combinator that would allow me to target paper-button distributed into paper-dialog, but I wish it were easier to find that combinator. And if there is no easier way to do this, then why is paper-dialog using such a high precedence selector to ensure that none of its nodes have borders?

I have a solution, but I have more questions than answers to go along with that solution. Which makes this feel like a cheat.




Day #163

Sunday, August 24, 2014

Crazy Theming Polymer.dart with Core-Style


I am resigned.

Resigned that the core-style element and I disagree on how it should support theming. I have no illusions that I am in the right on this one, but I will attempt to make my case anyway.

When I think of custom themes, I think of setting a few colors and maybe a few other atomic values that can be used by a widget to look more or less like it fits in with the rest of the web page. In core-style, parlance, this looks like:
      <script>
        CoreStyle.g.primaryColor = 'orange';
        CoreStyle.g.secondaryColor = 'green';
      </script>
Or, alternatively, as:
        CoreStyle.g = {
          primaryColor: 'orange',
          secondaryColor = 'green'
        };
I would think that web page trying to use a widget would set these values and the widget would then honor the values. As best I can tell, this is not how core-style works.

Instead, core-style wants these global settings defined by the containing page and it wants the containing page to define styles that will apply to the internals of the widgets being used. That is, if I know that my <lorem-dialog> custom Polymer element contains paper-button elements, then core-style would have me define the global property setting and the detailed widget styling on the containing page:
  <body>
    <h1>Play Paper</h1>
    <lorem-dialog></lorem-dialog>
    <core-style id="theme">
      :host paper-button {
        border: 5px solid {{g.primaryColor}};
        padding: 2px 5px;
      }
    </core-style>
    <script>
      CoreStyle.g.primaryColor = 'orange';
    </script>
  </body>
I cannot help but think this requires the containing page to know too much about the internal implementation of the widget (the Polymer element).

I realize that I am almost certainly making a dumb assumption here. I am probably abusing this. Or not thinking right. Knowing this does not help me. Making the problem worse usually does. If I push this further—feel more pain in coding the wrong way—then I usually figure out how to do it right.

Last night, I was able to get core-style to work like I want by making the core-style's g property available in the backing Polymer element class:
Polymer('lorem-dialog', {
  created: function() {
    this.g = CoreStyle.g;
  },
  // ...
}
I could then use this reference inside the Polymer template:
<polymer-element name="lorem-dialog">
  <template>
    <!-- ... -->
    <core-style id="theme">
      :host paper-button {
        border: 5px solid {{g.primaryColor}};
        padding: 2px 5px;
      }
    </core-style>
    <core-style ref="theme"></core-style>
  </template>
  <script>
    Polymer('lorem-dialog', { /* ... */ });
  </script>
</polymer-element>
Unfortunately, that does not work in Polymer.dart. Try as I might, there is no g property on the core-style object in Dart. But…

I know that the Dart versions of the core and paper elements are just thin wrappers around the JavaScript versions. Since I know how to get the global core-style values from JavaScript, perhaps I can use Dart's awesome JavaScript interoperability to resolve this dilemma.

So, I import the dart:js packages and define a g getter to return the value of CoreStyle.g from JavaScript:
import 'package:polymer/polymer.dart';
import 'dart:html';
import 'dart:js';

@CustomTag('lorem-dialog')
class LoremDialog extends PolymerElement {
  LoremDialog.created(): super.created();

  get g => context['CoreStyle']['g'];
  // ...
}
And that actually works. In the template, I can define and reference a “theme” style that makes use of the global values from the web page using my Polymer element:
<polymer-element name="lorem-dialog">
  <template>
    <!-- ... -->
    <core-style ref="theme"></core-style>
    <core-style id="theme">
      paper-button {
        border: 5px solid {{g['secondaryColor']}};
        color: {{g['primaryColor']}};
        font-weight: bold;
        padding: 2px 5px;
      }
    </core-style>
  </template>
  <script type="application/dart" src="lorem_dialog.dart"></script>
</polymer-element>

I strongly doubt that I will offer this up as a solution in Patterns in Polymer, but it does work in both JavaScript and Dart. Even so, the amount of resistance that I get from the library is strongly suggesting to me that I am doing something wrong. But even pushing this hard against core-style is not suggesting to me the right way to tackle this problem. Hopefully something will come to me (or someone can point me in the right direction) over the course of the next few days...


Day #162

Saturday, August 23, 2014

Where Core-Style Global Properties Can Be Used


I am struggling with the core-style element in Polymer.dart. I can implement simple styles—both as a source and referencing them later. But I have not been able to get arguably the coolest feature working yet: setting group variables.

For instance, I might want to theme some elements with the primary color of orange. From the container page, I ought to be able to set this in a script like so:
    <script>
      CoreStyle.g.primaryColor = 'orange';
    </script>
Custom Polymer elements should then honor this primary color with settings like:
<link rel="import"
      href="../../../packages/polymer/polymer.html">
<!-- ... -->
<link rel="import"
      href="../../../packages/core_elements/core_style.html">
<polymer-element name="lorem-dialog">
  <template>
    <paper-button label="Bottom" on-tap="{{toggleDialog}}"></paper-button>
    <paper-button label="Center" on-tap="{{toggleDialog}}"></paper-button>
    <!-- ... -->
    <core-style id="theme">
      paper-button {
        border: 5px solid {{g.primaryColor}};
        padding: 2px 5px;
      }
    </core-style>
    <core-style ref="theme"></core-style>
  </template>
  <script type="application/dart" src="lorem_dialog.dart"></script>
</polymer-element>
Try as I might, I cannot get this to work. I wind up with an error about the g property not being defined:
Exception: Error evaluating expression 'CoreStyle.g.primaryColor': Class 'LoremDialog' has no instance getter 'CoreStyle'.

NoSuchMethodError: method not found: 'CoreStyle'
Receiver: Instance of 'LoremDialog'
Arguments: []
A hint from James Hurford suggests that including the script that sets the global color on the same page that defines the styles will work:
  <body>
    <h1>Play Paper</h1>

    <lorem-dialog></lorem-dialog>

    <core-style id="legacy-button">
      :host paper-button {
        border: 5px solid {{g.primaryColor}};
        padding: 2px 5px;
      }
    </core-style>
    <script>
      CoreStyle.g.primaryColor = 'orange';
    </script>
  </body>
In fact, that does work. My Polymer element can then reference the "legacy-button" core style and the buttons will have orange borders. But that does not seem right to me. I feel like I ought to set the global property in the main page and use it inside Polymer elements. I should not have to build the entire style in the containing page—the containing page then needs to know too much about the internals of my Polymer element. That defeats the purpose of encapsulating all of this stuff inside Polymer elements, does it not?

To decide which I right, I try it in JavaScript as well. And find… the same thing. In JavaScript, I do not get the exceptions that I do from Dart, but I still do not see global core styles inside Polymer element <core-style> elements:
<link rel="import"
      href="/bower_components/polymer/polymer.html">
<!-- ... -->
<link rel="import"
      href="/bower_components/core-style/core-style.html">
<polymer-element name="lorem-dialog">
  <template>
    <paper-button label="Bottom" on-tap="{{toggleDialog}}"></paper-button>
    <paper-button label="Center" on-tap="{{toggleDialog}}"></paper-button>
    <!-- ... -->
    <core-style id="theme">
      :host paper-button {
        border: 5px solid {{g.primaryColor}};
        padding: 2px 5px;
      }
    </core-style>
    <core-style ref="theme"></core-style>
  </template>
  <script>
    Polymer('lorem-dialog', {/* ... */});
  </script>
</polymer-element>
With this, I get 5px solid button borders, but the color is empty so the buttons default to black:



What I can do in the JavaScript version of Polymer that did not work in Polymer.dart is make a local copy of the g property in my sample Polymer class:
<link rel="import"
      href="/bower_components/polymer/polymer.html">
<!-- ... -->
<link rel="import"
      href="/bower_components/core-style/core-style.html">
<polymer-element name="lorem-dialog">
  <template><!-- ... --> </template>
  <script>
    Polymer('lorem-dialog', {
      created: function() {
        this.g = CoreStyle.g;
      },
      // ...
    });
  </script>
</polymer-element>
This makes the g property available inside the <template> of my Polymer element:



So am I wrong in my assumption that I should be able to set a global CoreStyle property in the containing page and use it inside elements? It sure seems that way. I have a workaround, but a workaround implies that I am working against the library, not using it as intended. So the question remains: am I doing something wrong or is core-style not meant to work like this?


Day #161


Friday, August 22, 2014

Getting Started with Core-Style for Theming Polymer


I have enjoyed investigating Material Design. It provided much needed inspiration and new ideas on design—especially with regards to the use of motion in design. I remain concerned on how or if to use things like Paper Elements in “legacy” applications.

Paper elements are a Material take on custom Polymer elements. They look pretty, but they wind up looking—for lack of a better word—Googly:



Heck, even if I am following Material design without Paper elements, I find myself building applications that might look quite at home in a Google property:



In many cases, this would be a good thing. Let's face it, if I am designing something, it would always be a good thing. But there are times that a client wants to continue using their own styles in Polymer elements. There are even times that the people writing the checks cannot be convinced to stray at all from something like Bootstrap.

So what to do in those cases? Is a polymer element designed with Material principles impossible to use in legacy designs without looking impossibly out of place? To a certain extent, this is why I built <apply-author-styles>—to pull styles from a containing pages into a Polymer element.

That is helpful, but not really a theming solution. For theming, the Polymer team introduced core-style. Let's say that a client insists on a large orange border with initial caps and the lovely Arial font. From last night, paper buttons look like:



To get my legacy style in there, I can import core-style using the usual Polymer.dart:
  <head>
    <!-- Load platform polyfills -->
    <script src="packages/web_components/platform.js"></script>
    <script src="packages/web_components/dart_support.js"></script>

    <!-- Load component(s) -->
    <link rel="import"
          href="packages/paper_elements/paper_dialog_transition.html">
    <link rel="import"
          href="packages/paper_elements/paper_dialog.html">
    <link rel="import"
          href="packages/paper_elements/paper_button.html">
    <link rel="import"
          href="packages/core_elements/core_style.html">

    <!-- Start Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>
  </head>
Actually using core-style is a two step process. First I need to define the styles that I want to use:
    <core-style id="legacy-button">
      paper-button {
        text-transform: initial;
        font-family: Arial, sans-serif;
        border: 5px orange solid;
        padding: 2px 5px;
      }
    </core-style>
That should keep my clients happy. Now I need to actually apply it. In core-style parlance, I need to reference it:
    <core-style ref="legacy-button"></core-style>
With that, get:



This is a simple example. For actual theming, I might want to expose style variables that can be set. Core-style supports setting these in the global style group with CoreStyle.g. If I wanted to style my example <lorem-dialog> element, I might do so with:
    <lorem-dialog></lorem-dialog>
    <script>
      CoreStyle.g.fontFamily = 'Arial, sans-serif';
      CoreStyle.g.buttonBorder = '5px orange solid';
    </script>
I could then apply these inside my element with something along the lines of:
<link rel="import"
      href="../../../packages/polymer/polymer.html">
<link rel="import"
      href="../../../packages/core_elements/core_style.html">
<!-- ... -->
<polymer-element name="lorem-dialog">
  <template>
    <!-- ... -->
    <core-style id="legacy-button">
      paper-button {
        text-transform: initial;
        font-family: {{g.fontFamily}};
        border: {{g.buttonBorder}};
        padding: 2px 5px;
      }
    </core-style>
    <core-style ref="legacy-button"></core-style>
  </template>
  <script type="application/dart" src="lorem_dialog.dart"></script>
</polymer-element>
Only I am unable to make this work in Polymer.dart. Try as I might, the g property is not available:
Exception: Error evaluating expression 'g.buttonBorder': Class 'LoremDialog' has no instance getter 'g'.

NoSuchMethodError: method not found: 'g'
Receiver: Instance of 'LoremDialog'
Arguments: []
Darn it.

I think I am doing this right, but I am unable to discern a way to tease the g property into my Polymer.dart element. I will likely give this a try in JavaScript tomorrow to make sure that I am not overlooking something obvious.


Day #160

Thursday, August 21, 2014

Paper-Dialog-Transition (Polymer.Dart)


I love me transitions and animations, so I will take one more day to explore Paper Elements in Polymer.dart. Paper are the Polymer spin on Google's Material Design. Although I still worry that Material tends to look too Googly, I cannot argue with the concepts and emphasis that Material has for design. So I keep playing and learning.

Last night, I created a fairly simple paper-dialog in Polymer.dart:



What is most remarkable to me is that it worked so easily. A while back, I could barely get Core Elements to work in Polymer.dart. Now both Core and Paper work with ease. The team behind Polymer.dart has been active (thanks folks!).

One of the core tenants of Material Design is “Motion with meaning.” There is no motion in my paper-dialog and I can't help but notice that there is a paper-dialog-transition element. As if that were not enough to tempt me to investigate, the documentation on the JavaScript version is currently empty. So really, I can't help but investigate.

My first thought is to use the <paper-dialog-transition> as a drop-in replacement for last night's <paper-dialog>:
    <paper-dialog-transition heading="Title for dialog" opened="true">
      <p>Lorem ipsum ....</p>
      <p>Id qui scripta ...</p>
      <paper-button label="More Info..." dismissive></paper-button>
      <paper-button label="Decline" affirmative></paper-button>
      <paper-button label="Accept" affirmative autofocus></paper-button>
    </paper-dialog-transition>
I also add the appropriate <link> import of paper-dialog-transition to the document <head>:
  <head>
    <!-- Load platform polyfills -->
    <script src="packages/web_components/platform.js"></script>
    <script src="packages/web_components/dart_support.js"></script>

    <!-- Load component(s) -->
    <link rel="import"
          href="packages/paper_elements/paper_dialog_transition.html">
    <link rel="import"
          href="packages/paper_elements/paper_dialog.html">
    <link rel="import"
          href="packages/paper_elements/paper_button.html">

    <!-- Start Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>
  </head>
But that does not work. Loading the page, I do not find a pre-opened dialog. I find nothing. If I query in Chrome's JavaScript console for paper-dialog-transition elements, I find not one, but three:



The first two are added by the Polymer transformer in Dart Pub. The last is the real one that I added. And it does not behave like a <polymer-dialog>:
> d = document.querySelectorAll('paper-dialog-transition')[2]
    <paper-dialog-transition heading=​"Title for dialog" opened=​"true" hidden>​…​</paper-dialog-transition>​
> d.toggle()
    TypeError: undefined is not a function
It seems like <paper-dialog-transition> is adding those first two copies of itself for a reason. I am ultimately unable to figure out why by reading the code. Or rather, I stumble across some demo code that seems to do use the element.

The key seems to be using the IDs of the extra <paper-dialog-transition> elements in transition attributes of <paper-dialog> elements:
    <paper-dialog heading="Bottom Dialog" transition="paper-dialog-transition-bottom">
      <p>Lorem ipsum ....</p>
      <p>Id qui scripta ...</p>
      <paper-button label="More Info..." dismissive></paper-button>
      <paper-button label="Decline" affirmative></paper-button>
      <paper-button label="Accept" affirmative autofocus></paper-button>
    </paper-dialog>
I add a similar <paper-dialog> with a transition of paper-dialog-transition-center.

The final piece of the puzzle comes directly from the demo page. I add two buttons that invoked the toggle() method on the appropriate dialog:
    <paper-button label="Bottom" onclick="toggleDialog('paper-dialog-transition-bottom')"></paper-button>
    <paper-button label="Center" onclick="toggleDialog('paper-dialog-transition-center')"></paper-button>
  <script>
    function toggleDialog(transition) {
      var dialog = document.
        querySelector('paper-dialog[transition=' + transition + ']');
      dialog.toggle();
    }
  </script>
The result is quite pleasing pair of dialog transitions. One travels up from the bottom of the page, the other expands from the center:

video

The <paper-dialog-transition> transitions work nicely with the <paper-dialog> elements. Toggling the dialog, clicking elsewhere, clicking decline, even hitting escape all result in the transition reversing itself. All I needed to make this work was the addition of transition attributes and the import of paper_dialog_transition.html (removing this import disables the transitions).

I have to admit that the usage of <paper-dialog-transition> was not obvious to me. By extension, I have the feeling that I am a little weak on core-transition-css (which paper-dialog-transition extends). This may be worth a little more exploration. Tomorrow.

Day #159

Paper Dialogs with Polymer.dart


I have quite enjoyed playing with Material Design concepts of late. Interestingly, the solutions that I wound up with, both in Dart and JavaScript, rely on Core Elements instead of the material design based Paper Elements.

Rather than try to cram Paper into my very pretty Core/Material design in <x-pizza>, I start a completely new project. In this case, I am going to try to use the Paper elements directly in a Dart application rather than pulling them into another Polymer.dart element.

I start this “paper” application with a pubspec.yaml of:
name: paper
dependencies:
  polymer: any
  paper_elements: any
transformers:
- polymer
I had originally thought to skip the polymer dependency, but without it, pub serve will complain:
$ pub serve
Error in pubspec for package "paper" loaded from pubspec.yaml:
"transformers.polymer" refers to a package that's not a dependency
And if I try to remove the transformer, Dartium complains:
Exception: Missing initialization of polymer elements. Please check that the list of entry points in your pubspec.yaml is correct. If you are using pub-serve, you may need to restart it.
So, even though I am not creating my own Polymer elements, I need Polymer listed as a dependency. I also have to initialize the page in the same manner—the index.html file looks like:
<!DOCTYPE html>
<html>
  <head>
    <title>Play Paper</title>

    <!-- Load platform polyfills -->
    <script src="packages/web_components/platform.js"></script>
    <script src="packages/web_components/dart_support.js"></script>

    <!-- Load component(s) -->
    <link rel="import"
          href="packages/paper_elements/paper_dialog.html">
    <link rel="import"
          href="packages/paper_elements/paper_button.html">

    <!-- Start Polymer -->
    <script type="application/dart">
      export 'package:polymer/init.dart';
    </script>

  </head>
  <body>
    <h1>Play Paper</h1>
    <!-- ... -->
  </body>
</html>
That is the same setup that I use with any Polymer code—the same way to load the JavaScript polyfills (and associated Dart support), the same way to import the elements (Paper in this case) and the same way to start the Polymer.dart system.

As the elements being imported suggest, I am going to try a simple Paper dialog in Dart, so I add the following custom HTML (copied from the JavaScript documentation):
    <paper-dialog heading="Title for dialog" opened="true">
      <p>Lorem ipsum ....</p>
      <p>Id qui scripta ...</p>
      <paper-button label="More Info..." dismissive></paper-button>
      <paper-button label="Decline" affirmative></paper-button>
      <paper-button label="Accept" affirmative autofocus></paper-button>
    </paper-dialog>
The trick with this simple, open-by-default dialog is the opened attribute on <paper-dialog>. This would normally be accomplished via the toggle() method on <paper-dialog> elements, but I am simply hoping to verify that Paper works tonight. I will worry about additional interaction another night.

After starting the pub serve test web server, I find:



That was easy! But it certainly could look better—especially when I compare it to everything else in Material design. To get somewhat better results, I follow along with the Material Typography guide, and switch to the Roboto font:
  <head>
    <title>Play Paper</title>
    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
    <style>
      html { font-family: 'Roboto', sans-serif; }

      paper-button[autofocus] {
        color: #4285f4;
      }

      paper-button:hover {
        color: #2a56c6;
      }

      paper-button::shadow #ripple {
        color: #2a56c6;
      }
    </style>

    <!-- Load platform polyfills -->
    <!-- ... -->
  </head>
This winds up looking very Googly (and much better):



So Paper in Dart turns out to be blessedly easy—at least getting started with it. I may add some interaction or play with some additional elements tomorrow. Or, if that turns out to be too easy (because Polymer.dart works too darn well), then I may move on to other topics.


Day #158