Accessing CSS Constants in GWT UiBinder Style - css

Using GWT 2.1, I am trying to create a CSS file that contains numerous constants and common styles. I would like to use the ui:style tag to include it in the UiBinder template:
<ui:UiBinder
xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
<ui:style field="css" src="constants.css" />
</ui:UiBinder>
I can easily utilize the styles for elements:
<g:FlowPanel styleName="{css.panel}">...</g:FlowPanel>
But attempting to use the constants in another Style block fails:
<ui:Style>
.templateSpecificStyle {
background-color: {css.royalBlue};
padding: 1em;
}
</ui:Style>
Oddly I do not receive a compile error. The obfuscated CSS class is created; however, the content is empty. Is there any way to access these CSS constants within another Style block? Is it possible using the older ResourceBundle / CssResource pattern?

After re-reading https://stackoverflow.com/questions/3533211/need-app-wide-css-constants-in-gwt/4143017#4143017 I see that the constants work if you add the template specific style within the style block:
<ui:Style src="constants.css">
.templateSpecificStyle {
background-color: royalBlue;
padding: 1em;
}
</ui:Style>
This is perfect for my needs.

It may be in your best interest to define these constants in some class, then use runtime substitution to include this constant in each CSS resource you intend to use.
CSSConstants.java
package com.foo.client;
public final class CSSConstants {
public static final String ROYAL_BLUE = "#4169E1";
}
Style block in UiBinder template
<ui:style>
#eval royalBlue com.foo.client.ROYAL_BLUE
.templateSpecificStyle {
background-color: royalBlue
}
</ui:style>
Note that even the name of the technique is "runtime substitution", the GWT compiler will replace royalBlue with a string literal because the value of royalBlue can be evaluated at compile time.
For more cool stuff that you can do in CSS resources, take a look at http://code.google.com/webtoolkit/doc/latest/DevGuideClientBundle.html#CssResource

Related

Does Blazor Web Assembly work with CSS variables in CSS Isolation files?

Does CSS variables work in a Blazor component with CSS islolation files ?
When my component named Test.razor has no CSS isolation file and has the style set:
<h1 class="mh1">Test</h1>
<style>
:root {
--mblue:#0000ff;
}
.mh1{
color:var(--mblue);
}
</style>
Test is indeed blue.
However if I put the styles in a isolation file name Test.razor.css it does not work.
:root {
--mblue: #0000ff;
}
.mh1 {
color: var(--mblue);
}
The component Test resides in the index page:
#page "/"
<Test></Test>
What am I doing wrong?
The answer is yes, but not so sure that you can use :root in a css isolation file (the class is no longer called :root in a css isolation file -- it gets a random suffix with css isolation).
My approach has been as follows:
Use a wrapper element to provide a context to assign the css variables to.
Then use the variable in the class you assign to the relevant element.
Test.razor
<div class="test-wrapper">
<h1 class="mh1">Text</h1>
</div>
Test.razor.css
.test-wrapper {
--mblue: #0000ff;
}
.mh1 {
color: var(--mblue);
}

What does :global (colon global) do?

In some SCSS files, I see the following:
:global {
/* ... */
}
I don't know if it is an SCSS feature or a CSS feature.
I tried searching about it but couldn't find any good results at first sight.
The :global operator is used in CSS Modules. Modular CSS uses a CSS Modules compiler to scope CSS styles within their respective modules (e.g., React component).
Here's an example from a React module (in the file ErrorMessaging.less for the ErrorMessaging.jsx React component):
:global(.ocssContainer) {
.ui_column {
padding-left: 0;
}
}
This gets compiled into:
.ErrorMessaging__alertContainer--1I-Cz .ocssContainer .ErrorMessaging__ui_column--3uMUS {
padding-left: 0;
}
But now I add a :global modifier onto .ui_column:
:global(.ocssContainer) {
:global(.ui_column) {
padding-left: 0;
}
}
And this is what it compiles to:
.ErrorMessaging__alertContainer--1I-Cz .ocssContainer .ui_column {
padding-left: 0;
}
Now .ui_column can apply to any child element with that style, including in a child React component, and not just .ui_column elements that are part of the ErrorMessaging React component.
It looks like they are using CSS Modules. If you follow the docs they say:
:global switches to global scope for the current selector resp.
identifier. :global(.xxx) resp. #keyframes :global(xxx) declares the
stuff in parenthesis in the global scope.
The :global selector keyword is used in css modules to specify that a class should not be scoped to the component in which it is defined. This selector allows the class to be used globally in the application, rather than just within a specific component. For example, let say you have a .is-global-class class defined in a CSS Module file, you can use :global(.is-global-class) to apply that class to an element and make it available globally.

