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

3 comments:

  1. This works for me

    https://gist.github.com/terrasea/6afe7502be80cfe5ff83

    ReplyDelete
    Replies
    1. Thanks, I'll play around with that. I have the script settings in the main page and the core-style source (with id attribute) in the element being styled. I think that's how it is meant to be used, but it's possible that I overlooked something.

      I'll try your approach in my code as well as trying mine in JavaScript. Hopefully between the two I can figure out what I'm doing wrong.

      Delete
  2. if you want to use "g" variable inside dart code you need to get it from Js context. In other words, you should declare that variable inside the Polymer Dart Class. Something like this:

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

    @observable var g = context['CoreStyle']['g'];

    ...
    }

    And in the Html, you cannot call g.fontFamily and g.buttonBorder you should call g['fontFamily'] and g['buttonBorder'] instead:


    paper-button {
    text-transform: initial;
    font-family: {{g['fontFamily']}};
    border: {{g['buttonBorder']}};
    padding: 2px 5px;
    }


    ReplyDelete