Shadow dom usage in polymer 3 app (youtube.com example) - polymer

UPDATE: https://github.com/Polymer/polymer/issues/5551 - they use shadyDom
Youtube team recently updated their code to Polymer 3.x
If you go to youtube and open dev tools, you don't see any shadow dom at all:
However, when you start a new Polymer 3 app, shadow dom is here, as it was in previous versions.
There are a lot of discussions about how great it will be to be able to render certain components without shadow dom. Seems like youtube team has succeeded in this.
Shadow dom is great for component development, but pages, for
instance, should not be treated as components, IMHO. Treating
everything as a component (with ShadowDom) turns out to a be pain -
issues with styling, third party libs and more.
My question is: How youtube team achieved this?

Posibly they are using this:
polymer reference
emphasis mine :
Customize DOM initialization
There are several points where you can
customize how Polymer initializes your element's DOM. You can
customize how the shadow root is created by creating it yourself. And
you can override the _attachDom method to change how the the DOM tree
is added to your element: for example, to stamp into light DOM instead
of shadow DOM.
Stamp templates in light DOM
You can customize how the DOM is stamped by overriding the _attachDom
method. The method takes a single argument, a DocumentFragment
containing the DOM to be stamped. If you want to stamp the template
into light DOM, simply add an override like this:
_attachDom(dom) { this.appendChild(dom); } When you stamp the DOM template to light DOM like this, data bindings and declarative event
listeners work as usual, but you cannot use shadow DOM features, like
and style encapsulation.
A template stamped into light DOM shouldn't contain any tags.
Styles can be applied by an enclosing host element, or at the document
level if the element isn't used inside another element's shadow DOM.
About the styling in litelement, now you can do:
static get styles() {
return css`
:host {
display: block;
height: 100%;
}
.boxing rect {
x: -24;
y: -14;
width: 48px;
height: 28px;
rx: 8;
ry: 8;
}
.copia rect.text {
width: 135px;
height: 30px;
stroke:blue;
stroke-width: 1px;
}
text {
font-size: 20px;
font-family: Arial;
}
${miGestorEstilos.getDibujaGafa()}
${miGestorEstilos.getDibujaForma()}
`
}
Notice that this function can be shared across modules, and is composable with other functions returning also "CSS"

Related

Vaadin - print grid with CSS