Gwt Css and uibinder no-obfuscation not working

I have a Gwt widget library with configuration property:
<set-configuration-property name="CssResource.style" value="stable-notype"/>
which is expected to leave original css names, then a css file (example)
.invader {
width: 400px;
height: 400px;
background-color: #DBDBDB;
}
.invader .button {
background-image: url('merged.png');
width: 64px;
height: 64px;
background-position: 0px 64px;
background-color: #BA6622;
}
after that, a generated css resource
interface WidgetStyle extends CssResource {
String button();
String invader();
}
And when I call ensureInjected() on WidgetStyle instance (and/or) use styles programatically/in ui:binder with e.g.
<ui:style src="WidgetStyle.css" field="style" />
<g:HTMLPanel styleName="{style.invader}" ui:field="panel" />
Then, in result html file in browser instead of one injected css styles i got four defined selectors:
.org-invader-widget-client-WidgetStyle-invader;
.org-invader-widget-client-WidgetStyle-invader .org-invader-widget-client-WidgetStyle-button;
.org-invader-widget-client-MyWidget_UIImpl_GenCss_style-invader;
.org-invader-widget-client-MyWidget_UIImpl_GenCss_style-invader .org-invader-widget-client-MyWidget_UIImpl_GenCss_style-button;
Those pairs duplicate the styles above just with different names. I see that the second pair come as "MyWidget owned" styles, but how can I force all application to use only those css classes i defined in a .css file without any obfuscation?
Futhermore, the second pair of css-classess fails to apply properly. Only the first is applied, second is not matched.
What I did wrong here?
Ok, i found that accessing css with
<ui:style ... />
injects styles and css classes might get extra prefix, proper way for me was to access styles by a ClientBundle with
<ui:with ... >
Obfuscation overriding does not work 'by default' in SuperDevMode in *.gwt.xml and, if I am right, it has to be configured with DevMode run parameter.

How to override GWT obfuscated style for DataGrid header

I'm trying to figure out how to override the dataGridHeader style defined in DataGrid.css! GWT core. The GWT style name is obfuscated with adler32 so I can't simply use .dataGridHeader in my css. In my case I wish a simple change of white-space:normal.
I've seen may articles here about injecting css but they all appear to be class level rather than a sub style used within a component like DataGrid.
How do I override a header style used within a component like DataGrid?
Just like with any ClientBundle and CssResource: create an interface that extends Datagrid.Resources and overrides the dataGridStyle method with a #Source annotation pointing to your own CSS file (or possibly to both the original file and your own file, so they'll be combined together).
Doing it that way will override the style for all DataGrids in your app though (it actually depends on which CssResource instance gets ensureInjected() first: the one from the original DataGrid.Resources or the one from your sub-interface): because you use the same return type (DataGrid.Style), the obfuscated class names will be the same.
If you want to change the style on a case-by-case basis then, in addition, declare an interface that extends DataGrid.Style and use that as the return type to your dataGridStyle override: because the obfuscated class name is based on both the interface fully-qualified name and the method name, your DataGrid.Style sub-interface will generate different obfuscated class names than the original DataGrid.Style interface.
Then of course, GWT.create() your DataGrid.Resources sub-interface and pass it as an argument to the DataGrid constructor.
See also http://code.google.com/p/google-web-toolkit/issues/detail?id=6144
Thanks Thomas.
Just to make it easier for the readers...
Create a new Interface
public interface GwtCssDataGridResources extends DataGrid.Resources {
#Source({Style.DEFAULT_CSS, "gwtDataGrid.css"})
Style dataGrid();
}
Use a static reference
public static final GwtCssDataGridResources gwtCssDataGridResources = GWT.create(GwtCssDataGridResources.class);
static {
gwtCssDataGridResources.dataGrid().ensureInjected();
}
Finally create a new CSS file gwtDataGrid.css. Note that if you need to override a style, you have to use !important on each definition.
.dataGridHeader {
color: #FF0000 !important;
}
.dataGridFirstColumnHeader {
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
}
.dataGridLastColumnHeader {
-moz-border-radius-topright: 5px;
-webkit-border-top-right-radius: 5px;
}
That's it

How to declare dependent style names with UiBinder

