How to load google font in LitElement - lit-element

I am using LitElement and I am trying to load google-font at the element level.
I have tried returning it in an HTML literal in the connectedCallback event, but it does not work.
I could not manage to do it in the get styles() method.
Where should the <link...> statement be placed in the code?

You can import an external style sheet by adding a <link> element to your template, For details, see Import an external stylesheet.
Here's the demonstrate on StackBlitz.

You could import the google font in index.html easily:
<link href="https://fonts.googleapis.com/css?family=Kaushan+Script&display=swap" rel="stylesheet">
or you could create a common style.js file and include it:
const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<style>
#import url('https://fonts.googleapis.com/css?family=Kaushan+Script');
html,
body {
font-family: 'Roboto', Arial, sans-serif;
height: 100%;
margin: 0;
}
...
</style>`;
document.head.appendChild($_documentContainer.content);
var importDoc = window.document;
var style = importDoc.querySelector('style');
document.head.appendChild(style);
or:
class MyElement extends LitElement {
render() {
return html`
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Kaushan+Script">
`;
}
}
demo ( See the red a tag as I imported Kaushan+Script )

Related

How to style element content in Svelte?

<style>
color: red;
</style>
Some html content!
this code does not work. In the Angular framework it can be done by using the :host selector. :global can't help in my case, because I just want to style the component, where these styles are written.
How can I do this in Svelte?
Thank you
PS. I'm pretty new in Svelte :)
<style>
.hello {
color: red;
}
</style>
<div class='hello'>Hello world</style>
This will style all elements with the hello class and only in this component.
Now if we do something like this
App.svelte
<script>
import A from './A.svelte'
import B from './B.svelte'
</script>
<div>
<A/>
<B/>
</div>
A.svelte
Hello
B.svelte
world
then svelte renders that as
<div>Hello world</div>
And there's no way to define a selector to style only "Hello" but not "word". The documentation also mentions that it need something to attach a class to:
CSS inside a block will be scoped to that component.
This works by adding a class to affected elements, which is based on a hash of the component styles (e.g. svelte-123xyz).

Generate Styled Component from Serialized String

Is it possible to create a Styled Component from a serialized string? Do I need to parse my string out into actual functions to support interpolated variations? Example of a string I might store:
// this is a serialized string from storage:
background-color: black;
${p => p.white && css`
background-color: white;
`}
I'd like to be able to do something like this:
const MyComp = styled.div`
${myComponentStringFromStorage}
`;
<MyComp white /> // works, but displays the black background
This works for the base CSS rules, but it misses my functions as they're just passing in as text in the string and not real functions.
I'm guessing that I need to write a parser to break my string into real functions that I send into the styled component factory function?
Curious if Styled Components has a built in helper function for this, or if there's a different approach.
You can use eval on your stored string together with styled.div as a string in order to create a component out of it.
const MyComp = eval("styled.div`" + myComponentStringFromStorage + "`");
Keep in mind that eval might be dangerous, and that this will be done at runtime, so it will not work in environments that don't support template strings.
const { css } = styled;
const myComponentStringFromStorage = [
"background-color: black;\n",
"\n",
"${p => p.white && css`\n",
" background-color: white;\n",
"`}"
].join("");
const MyComp = eval("styled.div`" + myComponentStringFromStorage + "`");
class App extends React.Component {
render() {
return <MyComp white>Foo</MyComp>;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id="root"></div>

chrome extension shadow DOM import boostrap fonts

so I'd like to display bootstrap 3 icons in a shadowroot added from a chrome extension content script. So far its not working, help?
manifest.js does include the woff file in web_accessible_resources
shadow root has style tag with:
#import url(chrome-extension://__MSG_##extension_id__/fonts/glyphicons-halflings-regular.woff2);
What am I missing?
To import a font, you should not use #import url which is used to import a CSS stylesheet.
Instead, you should use the #font-face directive.
Also, this directive should be placed in the <head> element of the HTML page, not inside the Shadow DOM.
host.attachShadow( { mode: 'open' } )
.innerHTML = `
<style>.icon { font-family: Icons; color: green ; font-size:30pt }</style>
<span class="icon">&#xe084</span>`
#font-face {
font-family: "Icons" ;
src: url("https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/fonts/glyphicons-halflings-regular.woff2") format("woff2")
}
<div id=host></div>
You can read this SO answer for further details.

Isolated styled-components with #font-face

I'm using https://github.com/styled-components/styled-components.
I'm trying to work out the best strategy for components that require #font-face. I want to make sure each component is independent of its context, so I'm defining font-family styles on each them. But if I use injectGlobal in multiple components, I get multiple #font-face rules for the same font.
Should I just define the #font-face rules in my ThemeProvider entry-point component and live with the fact that the desired font might not be loaded by the browser?
That's exactly why we made injectGlobal. If you take a look at our docs they say:
We do not encourage the use of this. Use once per app at most, contained in a single file. This is an escape hatch. Only use it for the rare #font-face definition or body styling.
So what I'd do is create a JS file called global-styles.js which contains this code:
// global-styles.js
import { injectGlobal } from 'styled-components';
injectGlobal`
#font-face {
font-family: 'My custom family';
src: url('my-source.ttf');
}
`
As you can see, all we do here is inject some global styling-in this case #font-face. The last thing necessary to make this work is to import this file in your main entry point:
// index.js
import './global-styles.js'
// More stuff here like ReactDOM.render(...)
This will mean your font-face is only injected once, but still all of your components have access to it with font-family: 'My custom family'!
Doing it this way will give you a flash-of-invisible-text (FOIT), but that has nothing to do with styled-components-it'd be the same if you were using vanilla CSS. To get rid of the FOIT requires a more advanced font loading strategy rather than just #font-faceing.
Since this has nothing to do with styled-components, I highly recommend watching these two Front End Center episodes to learn more about how to best do this: "Crafting Web Font Fallbacks" and "The Fastest Webfont Loader in the West"!
And on the other side of the same coin in Chrome:
do not use #font-face inside injectGlobal if using e.g. react-router.
You will get re-paint of all of you app on each newly loaded route.
And this is why:
Same font-files downloaded on each new route.
As soon as you include font-face in a separate .css file - problem solves as stated in the last comment in this github issue.
injectGlobal is deprecated. Use createGlobalStyle
import { createGlobalStyle } from 'styled-components'
export const GlobalStyle = createGlobalStyle`
body {
font-family: 'Muli', sans-serif;
h1 {
font-weight: 800;
font-size: 36px;
p {
font-size: 18px;
}
}
`;
Then you can use it in your App.js:
import { GlobalStyle } from './styles/global'
class App extends Component {
render() {
return (
<ThemeProvider theme={theme}>
<>
<GlobalStyle/>
<Container/>
</>
</ThemeProvider>
)
}
}
I agree
I get reloaded with
import { createGlobalStyle } from 'styled-components';
import { silver } from 'shared-components/themes/colors';
export default createGlobalStyle`
#font-face {
font-family: "Proxima Nova";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url("/static/media/fonts/proxima_nova/ProximaNova_300.otf");
}
and react create app

2 Dojo Dijit Content Panes Side by Side - When Showing/Hiding one, the other will not resize dynamically

I have 2 Dojo Dijit ContentPane's side by side. I want to show/hide one of them, and have the other one stretch dynamically as needed. I am using an ESRI mapping example which uses 'dijit.layout.BorderContainer'. The "divRightMenu" will show/hide itself correctly, but, when opened, rather than pushing the "mapDiv" Div, it just appears on top of it. I want the "mapDiv" div to dynamically resize itself depending on the visible state of the "divRightMenu" div.
I'm including the full page code below - I have already experimented with style.Display = Block / None, style.Visibility = Visible/Hidden, as well as trying to dynamically set the width of divRightMenu from 1 pixel to 150 pixels. In all cases, divRightMenu appears "on top of" mapDiv, rather than "pushing" it like I want. If I change the code so that divRightMenu is visible by default on page load, then what happens when i hide it is it disappears, but the blank spot it once occupied still remains. Surely this is something simple I'm missing?
In the past (standard CSS), I would combine "float:left/right" with "overflow:hidden", and display:block/none, and could easily achieve the effect I'm after, but with Dojo/Dijit i'm not sure what i'm missing. I experimented with various combinations of float/overflow on the inline styling of the 2 DIV tags in question, but was unable to get it to work. I also noted that one poster mentioned that he programmatically created his dijit ContentPanes on the fly to overcome the issue, but I was hoping for a solution other than this (i need all the settings from the div's content to be retained between showing/hiding the div, and i'm not sure if re-creating it on the fly will allow for this).
Here are the 2 threads I found that touch on the topic:
Dojo Toggle Hide and Show Divs
Toggling the display of a Dojo dijit
These mainly deal with being able to hide the div or not. In my case I'm able to hide/show it, but just not able to get the desired auto-resize behavior from the remaining DIV.
In any case, full code sample is included below - any help would be appreciated:
Main Index.htm Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta name="generator" content="HTML Tidy for Windows (vers 14 February 2006), see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title></title>
<link rel="stylesheet" type="text/css" href="layout.css">
<link rel="stylesheet" type="text/css"href="http://serverapi.arcgisonline.com/jsapi/arcgis/1.2/js/dojo/dijit/themes/tundra/tundra.css">
<script type="text/javascript">
var djConfig = {
parseOnLoad: true
}
function ToggleVisibility(id)
{
//if (dijit.byId(id).domNode.style.width == '150px') {
if (dijit.byId(id).domNode.style.display == 'block') {
dijit.byId(id).domNode.style.display = 'none';
//dijit.byId(id).domNode.style.width = "1px";
//dojo.style(id, "visibility", "hidden");
}
else {
//dijit.byId(id).domNode.style.width = "150px";
dijit.byId(id).domNode.style.display = 'block';
//dojo.style(id, "visibility", "visible");
}
dijit.byId(id).resize();
//dijit.byId("mapDiv").resize();
}
</script>
<script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.2"></script>
<script src="layout.js" type="text/javascript"></script>
<script type="text/javascript">
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.ContentPane");
</script>
</head>
<body class="tundra">
<!--TOPMOST LAYOUT CONTAINER-->
<div style="border:4px solid purple;width:100%;height:100%;" id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">
<!--HEADER SECTION-->
<div id="header" style="border:4px solid red;height:85px;" dojotype="dijit.layout.ContentPane" region="top">
<div id="headerArea" style="border:2px solid black;height:50px;" dojotype="dijit.layout.ContentPane" region="top">Logo Here</div>
<div id="navMenuArea" style="border:2px solid green;height:35px;" dojotype="dijit.layout.ContentPane" region="top">Menu Here | <input type="button" onClick="ToggleVisibility('divRightMenu');" value="Toggle Right Menu"/></div>
</div>
<!--CENTER SECTION-->
<!--CENTER CONTAINER-->
<div id="mapDiv" style="border:2px solid green;margin:2px;" dojotype="dijit.layout.ContentPane" region="center"></div>
<!--RIGHT CONTAINER-->
<div id="divRightMenu" style="display:none;width:150px;border:2px solid orange;background-color:whitesmoke;" dojotype="dijit.layout.ContentPane" region="right">
Right Menu
</div>
<!--FOOTER SECTION-->
<div style="border:4px solid blue;height:50px;" id="footer" dojotype="dijit.layout.ContentPane" region="bottom">
Footer Here
</div>
</div>
</body>
</html>
layout.js Code:
dojo.require("esri.map");
var resizeTimer;
var map;
function init() {
var initialExtent = new esri.geometry.Extent(-125.0244140625, 14.4580078125, -80.0244140625, 59.4580078125, new esri.SpatialReference({
wkid: 4326
}));
map = new esri.Map("mapDiv", {
extent: initialExtent
});
dojo.connect(map, 'onLoad', function(theMap) {
dojo.connect(dijit.byId('mapDiv'), 'resize', function() {
resizeMap();
});
});
var url = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";
var tiledLayer = new esri.layers.ArcGISTiledMapServiceLayer(url);
map.addLayer(tiledLayer);
}
//Handle resize of browser
function resizeMap() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
map.resize();
map.reposition();
}, 800);
}
//show map on load
dojo.addOnLoad(init);
layout.css Code:
html, body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color:#FFF;
overflow:hidden;
font-family: "Trebuchet MS";
}
#header {
background-color:#FFF;
color:#999;
font-size:16pt;
font-weight:bold;
}
#headerArea {
text-align:left;
}
#navMenuArea {
text-align:right;
/*background:url(toolbar_bg.png) repeat #6788a2;*/
}
#topmenu {
background-color:#FFF;
color:#999;
font-size:16pt;
text-align:right;
font-weight:bold;
}
#footer {
background-color:#FFF;
color:#999;
font-size:10pt;
text-align:center;
}
Use a dijit/layout/BorderContainer, place the 2 contentpanes inside it, setting one of the 2 containers' region property to "center" and the other one to "right".
When you want to resize one of the contentpanes, call their "resize" method with an object containing the "w" property.
After calling resize on the contentpane, call "layout" on the border container.
Example :
require([
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dijit/form/Button",
"dojo/domReady!"
], function(BorderContainer, ContentPane, Button){
var container = new BorderContainer({
design : "headline",
gutters : false
}, "container");
var pane1 = new ContentPane({
region : "center",
id : "pane1"
});
var pane2 = new ContentPane({
region : "right",
id : "pane2"
});
var toolbar = new ContentPane({
region : "bottom",
id : "toolbar"
});
var btn = new Button({
label : "Change right side",
onClick : function(){
pane2.resize({ w : Math.random() * pane2.get("w") });
container.layout();
}
});
toolbar.addChild(btn);
container.addChild(pane1);
container.addChild(pane2);
container.addChild(toolbar);
container.startup();
});
See this fiddle : http://jsfiddle.net/psoares/vEsy7/

Resources