Conditional statements with SCSS - class

Does anyone know if this is possible:
I want my brand colour to be $brand: #00cccc;
however, I want to change that on just one page, and that page is defined by a class on it's body.
body class="purple"
Now my mind is thinking that this would be ideal:
body.$class {
#if $class == 'purple'
{
$brand = #ff0033;
}
#else
{
$brand = #00cccc;
}
}
But that's not correct syntax at all.
Is this something that can be done in a similar way?

I believe you are looking for something like this?
#each $class in purple, none {
$brand: #00cccc;
$selector: 'body';
#if $class == purple {
$brand: #ff0033;
$selector: 'body.' + $class;
}
#{$selector}{
/* Use $brand */
}
}

I don't believe there is an #if statement you could create for that. In LESS you could redeclare the same variable inside body.purple and it would only apply inside that block, but in Sass/Scss redeclaring the variable will change it globally. This might not be ideal but you could redeclare the variable twice, once at the top for the purple color, and once at the bottom to set it back to its default value.
scss
// Global Variables
$blue: #0cc;
$purple: #f03;
$brand: $blue;
body {
color: $brand; // blue
}
.purple {
$brand: $purple;
color: $brand; // now purple
// all other styles
$brand: $blue;
}
.test {
color: $brand; // back to blue
}
css output
body {
color: #00cccc;
}
.purple {
color: #ff0033;
}
.test {
color: #00cccc;
}
Here is an article about the variable scope differences between LESS and Sass. http://blog.freeside.co/post/41774744757/less-vs-sass-variable-scopes

Yes, as of 2022 Sass does include #if and #else rules for flow control. More info on the Sass documentation site.
The #if rule is written #if { ... }, and it controls whether or not its block gets evaluated (including emitting any styles as CSS). The expression usually returns either true or false—if the expression returns true, the block is evaluated, and if the expression returns false it’s not.
For example, this Sass code:
$light-background: #f2ece4;
$light-text: #036;
$dark-background: #6b717f;
$dark-text: #d2e1dd;
#mixin theme-colors($light-theme: true) {
#if $light-theme {
background-color: $light-background;
color: $light-text;
} #else {
background-color: $dark-background;
color: $dark-text;
}
}
.banner {
#include theme-colors($light-theme: true);
body.dark & {
#include theme-colors($light-theme: false);
}
}
...will produce this CSS:
.banner {
background-color: #f2ece4;
color: #036;
}
body.dark .banner {
background-color: #6b717f;
color: #d2e1dd;
}
There is also support for #else if and Boolean operators and, or, and not.

Related

VSCode/TextMate syntax highlighting grammar -- matching code until end of line

