Pass generated Sass variables back to Gulp stream - css

On my project, I need to generate a second Sass file with theme-specific code, which will be generated when Sass (inside a Gulp task) is processed.
#mixin theme-set($key, $value) {
#if not global_variable_exists(theme-config) {
$theme-config: () !global;
}
// magic stuff here, which will be appended to $theme-config
}
.class1 {
#include theme-set(foo, bar);
}
.class2 {
#include theme-set(bar, baz);
}
The mixin theme-set will generate Sass map key-value pairs that will be appended to $theme-config.
Now, my issue is that I need to pass $theme-config back to the Gulp stream so I can generate a separate theme.sass (or theme.css) file as override stylesheet of the main.css
Then, the $theme-config should be imported in another file (ideally in the same stream, or passing it to another stream in the same task, using merge-stream) that would then generate theme.css.
Any advice on how to do this?

Related

Referencing class names between SASS modules

I'm confused how to reference my SASS module class name in another module. I have a Contact page module and a PhoneNumber module. In certain context on this page, I'd like to change the button inside the PhoneNumber. Using simplified example for clarity:
// src/pages/contact/index.module.scss
#use 'src/components/PhoneNumber/index.module' as phoneNumber;
.page {
phoneNumber.container {
:global(.button) {
background-color: pink;
}
}
}
It doesn't work, I'm not sure how to reference .container class name of PhoneNumber component.
There are 2 issues:
(1) If you include variables imported by directive #use ... as namespace you have to call them using the added namespace with character $ as well. So you have to call the variable with phoneNumber.$container, not: 'phoneNumber.container'.
(2) If you use a variable as element/id/class-name you have to wrap variables in #{$hereMyVariable} at all.
So try following code:
.page {
.#{phoneNumbers.$container}{
:global(.button) {
background-color: pink;
}
}
}
FURTHER EXPLANATION
Rule #use loads mixins, functions, and variables from other Sass stylesheets so you can use them. To separate same variables/mixins/functions names from different stylesheets you can separate them to different namespaces by #use scssFileName as myNamespace.
Now you can call i.e. variables with same name namespace1.$container and namespace2.$container from different stlesheetswith different values. Mixins works the same way just without $.
So: if you load #use filepath/filename as phoneNumber to your stylesheet and call phoneNumber.container SASS is looking to the other stylesheet for a function or mixin named container. From the context of you simplified example I assume you want to call a variable with the name of the class. Than you need to use $ and the brackets.
(Notice: But if you want just to name your class phoneNumber.container you should write .phoneNumber.containerso SASS will interpret it as classname and not as reference to the namespace of the other stylesheet ...)
Wider explanations how to use #use can be find in the excellent official docs: https://sass-lang.com/documentation/at-rules/use

Get CSS Parameter from Typescript Angular

Is there a way to Get a variable that is set in the global scss file from a ts file in Angular (8)
I'm looking to use some of the defined variables dynamically in a canvas element defined in the ts code.
I have a way to do this using a styles service based on
https://en.programqa.com/question/52907585/
Within Global.SCSS
#mixin ExportVariables($map, $prefix: null) {
$mapPrefix: "--#{$prefix}";
#if ($prefix){
$mapPrefix: "#{$mapPrefix}-";
}
body {
#each $name, $value in $map {
#{$mapPrefix}#{$name}: $value;
}
}
}
--idle-state: #29ABE2;
// Import each of these in the theme service
$stateSCSS:(
idle: var(--idle-state),
);
#include ExportVariables($stateSCSS, 'stateSCSS');
In the Service
const bodyStyles = window.getComputedStyle(document.body);
this.stateSCSS = {
idle: bodyStyles.getPropertyValue('--stateSCSS-idle'),
};
I think this answers your questions: access SASS values ($colors from variables.scss) in Typescript (Angular2 ionic2)
TLDR:
Unfortunately, there is no way to access SASS variable directly from typescript/javascript code. However, we can make a workaround to access those variables.
You can view the workaround in the post mentioned above

Gulp 4 compilling scss creates empty css file, but sass compiles correctly