Inside vaadin-grid.css I managed to get the #table element which contains the grid's rows
and with for example
#table th {
backround-color:green;
}
I can change its color.
Now I need to do that only when the page is printed.I tried adding inside vaadin-grid.css
#media print {
#table th {
backround-color:green;
}
}
but that has no effect.Note that I print the page using javascript print().
I added an id="viewfgrid" (as seen in the screenshot) to the enclosing grid and with that now when I add
inside shared-style.css
#media print {
#viewfgrid {
outline:green;
}
}
I can access and change the grid when printing.
However I can't access the inside table with the rows.I tried various variations like
#media print {
#viewfgrid #table {
background-color:green;
}
}
#media print {
#viewfgrid :host > table {
background-color:green;
}
}
but no effect.
How can I access that table ?
Also as a secondary question why can I access #table from within vaadin-grid.css without prepending :host ? when I do that , it has no effect
thanks
I’m not sure why #media print would not work from within the Grid’s shadow DOM styles. Did you try in different browsers? I wonder if there’s some browser bug/limitation here, similar to the fact that you can’t define a #font-face inside shadow DOM.
Also as a secondary question why can I access #table from within vaadin-grid.css without prepending :host ? when I do that , it has no effect
The host selector targets the same element as the #viewfgrid ID. To select a host element with a specific ID, you can use :host(#viewfgrid) inside the shadow DOM styles.
Notice, that you should not rely on any ID, class name, or raw tag name selectors when styling Vaadin components (for example #table or th. Those are considered internal implementation details / private API, and can change in any release. You should only rely on the :host(...) and [part~="..."] selectors and state attribute selectors (for example, [focused]).
If there really is a limitation in using #media print inside shadow DOM styles, I think your best option is to use the ::part() selector, which allow you to style named parts inside the shadow DOM from the outside/light DOM styles. That is actually a more robust method than relying on injecting styles into the shadow DOM (via the frontend/mytheme/components/vaadin-grid.css file).
styles.css:
#media print {
#viewfgrid::part(cell) {
background-color: green;
}
}
The API docs show all available parts of the Grid (look for the "Styling" section): https://cdn.vaadin.com/vaadin-web-components/23.2.0-alpha3/#/elements/vaadin-grid
Grid is by design not very printing friendly as it has been designed for "infinite vertical scrolling". You wont for example have headers and footers per page. If you want to include "report" functionality to your application, it is better approach to create separate report view that is designed printing friendly instead of screen use. This will allow you to use different layouting and components in it. You can for example generate multiple Grid's for each page. Or use BeanTable component from Directory, which generaters HTML Table without shadow DOM.
Because apparently you can't access the shadow dom from CSS when there's no 'part' tag on the element,as is the case with this table,I got it by using Javascript as in :
UI.getCurrent().getPage().executeJs("const tabledom = document.querySelector(\"#viewfgrid\").shadowRoot.querySelector(\"#table\");
tabledom.style.cssText+='.....' "
So now this snippet is called when the user clicks on a Print button and you can do whatever with the element's style.In my case I flatten the table so that it can be printed without the scrollbar intervening.

Can you set body id dynamically in React?

I am trying to implement dark mode in my app.
The idea is to add this to the root element:
<div id="dark">
And then this in CSS:
#dark {
background-color: #1A1A2E;
}
And then in Css, customize each dom element by using classes. For example, here I will work on cards:
#dark .card-body {
background-color: #16213E !important;;
}
#dark .card-header {
background-color: #0F3460 !important;
}
Now, this works perfectly fine.
But, with Modals, it does not work. I think it's because Modals are not rendered initially so for some reason the dark style does not apply to them.
What worked though is adding id="dark" to each modal:
#dark .modal-header {
background-color: #0F3460 !important;
}
#dark .modal-body {
background-color: #16213E !important;;
}
#dark .modal-footer {
background-color: #16213E !important;;
}
<Modal
// dark doesn't get applied automatically for modals because apparently modals are not rendered in the beginning
id="dark"
isOpen={this.state.isModalOpen}
toggle={this.toggleModal}
>
<div className="modal-header">
But, it'll be a pain to apply this to every single modal.
One solution mentioned here:
Modal should be the descendant of a tag which has id="dark". It is
loaded by the script right below the script tag and you are trying to
put 'dark' id on some div tag and the modal doesn't lie inside it,
thus the CSS selector not targeting it.
So, you need to put id="dark" on the body tag.
This solves the modals issue.
But, the problem is in my original implementation of dark mode, I am controlling that id in the root component like this:
// Root component
<div id={this.state.should_enable_dark_mode ? "dark" : "default"}>
And should_enable_dark_mode is managed like this:
manageDarkMode() {
window.addEventListener("storage", () => {
console.log("change to local storage!");
let should_enable_dark_mode = localStorage.darkMode == "true";
this.setState({
should_enable_dark_mode,
});
});
}
So the problem with the solution mentioned above is that I couldn't find a way to control the body tag from the react app. And I am not sure if it's a good thing to do.
What do you think I should do?
I see in the comments to your original question that you decided to just modify the body element in the browser DOM, which will probably work fine since the body element is not controlled by React and will likely not be changed by any other code.
I would however like to suggest a few improvements that makes it at bit less dirty:
use a data attribute like data-display-mode="dark" as a target for your CSS selectors instead of the ID. IDs are supposed to be stable and other tools and libraries (e.g. UI test tools) might rely on this.
use the Modal.container property to attach your Modals to the App element (the React-controlled global parent div defined in your React code, which you can control, not the app-root-div in index.html). Then set your data-display-mode attribute here by React-means. This way you will not bypass the virtual DOM.
use CSS custom properties for defining your colors, and then define all dark mode modifications in one place. Don't spread your dark-mode-styling code across multiple class selectors - you will have a hard time maintaining this.

React CSS Style is getting overridden

