I'm trying to make a library of react components that's external to an application. This will be an npm module, loaded with Webpack. I'm styling the component using CSS Modules, and I'm trying to see how to make some of its properties customizable. For instace, background color.
I would like to use css variables for this to have for instance this syntax in the css file:
.myClass {
backgrond-color: var(--backgroundColor, red);
}
Where --backgroundColor is a variable I can set, and red is the default. My question is, is there a way I can pass variables to the .css file when loading it from the .jsx file? So I could pass a variables object to the component, which then would influence how it loads it style? Could I use PostCSS for this?
Thanks.
PS: I know this could be solved by using inline JS styles, but I'm trying to give CSS a shot first.
You cannot inject javascript into a css file and PostCSS can only transform your css files, but not inject/replace variables.
However, one way of doing this would be to create .scss (sass) files with default variables, e.g. $background-color: red; One could then import your module and .scss files to their .scss files and overwrite any variables like $background-color with their own variables if they wish.
I'm not sure I understood you right, but here what I'm thinking of:
When you are requiring .css file with Webpack it adds this css as a string to the <head> element of the page behind the scene.
Why don't you do what Webpack does using your own function, like so.
Your module:
import $ from 'jquery';
/* this function builds string like this:
:root {
--bg: green;
--fontSize: 25px;
}
from the options object like this:
{
bg: 'green',
fontSize: '25px'
}
*/
function buildCssString(options) {
let str = ':root {\n'
for(let key in options) {
str += '\t--' + key + ': ' + options[key] + ';\n'
}
str += '}';
return str;
}
/* this function adds css string to head element */
export const configureCssVariables = function(options) {
$(function() {
var $head = $('head'),
$style = $('<style></style>');
$style.text(buildCssString(options));
$style.appendTo($head)
});
}
Usage:
import {configureCssVariables} from './your-module';
configureCssVariables({
bg: 'green',
fontSize: '25px'
});
And your css is simple
/* default variables that will be overwritten
by calling configureCssVariables()
*/
:root {
--bg: yellow;
--fontSize: 16px;
}
.myClass {
backgrond-color: var(--bg);
font-size: var(--fontSize);
}
It can be acheived by adding PostCSS and the postcss-custom-properties plugin in your pipeline. It has a variables option which will inject JS defined variables (properties) to any file being processed.
This eliminate the need to #import anything inside every CSS module file.
const theme = {
'color-primary': 'green',
'color-secondary': 'blue',
'color-danger': 'red',
'color-gray': '#ccc',
};
require('postcss-custom-properties')({
variables: theme,
});
See how to use it with babel-plugin-css-modules-transform https://github.com/pascalduez/react-module-boilerplate/blob/master/src/theme/index.js and https://github.com/pascalduez/react-module-boilerplate/blob/master/.babelrc#L21 but that works with Webpack as well.
I actually found a solution that already does this and takes advantage of the latest standardized JavaScript features
https://github.com/styled-components/styled-components
It may just be what I was looking for.
I am using This tutorial as a reference, and I am trying to use the below piece of code in my project :
let _setPlaceholderText = ( string = "Click or Drag a File Here to Upload" ) => {
template.find( ".alert span" ).innerText = string;
};
It works fine with the tutorial code when I download it and tested it, but when I copy pasted exact the same code to my project it didn't work.
If I am not mistaken the problem has to do with this line of code :
template.find( ".alert span" ).innerText = string;
can anyone explain for me what is ".alert span"? the tutorial says that the above line attempts to find the .alert span element only. Unfortunately, it wasn't enough for me to understand how to get it to work in my project.
Any help please
It looks like you're looking at the inner text for a piece of CSS intended to modify the style of span elements contained within anything that has the class name alert.
It might looks like this:
<style type="text/css">
.alert span {
color: #ff0000;
}
</style>
For modifying something like this:
<div class="alert">
<span>There was an error!</span>
</div>
My website - www.forex-central.net - has the Google Translate drop-down widget on the top right of every page.
Only problem is it's a bit too wide for my website (5 cm), I would need a 4 cm version (which I've seen on other sites so I know this is possible)...but I have no idea how to tweak the code.
The code Google supplies for the widget I use is:
<script type="text/javascript">function googleTranslateElementInit() { new google.translate.TranslateElement({ pageLanguage: 'en', gaTrack: true, layout: google.translate.TranslateElement.InlineLayout.SIMPLE }, 'google_translate_element');}</script><script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
Any help would be greatly appreciated! I'm a bit of a novice and have searched for hours on this, not getting anywhere :-/
Something like this will get you started:
.goog-te-menu-frame {
max-width:100% !important; //or whatever width you want
}
However, you would also need to do something like:
.goog-te-menu2 { //the element that contains the table of options
max-width: 100% !important;
overflow: scroll !important;
box-sizing:border-box !important; //fixes a padding issue
height:auto !important; //gets rid of vertical scroll caused by box-sizing
}
But that second part can't actually be done because the translate interface is included in your page as an iframe. Fortunately, it doesn't have its own domain, so we can access it via Javascript like this:
$('.goog-te-menu-frame').contents().find('.goog-te-menu2').css(
{
'max-width':'100%',
'overflow':'scroll',
'box-sizing':'border-box',
'height':'auto'
}
)
But that won't work until the element actually exists (it's being loaded asynchronously) so we have to wrap that in something that I got here. Put it all together, you get this:
function changeGoogleStyles() {
if($('.goog-te-menu-frame').contents().find('.goog-te-menu2').length) {
$('.goog-te-menu-frame').contents().find('.goog-te-menu2').css(
{
'max-width':'100%',
'overflow':'scroll',
'box-sizing':'border-box',
'height':'auto'
}
)
} else {
setTimeout(changeGoogleStyles, 50);
}
}
changeGoogleStyles();
Whew.
You can use that same strategy to apply other styles to the translate box or perhaps alter the table styles to have it flow vertically instead of scroll horizontally offscreen, whatever. See this answer.
EDIT:
Even this doesn't work, because Google re-applies the styles every time you click the dropdown. In this case, we try and change height and box-sizing, but Google reapplies over those, while overflow and max-width stick. What we need is to put our styles somewhere they won't get overriden and add !importants [cringes]. Inline styles will do the trick (I also replaced our selector with a variable for succinctness and what is likely a negligible performance boost):
function changeGoogleStyles() {
if(($goog = $('.goog-te-menu-frame').contents().find('body')).length) {
var stylesHtml = '<style>'+
'.goog-te-menu2 {'+
'max-width:100% !important;'+
'overflow:scroll !important;'+
'box-sizing:border-box !important;'+
'height:auto !important;'+
'}'+
'</style>';
$goog.prepend(stylesHtml);
} else {
setTimeout(changeGoogleStyles, 50);
}
}
changeGoogleStyles();
The Google Translate widget creates an iframe with content from another domain (several files from Google servers). We would have to manipulate the content inside the iframe, but this so-called cross-site scripting did not work for me. I found another solution. I downloaded two of the many files which the widget uses, so I could edit them.
Bear in mind that Google can change its API anytime. The hack will have to be adapted then.
Prerequisite:
I assume that the widget is working on your website. You just want to fit it on smaller screens. My initial code looks like:
<div id="google_translate_element"></div>
<script type="text/javascript">
function googleTranslateElementInit()
{
new google.translate.TranslateElement({pageLanguage:'de', layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element');
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
If your initial code looks different, you might have to adapt your solution accordingly.
Special tools used:
Chrome DevTools (adapt for other browsers)
Procedure:
In Google Chrome, right-click on your page containing the Google Translate widget.
Click Inspect. A window or side pane will apper with lots of HTML info.
In the top line, select the Sources tab.
Browse the sources tree to
/top/translate.google.com/translate_a/element.js?cb=googleTranslateElementInit
Click the file in the tree. The file content will be shown.
Under the code window of element.js, there is a little button with two curly brackets { }. Click this. It will sort the code for better readability. We will need this readability in the next steps.
Right-click inside the element.js code > Save as…. Save the file inside the files hierarchy of your website, in my case:
/framework/google-translate-widget/element.js
Point your <script> tag to the local element.js.
<!--<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>-->
<script type="text/javascript" src="../framework/google-translate-widget/element.js?cb=googleTranslateElementInit"></script>
From now on, your website should load element.js from its local directory. Now is a good moment to check if your Google Translate widget still works. Also check in Chrome DevTools where the browser has taken the file from (Google server or local directory). It should sit in the sources tree under
/top/[your domain or IP]/framework/google-translate-widget/element.js?cb=googleTranslateElementInit
We need another file from Google servers. Browse the sources tree to
/top/translate.googleapis.com/translate_static/css/translateelement.css
Download this file after clicking the curly brackets { }. I saved it in my website files directory as
/framework/google-translate-widget/translateelement.css
In your website files directory, open element.js and change line 66:
//c._ps = b + '/translate_static/css/translateelement.css';
c._ps = '/framework/google-translate-widget/translateelement.css';
From now on, your website will also load translateelement.css from its local directory. Check this now.
Open your local translateeleent.css and append the following styles at the end:
/* Make all languages visible on small screens. */
.goog-te-menu2 {
width: 300px!important;
height: 300px!important;
overflow: auto!important;
}
.goog-te-menu2 table,
.goog-te-menu2 table tbody,
.goog-te-menu2 table tbody tr {
width: 100%!important;
height: 100%!important;
}
.goog-te-menu2 table tbody tr td {
width: 100%!important;
display: block!important;
}
.goog-te-menu2 table tbody tr td .goog-te-menu2-colpad {
visibility: none!important;
}
I borrowed the code from another answer: Google translate widget mobile overflow
The geometry might work now, but we broke another thing. The widget text showing “Select Language”, “Sélectionner une langue”, or whatever it says in you language, is locked to that language now. Since you want your other-language readers to understand the offer, the widget should adapt to their language as it used to work before our hack. Also, the listed languages’ names are affected. The reason for this bug can be found in the file element.js, which was silently tailored to our browser’s language setting. Look in element.js on lines 51 and 69
c._cl = 'fr';
_loadJs(b + '/translate_static/js/element/main_fr.js');
In my case, it was set to French (fr).
Correcting line 51 is as simple as
c._cl = 'auto'; //'fr';
Line 61 is trickier, because there is no 'auto' value available. There is a file main.js (without the _fr ending) available on Google servers, which provides English as a fallback, but we prefer the user’s language. Have a look in the file
/top/translate.googleapis.com/translate_a/l?client=…
It contains two objects. sl and tl meaning the source languages and target languages supported for translation. We have to check if the user’s browser is set to one of the target languages. There is a JavaScript constant navigator.language for this.
Edit element.js at line 69:
// determine browser language to display Google Translate widget in that language
var nl = navigator.language;
var tl = ["af","sq","am","ar","hy","az","eu","bn","my","bs","bg","ceb","ny",
"zh-TW","zh-CN","da","de","en","eo","et","tl","fi","fr","fy","gl",
"ka","el","gu","ht","ha","haw","iw","hi","hmn","ig","id","ga","is",
"it","ja","jw","yi","kn","kk","ca","km","rw","ky","ko","co","hr",
"ku","lo","la","lv","lt","lb","mg","ml","ms","mt","mi","mr","mk",
"mn","ne","nl","no","or","ps","fa","pl","pt","pa","ro","ru","sm",
"gd","sv","sr","st","sn","sd","si","sk","sl","so","es","sw","su",
"tg","ta","tt","te","th","cs","tr","tk","ug","uk","hu","ur","uz",
"vi","cy","be","xh","yo","zu"];
var gl = "";
if( tl.includes( nl )) gl = '_'+nl;
else
{
nl = nl.substring(0, 3);
if( tl.includes( nl)) gl = '_'+nl;
else
{
nl = nl.substring(0, 2);
if( tl.includes( nl)) gl = '_'+nl;
else gl = '';
}
}
_loadJs(b + '/translate_static/js/element/main'+gl+'.js');
//_loadJs(b + '/translate_static/js/element/main_fr.js');
… should do the trick.
Try using this in your CSS
.pac-container, .pac-item { width: 100px !important;}
where you can alter the with of the dropdown by altering 'the 100px' value.
This should work. Let me know if it doesn't and I'll have another look.
I've installed the codemirror editor succesfully.
But there is one issue regarding css of that editor.
You can check here what I mean.
So how can I display the color after 3rd line in the editor.
you should look at
<div class="CodeMirror-gutters" style=" /*height: some_pixel*/; "><div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 28px;"></div></div>
instead of some_pixel after press enter or any keyword it will automatically set the height of the line number,
if you have that problem on start you might want to see how to create at first,
there is three common method,
The simplest is to define your Text Area and just use this code:
var YourCodeMirror = CodeMirror.fromTextArea(YourDefinedTextArea);
The best is put values using code:
var yourCodeMirror = CodeMirror(PlaceYouWant, {
value: /*any code here :*/"function(){return 'anything'}",
mode: /*your mode ie.*/"javascript"
});
hope it helps
UPDATE: There is a manual site here : http://codemirror.net/doc/manual.html
CodeMirror parses HTML using the XML mode. To use it, the appropriate script must be included, same as with any other mode.
Add its dependency in your markup:
<script type="text/javascript"
src="/site.com/js/libs/codemirror/mode/xml/xml.js"></script>
and set the mode to xml:
config = {
mode : "xml",
// ...
};
In addition, you may want to configure the parser to allow for non well-formed XML. You can do so by switching the htmlMode flag on:
config = {
mode : "xml",
htmlMode: true,
// ...
};