Custom Polymer element <x-strong> that works like the builtin <strong>? - polymer

How do you create a custom element such as <x-strong> that works like the builtin <strong>?
I've got as far as the following:
<polymer-element name="x-strong" noscript>
<template>
<style>
x-strong {
font-weight: bold;
}
</style>
???
</template>
</polymer-element>
HTML:
<x-strong>Hello, <em>Clem</em></x-strong>
// Would like this to render exactly the same as
<strong>Hello, <em>Clem</em></strong>
However, this has at least two problems:
I don't know how to get at the contents/children of the <x-strong> element. (All of the examples I've found show how to access attributes from the custom element, but not its content.)
For some reason the CSS selector within the <style> element needs to be x-strong--body, html and * all don't work.
Adding/removing the lightdom and noscript attributes modify the behaviour in slightly different ways, but no combination seems to replicate the builtin element. Extending <strong> also doesn't work (although I actually want to do this from scratch, as an exercise).

To render content from the light dom into your Polymer element's shadow use an insertion point: <content>. Also to style the host element, you can use the :host selector. Both are features of Shadow DOM.
<polymer-element name="x-strong" noscript>
<template>
<style>
:host {
font-weight: bold;
}
</style>
<content></content>
</template>
</polymer-element>
Demo: http://jsbin.com/EqaxOTo/1/edit

Related

Shared styles and external stylesheets in Polymer 1.1

I've read the new style modules recommendation in Polymer 1.1 and it works beautifully.
My issue here, again, as with the old approach is how could I move all my CSS to a CSS file and not just place it between a <style> tag in the HTML?
Here's an example.
I have a custom <ot-subscribe> element that looks like this:
<dom-module id="ot-subscribe">
<template>
<style>
paper-input {
--paper-input-container-underline: {
display: none;
};
--paper-input-container-underline-focus: {
display: none;
};
}
</style>
<form is="iron-form">
<paper-input placeholder="{{labelPlaceholder}}" no-label-float></paper-input>
<ot-button submit class="button-secondary">{{labelSubscribe}}</ot-button>
</form>
</template>
</dom-module>
As you can see I have a paper-input for which I want to hide the underlines.
This example works just fine.
Now, I need to move that CSS in an external CSS file, but keep it all working exactly the same. So the final markup would look something like this (I've added comments to explain the different approaches I've tried).
<dom-module id="ot-subscribe">
<template>
<!-- Both of these have absolutely no effect -->
<style type="text/css" src="external.css"></style>
<style src="external.css"></style>
<!-- This DOES work, however only for regular CSS, no custom properties or mixins would work -->
<!-- Also, it's deprecated: https://www.polymer-project.org/1.0/docs/devguide/styling.html#external-stylesheets -->
<link rel="import" type="css" src="external.css">
<!-- Using a style module DOES work, however we're just moving the issue, not solving it, since the CSS must still be in the HTML not in an external CSS file -->
<style include="shared"></style>
<form is="iron-form">
<paper-input placeholder="{{labelPlaceholder}}" no-label-float></paper-input>
<ot-button submit class="button-secondary">{{labelSubscribe}}</ot-button>
</form>
</template>
</dom-module>
Why do I need this? One word: Sass.
Has anyone else ever encountered this issue? Has anyone found a solution?
Or to summarize my question, how the heck does one use Sass with Polymer?
As far as I know this is not supported. There are tools available that create style-modules from CSS files automatically though.
https://github.com/Polymer/polymer/issues/2429
build step: https://github.com/MaKleSoft/gulp-style-modules
web service: https://poly-style.appspot.com/demo/

What's the right way to define the <content> tag?

When defining an insertion point for light DOM in WebComponents, is there any difference between these two syntaxes?
<template id="my-element">
<content></content>
</template>
and
<template id="my-element">
<content/>
</template>
What's the right or the best way to define the tag?
I tested both syntaxes in Firefox/Chrome and they behave identically (at least in a simple test).
Look at https://developer.mozilla.org/en-US/docs/Web/HTML/Element/content :
Tag omission: None, both the starting and ending tag are mandatory.

Usage of Polymer 1.0 paper-styles Element