I have a react application which uses 3rd party libraries to create components.
The problem I am facing is one library css is getting loaded from CDN and other through node_modules. The css coming from CDN is overriding the css from other libraries.
CSS from CDN is written as -
.solar-theme button {
// css properties
}
CSS from other library is as -
.some-button {
// css properties
}
And button component in this library uses solar-theme as classname.
How to isolate the CSS coming from CDN to a single react component so that it doesn't overrides the other library css?
I am new to UI/UX. Please help.
Since you can't edit the CSS files from the libraries, you should write a new stylesheet to override certain properties as you come across them.
You might also have to use important! to enforce your properties.
For example:
/* Your custom stylesheet */
.some-button {
background-color: red !important;
}
If this does not work (it probably won't), you need to be more specific with your declarations.
Generally, the more specific you can be, the higher the chance of your style getting applied (when there are conflicting stylesheets).
So you can upgrade the declaration above by doing something like this instead:
/* Your custom stylesheet */
footer .container .some-button {
background-color: red !important;
}
It's called specificity. You can read more about it here:
https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

Overriding polymer element css

I want to customize an existing polymer element spinner-backdrop
by overriding its z-index css attribute.
All customization attempts from the outside have failed.
Because the z-index attribute is not exposed for outside customization.
I'm using that component wrapped inside an Angular2 app.
Should I create an new polymer element which extends that element?
Is there a more direct route, because I have never developed an polymer element.
The current 1.0.0 release of <spinner-backdrop> has no CSS property/mixin to set the z-index, but the --spinner-backdrop-overlay mixin was recently added and not yet released. You'd be able to use the mixin to set the z-index like this:
<style is="custom-style">
spinner-backdrop {
--spinner-backdrop-overlay: {
z-index: 0;
};
}
</style>
If <spinner-backdrop> is inside a Polymer element (<dom-module>), your <style> doesn't need is="custom-style". Otherwise, it's needed to apply the mixin properly.
demo (in <dom-module>)
demo (in index.html)

GWT + CSS Style Overloading

I'm looking at making some custom GWT widgets styled in a uniform fashion without requiring the designer to go into each widget's UI file every time they want something to appear differently. I would provide a bunch of base styles for elements in the widget and the designer comes along later and sets, in UIBinder, HTML, CSS, anything really, the style using the same selector.
For example:
I have a composite widget which I have setup to use a CSSResource. This CSS resource has a style named .myHeaderStyle which is applied to an element on the composite.
This composite is used in another GWT Widget and needs to appear slightly differently when used in the enclosing widget.
My hope here is that I can specify another style in the UIBinder definition of that UI also named .myHeaderStyle and have this style override the style specified in the composite widget's CSSResource.
However, in my attempts to make this happen even with !important included on the style properties that are to override the initial style, I'm only getting the original .myHeaderStyle set on the composite widget.
I'm trying to specifically avoid adding/changing the style in the composite every time we compile, I want it to inherit from the enclosing page effectively overriding the composite widget's original styling.
Is what I'm trying to do possible in some form with GWT+CSS?
After building complex GWT apps for 6 years, I am a big proponent of using a single CSS file for the entire app, and never using CSS resources or UIBinder definitions. Then you can set ".myWidget" style in your widget, and your designer can do:
.myHeaderStyle {
font-size: 1.4rem;
}
.myWidget .myHeaderStyle {
font-size: 1.6rem;
}
In my opinion, this is the easiest way to maintain consistency throughout the app - all styles are in one place, using inheritance, rem, and other best practices. It's much easier for designers that CSS resources scattered throughout the app.
By the way, this is also the easiest approach to implement themes (or skins), or change CSS based on the screen size without touching the code.
EDIT:
This is an example from one of my apps:
<g:HTMLPanel>
<g:Label ui:field="logo" styleName="logo">My App</g:Label>
<div class="menu" >
<div class="tab" >
<g:Label ui:field="tab1" ><ui:text from="{constants.tab1}" /></g:Label>
<g:Label ui:field="tab2" ><ui:text from="{constants.tab2}" /></g:Label>
<g:Label ui:field="tab3" ><ui:text from="{constants.tab3}" /></g:Label>
</div>
</div>
</g:HTMLPanel>
Note that I use 'class' for div element, but styleName for a widget. I don't set style on my tab labels, because I use CSS to style all of them at once:
.tab>div {
float: right;
margin: 0 0 0 6px;
padding: 2px 6px;
width: 120px;
}