I have installed gulp#4.0.0, and gulp-sass#4.0.2, and latest gulp-cli in Windows
When I set path for src() to lookup for 'assets/css/src/**/*.sass' files to create a stream, it compiles sass into css correctly.
But when I try to do so with 'assets/css/src/**/*.scss' files, it creates corresponding .css file, but empty one.
When I put intentionally erroneous code in .scss file, it throws an error, so gulp-sass actually does go through .scss file, but doesn't output the buffer into css code.
Even when I run node-sass manually to compile the script, it produces same issue, so it might be related more to node-sass as compiler.
note:
Syntax for both .scss and .sass are correct, and correct extensions are being used.
This is my gulpfile.js:
var gulp = require("gulp");
var sass = require("gulp-sass");
let paths = {
css : {
src : 'assets/css/src/**/*.scss',
dest : 'assets/css/dist'
}
};
function style() {
return (
gulp
.src(paths.css.src)
.pipe(sass())
.on("error", sass.logError)
.pipe(gulp.dest(paths.css.dest))
);
}
// $ gulp style
exports.style = style;
Could it be when you change the file extension to .scss the content is still using the old style indented syntax.
.SASS indented syntax
body
background-color: red;
h1
font-size: 2.5rem;
.SCSS syntax
body {
background-color: red;
h1 {
font-size: 2.5rem;
}
}
Make sure you're using the right syntax per extension.
You can read more about Sass Indented Syntax and the difference between SASS and SCSS
Resolved: It turns out that only style block that had some property was commented, thus causing .scss file return empty output, and sass won't compile empty blocks.

Making customizable css properties with React and CSS Modules/PostCSS

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.

JavaFX - generate compile time error if a class doesn't exist in css

I develop an application in JavaFX. Now i've got the Problem that i would like to generate an error at compile time if a css class, e.g. for a button, which if've set in the code doesn't exist in the corresponding css file.
Example:
main.java
String sCSS = this.getClass().getResource("/main.css").toExternalForm();
scene.getStylesheets().add(sCSS);
Button btn = new Button("Hello JFXWorld...");
btn.getStyleClass().add("button"); // should show compile time error
main.css
.buttonWithWrongName {
-fx-background-color: red; }
My solution would be the following, but I'm looking for advice how I can realize it.
I include an preprocessor or create an new project or something like that which parses the css code and dynamically generates an enum (into a .jar). And this jar i could include into my Project. In the best case ant would trigger the build of the enum automatically if no preprocessor is used.
again an Example:
Css file is the same as above.
{
Do preprocessor stuff for the css file here (parse and create enum) and build it to a jar file.
}
main.java
String sCSS = this.getClass().getResource("/main.css").toExternalForm();
scene.getStylesheets().add(sCSS);
Button btn = new Button("Hello JFXWorld...");
// will throw an compile time error becaus the eMainCSS enum only contains the class ".buttonWithWrongName"
btn.getStyleClass().add(eMainCSS.button.toString());
// works fine
btn.getStyleClass().add(eMainCSS.buttonWithWrongName.toString());
I'm using Eclipse (Neon) and JDK 1.8.0.
I hope there's a solution.
Thank you for the answers.
Best Regards,
Max S.
-- Edit --
Solution:
I've used an Ant WatchTask to watch at all my less files in the project.
If I change something in the less file, ant will run a self written jar file with the file name as parameter. The jar converts the less file to a css file (with less4j) and the css file to a java file (my own parser) which contains the enum.
Note: Youre not allowed to change anything in the enum. Even if you do, after the next changes in the less file, itll be gone.
The result looks like this:
Stylesheet.less:
.button { -fx-stroke-width: (1 + 1); }
#anotherButton { -fx-stroke-width: (1 + 2); }
to Stylesheet.css:
.button { -fx-stroke-width: 2; }
#anotherButton { -fx-stroke-width: 3; }
to Stylesheet.java:
// Auto-generated java file
public enum Stylesheet {
C_BUTTON("button"),
ID_ANOTHERBUTTON("anotherButton");
private final String sValue;
Stylesheet(String sValue) {
this.sValue = sValue;
}
#Override
public String toString() {
return this.sValue;
}
}
Now the compiler will throw an error at the compile time if the class or id which i'm using in javafx doesn`t exist.
Best Regards,
Max S.

Resources