Unfortunately, I'm finding the current documentation/examples for the usage of paper-styles a bit lacking. I'm not an experienced CSS guy (relative newbie actually), so I could really use examples of how to implement Polymer 1.0 application-wide styling in order to be used by all of it's custom elements (i.e. by applying classes to any tags in those custom element's local DOMs). I did this kind of thing relatively easily in Polymer 0.5 using core-styles, but it has changed enough in 1.0 to confuse me, particularly without full docs/examples to work from. It also seems there may be a few ways to accomplish this. I'm also wondering if paper-styles is still considered experimental in 1.0? There are no docs or examples for it's use in polymer 1.0 online element catalog (https://elements.polymer-project.org/elements/paper-styles), although I did come across 'some' on it's gitHub repository.
The general misunderstanding seems to be, that just by importing the paper-styles element, the document gets styled according to the material design specs. That's not the case.
You just get all the variables and mixins.
Then you need to apply them to each and every element inside your custom-element the way you see it fit.
Here is an example element:
<dom-module id="demo-element">
<template>
<style>
:host {
display: block;
background: var(--paper-blue-500);
padding: 20px;
}
.title { #apply(--paper-font-title); }
button { #apply(--paper-font-button); }
</style>
<h1 class="title">Hello World</h1>
<button>Demo</button>
</template>
<script>
Polymer({
is: 'demo-element'
});
</script>
</dom-module>
Luckily the styles are nicely structured inside just four files with each just a couple of hundred lines max.
One thing you can do when documentation is lacking is search through other projects that are using the code you would like to use. paper-tabs, for example, uses paper-styles. You can see an example import of paper-styles/color.html in paper-tabs.html. The value --paper-yellow-a100 is being used in paper-tabs.html. Below is an example of using various CSS variables (var) and mixins (#apply) defined in paper-styles to apply style to the main document.
<!DOCTYPE html>
<html>
<head>
<title>paper-styles Example</title>
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html" />
<link rel="import" href="bower_components/paper-styles/paper-styles.html" />
<style is="custom-style">
.shadow {
#apply(--shadow-elevation-16dp);
}
section {
background-color: var(--google-blue-700);
}
p {
#apply(--paper-font-display3);
}
</style>
</head>
<body>
<section class="shadow">
<h1>Example</h1>
<p>
This is an example using <em>paper-styles</em>.
</p>
</section>
</body>
</html>
Click here to learn more about styling in Polymer 1.0.
Concerning your question about paper-styles being experimental, on the Polymer home page in the catalog section it states:
Custom elements, built by the Polymer team, ready to use in your
applications.
However, in various locations on the site, including styling, there are mentions of experimental features.
the custom properties shim included in Polymer includes an
experimental extension
At this time using #apply would be considered experimental.
There is a page on the Polymer website titled Experimental features & elements you can look at for more information.

How to style lightDOM from shadowDOM (without using ::content)?

I try so solve the following problem. Please, see example:
custom-elements.html
<polymer-element name="ui-nav" class="_row _columned _cols-2 mobile_cols-12" noscript>
<template>
<content></content>
</template>
</polymer-element>
index.html
<ui-nav>
<div>Привет русским</div>
<div>Контакты</div>
<div>О себе</div>
</ui-nav>
main.css
._row {display: block;}
._row [class*="_cols-"] {float:left;}
._cols-2 > * {width: 20%;}
...
The example above works as expected: all the styles applied to ui-nav (using classes) inherited by all div child elements. However, what if I need to add additional classes to ui-nav in different case? For example
<ui-nav> <!-- case 1 -->
<div>Content</div>
...
</ui-nav>
<ui-nav class="border-green"> <!-- case 2 -->
<div>Another content</div>
...
</ui-nav>
In the example border-green will break the logic, because it overwrites predefined classes previously defined in class attribute of polymer-element. I tried to apply classes on content tag, but it doesn't work. As well as the following form doesn't work too:
<polymer-element name="ui-nav" noscript>
<template>
<div class="_row _columned _cols-2 mobile_cols-12">
<content></content>
</div>
</template>
</polymer-element>
So how can I apply already existing classes like _row _cols-2 to the elements of lightDOM without defining additional classes/styles using ::shadow, ::content etc?
The short answer is you can't.
You could include your stylesheet that contains these styles in your template, and use the last option where you wrap the content in a div with those classes, but that is likely to have some performance issues as the stylesheets will be inlined at runtime.
The only other option really is to use some shadow boundary piercing selector like ::shadow, /deep/, etc from your main stylesheet.

<content> within an anchor tag isn't switching cursor on hover

I should have specified that this is a polymer question and not native HTML.
I have a template like this
<template>
<a href="{{ href }}">
<content></content>
</a>
</template>
When I hover over the custom element my cursor iscursor:text and not cursor:pointer, this is an easy fix to apply cursor pointer, but I feel as if those kind of properties should be inherited. Is there any way to apply the content and inherit the a properties properly?
Example on jsfiddle here
Update: 1
An even bigger issue with this is that you can't right-click and select copy-link either.
Update: 2
I kind of think I get it now, <content> isn't being passed a height or width, so the outer most element (the custom one) is height 0, width 0. So the anchor has no room to expand. Hence the cursor isn't switching.
tried, no luck
::content * {
width:inherit;
height:inherit;
}
Update 3
This kinda worked.
I had to give the anchor a id=anchor and use jQuery.
$(this.$.anchor).append($(this).html());
This won't import font-awesome icons for some reason, where does.
Perhaps it's because it's not importing over the styles when I grab the HTML?
There's no error in the console either.
I dropped the to font-awesome within the polymer template and it worked, which is kind of crappy. Need a better solution.
This is a bug with Chrome's current implementation of Shadow DOM that will be fixed in Chrome 37.
You have nothing to make a link out of; you're "linkifying" an empty block.
If you give <content> some innards, you'll see the inherited style:
<template>
<a href="{{ href }}">
<content> Here is a link. </content>
</a>
</template>
Example Fiddle
I have no idea how you're actually using this element, but http://jsbin.com/qaqigizajuvi/1/edit is a simple example of how to make at least what I think you're trying to achieve, work.
If you're using {{ name }} macros, you'll need to declare attributes for each name that you use. There's also no point in a <content> block if you just want a linktext: use another attribute macro in your definition:
<polymer-element name="monkey-test" attributes="href label" noscript>
<template>
{{ label }}
</template>
</polymer-element>
and then instantiate it as either:
<monkey-test href="http://example.org" label="tadah"></monkey-test>
or set up a <monkey-test> element and then set its href and label attributes via JavaScript using e.href=... and e.label=... or e.setAttribute(name, value)
note that the noscript attribute is used here because there's no explicit script block with a new Polymer('monkey-test', { ... }) call. If we want a more complex element, we can't get away with noscript.