I am writing a TextMate grammar to implement syntax highlighting in VSCode for a custom flavor of Markdown. I would like everything on the same line after ##$ to be highlighted as Javascript.
This is what I came up with:
"majsdown_execute_statement": {
"begin": "(.*?)(##\\$)",
"name": "test",
"end": "(\\r\\n|\\r|\\n)",
"beginCaptures": {
"2": {
"name": "keyword.control.majsdown"
}
},
"patterns": [
{
"include": "source.js"
}
]
},
That almost works:
But I would like the ##$ part to always be highlighted as a keyword. Here's a mockup (edited image) of my desired result:
I've tried a lot of different combinations of "begin" and "end", and I've also tried many nested patterns like the following one:
"patterns": [
{
"begin": "\\s",
"while": "^(\\r\\n|\\r|\\n)",
"patterns": [
{
"include": "source.js"
}
]
}
]
Unfortunately, nothing provides the result I desire. How can I achieve my desired result?
To handle multiline constructs, I think you'll have to provide modified embedded language(JavaScript) definition as well. Easiest way to do it would be to make ##$ a comment in JavaScript, so it'll not mess up existing constructs.
I have no idea about VScode syntax highlighting. I'll try to demonstrate the idea using HighlightJs. It has very similar way of defining a language.
Demo: View in full page mode.
hljs.debugMode();
// default code for the demo
src.innerText = `
My custom markdown highlighted with custom rules.
Here is how javascript code looks:
##$ function test()
##$ {
##$ // TODO: stuff
##$ let rand = Math
##$ .random()
##$ .toFixed(2);
##$ }
##$ var string = "hello";
##$ const string2 = \`some long
##$ string\`;
Leave one empty line to get out of the code block.
Here is some more code:
##$ var rand = Math.random();
##$ console.log(rand);
We are out of the second code block now.
`;
// define our markup language, say 'mdown'
let langDef = {
name: 'Mdown',
aliases: ['mdown'],
case_insensitive: true,
contains: [
{
className: 'mscript',
begin: /##/,
end: /\$/,
keywords: { name: 'mscript' },
contains: [],
starts: {
end: /^\s*$/, // end on empty line
returnEnd: true,
subLanguage: ['js'], //embedded language
},
},
],
};
hljs.registerLanguage('mscript', () => langDef);
// patch javascript multiline structures
let js = hljs.getLanguage('javascript');
for (let c of js.contains) {
if (c.begin === "`") { // handle templet literals
c.contains.unshift({
begin: /^##/,
"relevance": 0,
end: /\$/,
contains: [],
scope: 'mscripttag'
})
}
}
// console.log(js);
// make '##$' a comment :)
// So it'll not mess existing styling
js.contains.push(hljs.COMMENT(/##/, /\$/, { scope: 'mscripttag', relevance: 10 }));
// for demo update highlighted code on user input
let handleChange = (event) => {
let html = hljs.highlight(src.innerText, { language: 'mscript', ignoreIllegals: true }).value;
code.innerHTML = html;
};
// javascript patching done
document.addEventListener('DOMContentLoaded', handleChange);
src.addEventListener('input', handleChange);
body { font-size: .8rem; }
.input {
width: 46%;
background-color: #eee;
display: inline-block;
overflow: auto;
}
.output {
width: 50%;
display: block;
float: right;
background-color: #ccc;
}
/* add extra theme for our tag ##$ */
.hljs { color: #bbb !important; }
.hljs-mscript,
.hljs-mscripttag { color: red; }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/styles/base16/snazzy.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.4.0/highlight.min.js"></script>
<div>Edit below markdown code.</div>
<pre class="input"><div id="src" contenteditable></div></pre>
<pre class="output"><code id="code" class="javascript hljs">abcd</code></pre>
In case the library not available, here is how the output looks like:
In above code I have defined ##$ <jscontent> \n as a tag in our markdown language definition. And the content will be processed according to the embedded language JavaScript. Next I've modified the default JS language definition and added ##$ as a comment so it'll be harmless to exiting syntax. Now we just need to handle template literals which are multiline. In the literal definition I've added ##$ as a part of the literal, but with different scope/name/styleOption msscripttag.
I hope you'll be able to define similar syntax in TextMate for VSCode.
try using match instead...
"patterns": [
{
"name": "keyword.control.factory",
"match": "(\\w|-)[^(]*"
}
]
this code matches everything up to a "(" character
so your code look something like this:
"majsdown_execute_statement": {
"patterns": [
{
"name": "keyword.control.majsdown",
"match": "(?<=##\$)\\w*"
}
]
}
you can also try [^##$]*(\\w)
try it out here

the function ToHaveStyleRule doesn't work with hover

I created a component to be an Icons wrapper, so I don't need to keep editing the icon in the style of the file I use... However, when testing a property that can be applied to the "hover" component , the test says that this property does not exist, even passing!
file index
export type IconsProps = {
hoverColor?: colorTypes
}
const Icons = ({ hoverColor }: IconsProps) => (
<S.Wrapper color={color} size={size} hoverColor={hoverColor}>
{children}
</S.Wrapper>
)
file style
const wrapperModifiers = {
hoverColor: (theme: DefaultTheme, hoverColor: colorTypes) => css`
& :hover {
color: ${theme.colors[hoverColor]};
}
`,
}
export const Wrapper = styled.main<IconsProps>`
${({ theme, hoverColor }) => css`
> ${StyledIconBase} {
${!!hoverColor && wrapperModifiers.hoverColor(theme, hoverColor)}
}
`}
`
test
import { Coffee } from '#styled-icons/boxicons-solid'
it('deve testar o hover e o transform', () => {
const { debug, container } = renderWithTheme(
<Icons color="primary" size="5rem" hoverColor="secondary">
<Coffee title="Coffee" />
</Icons>,
)
expect(screen.getByRole('img', { name: /coffee/i })).toHaveStyleRule(
'color',
'#0487cc',
{
modifier: ':hover',
},
)
})
error
No style rules found on passed Component using options:
{"modifier":":hover"}
In my opinion, the error that you are getting is that you haven't properly selected the element which is having a hover color. Because of that reason, jest-styled-component is not able to find the element with a hover modifier.
& :hover {
color: ${theme.colors[hoverColor]};
}
You added a space between & and : which is not right. The hover will not be applied to the selected element.
Solution: Remove the space between them.
&:hover {
color: ${theme.colors[hoverColor]};
}

createMuiTheme overrides, for a particular component style

Is it possible to override the default style of a particular Material UI component style? Let's say I want have different types of MuiButton's...
<Button color="primary" variant="contained">Foo</Button>
<Button variant="text">Foo</Button>
With the default styles the first button will have a white text color and the second one will have a black text color. If I would like to change the text color default globally (which in this case I won't) I should use the following options for createMuiTheme:
const options = {
overrides: {
MuiButton: {
root: {
color: 'white',
}
}
}
};
However in this case I would only like to change the text color of the primary colored and contained variant button. How do I do this?
From the documentation it was not very clear to me but apparently you can target different classes in the component like so:
const options = {
overrides: {
MuiButton: {
containedPrimary: {
'& > .MuiButton-label': {
color: 'white'
},
}
}
}
};

Is there a rule to prevent empty lines at the beginning of the block?

Is there a stylelint rule to obtain the following?
I've read the documentation but I wasn't unable to find one
/* bad */
a {
color: pink;
}
/* good */
a {
color: pink;
}
This solves my issue
"declaration-empty-line-before": ["always", {
"except": ["first-nested"],
"ignore": ["after-comment", "after-declaration"]
}],
Ref: https://stylelint.io/user-guide/rules/declaration-empty-line-before/#first-nested

How do I make multiline hilighter on draft-js?

Now I make markdown highlighter.
Highlight inline is not so difficult. I use CompositeDecorator to rewrite text. https://facebook.github.io/draft-js/docs/advanced-topics-decorators.html
But I can't use multiline syntax (for example, codeblock). By default, newline becomes next block and decorator is handled by block to block.
Below image is example of my implementation. I can't decorate codeblock syntax.
How do I make multiline highlighter on draft-js?
Depends on what 'Highlight' style you want. Mostly the inline style should be enough if you just want some color or font size. check the color example.
While for block style, you need a custom CSS class and map the block to your class, refer this.
I found work around. Detecting markdown codeblock by dand on blockRendererFn.
// use blockRedererFn
<Editor
blockRendererFn={(block) => blockRenderer(block, this.state.editorState)}
editorState={this.state.editorState}
/>;
// detect code block and add fontFamily: monospace
// Example
//
// ```
// here
// ```
function blockRenderer(contentBlock, editorState) {
const type = contentBlock.getType();
if (type === "unstyled") {
const allText = editorState.getCurrentContent().getPlainText();
const allCount = countCodeBlockHeader(allText);
if (allCount > 0 && allCount % 2 === 0) {
const contentText = contentBlock.getText();
const [before, after] = allText.split(contentText);
const beforeCount = countCodeBlockHeader(before);
const afterCount = countCodeBlockHeader(after);
if (beforeCount % 2 === 1) {
if (afterCount % 2 === 1) {
return {
component: (_props) => {
return <code style={{
fontFamily: "monospace",
direction: "ltr",
unicodeBidi: "bidi-override",
}}>{contentText}</code>;
},
editable: true
};
}
}
}
}
}
function countCodeBlockHeader(text) {
return text
.split("\n")
.filter(l => l.match(new RegExp("^(```)")))
.length;
}
but it's dirty.