I have a simple UiBinder widget containing a TextArea:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:TextArea visibleLines="3" />
</ui:UiBinder>
I want to control the background color of this textarea for writeable and read only states. GWT uses the "-readonly" style name decorator to achieve this. So I try this:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
.textBoxStyle {
background-color:yellow;
}
.textBoxStyle-readonly {
background-color:lightgray;
}
</ui:style>
<g:TextArea styleName="{style.textBoxStyle}" visibleLines="3" />
</ui:UiBinder>
Obviously this won't work because style names are obfuscated for CssResources resulting in something like this:
.G1x26wpeN {
background-color:yellow
}
.G1x26wpeO {
background-color: lightgray;
}
The result HTML for writeable textarea looks like this:
<textarea tabindex="0" class="G1x26wpeN" rows="3"/>
The read only textarea looks like this:
<textarea tabindex="0" class="G1x26wpeN G1x26wpeN-readonly" readonly="" rows="3"/>
How do I declare the style so GWT will obfuscate the primary part but not the "-readonly" decdorator?
I know that I can disable the obfuscation for the entire style name. But I'd like to keep the obfuscation while making use of the decorators.
At this moment (GWT 2.4) it is not supported, and it's not clear if/when it will be supported, see issue 4746 in the GWT issue tracker.
The workaround is to add #external, which disables obfuscation for those styles. In this case that would be:
#external textBoxStyle, textBoxStyle-readonly;
If you want to use this style for all your read-only TextAreas then I'd suggest just modifying the .gwt-TextArea-readonly style in your GWT theme CSS file.
Otherwise, I can only think of adding your custom style programmatically when you set the TextArea read-only.
PS: from the docs:
<set-configuration-property name="CssResource.obfuscationPrefix" value="empty" />` can be used for minimal-length selector names, but this is only recommended when the GWT module has total control over the page.
I recommend using this (with "empty" or "X" or other unused prefix) for much shorter class names - because at default settings you don't gain that much through obfuscation (textBoxStyle - 12chars, G1x26wpeN - 9chars, X0 - 2 chars ;)).
Why don't you try sth like this
public class MyFoo extends Widget {
interface MyStyle extends CssResource {
String normal();
String readonly();
}
#UiField MyStyle style;
/* ... */
void setEnabled(boolean enabled) {
getElement().addStyle(enabled ? style.normal() : style.readonly());
getElement().removeStyle(enabled ? style.readonly() : style.normal());
}
}
this would allow you change style if a text box is "normal" or readonly...
And off course, in the UiBinder you should have sth like
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>
<ui:style type='com.my.app.MyFoo.MyStyle'>
.redBox { background-color:pink; border: 1px solid red; }
.normal { color:black; }
.readonly { color:gray; }
</ui:style>
<div class='{style.redBox} {style.normal}'>I'm a red box widget.</div>
</ui:UiBinder>
Try Now This One I Hope You will get it.
With the <ui:style> element, you can define the CSS for your UI right where you need it
Note: <ui:style> elements must be direct children of the root element
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<g:TextArea visibleLines="3" />
</ui:UiBinder>
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style field='MyStyle'>
.textBoxStyle {
background-color:yellow;
}
.textBoxStyle-readonly {
background-color:lightgray;
}
</ui:style>
<g:TextArea name="myText" styleName="{MyStyle.textBoxStyle}" visibleLines="3" />
</ui:UiBinder>
Isn't there a typo in your UIBinder?
You have:
<g:TextArea styleName="{style.textBoxStyle}" visibleLines="3" />
.. but I think you need to be using "stylePrimaryName", ie.
<g:TextArea stylePrimaryName="{style.textBoxStyle}" visibleLines="3" />
But I guess this question has been answered really already..
Here's something valuable I figured out by putting together info from other posts in this thread especially...
If you use #external, you can override gwt styles. The problem is that is this change gets applied globally! It is possible, however, to extend & override select attributes without effecting every instance of a widget type. (This like the programmatic styling method of creating a css class with a gwt class name + a suffix and using addStyleDependantName().)
Here is an example of using UIBinder + a CssResource to extend a gwt style. I left out the CssResource part, but you'll get the idea...
In your xxxx.ui.xml file, expose the gwt style, but don't mess with it!
<ui:style>
#external .gwt-Button; .gwt-Button {}
</ui:style>
Then, style a widget it by specifying 2 (or more) styles in the styleName attribute. I.e. the gwt style, and the one (or more) from your resource.
<g:Button ui:field="submitButton_" text="Submit" styleName="{style.gwt-Button} {res.loginStyles.submitButtonStyle}" />
Here's the css class:
.submitButtonStyle{
margin: 3px 5px 5px 0px;
}
In this case, I defined a button that is styled in the standard method (easily changed via module inheritance) but with a specific margin that will remain fixed. This didn't mess up the global style, it didn't require defining all the attributes manually, and allowed for swapping the global styling at will with clean.css, dark.css, etc.

Resources