How to use a sass $ declaration in useEffect (jsx?) - reactjs

I have different styles set in a _variables.scss file. like
$secondary: #ffc500;
$tertiary: #ffdd69;
$quartiary: #fffbed;
I want to use different body colors so I want to change the body background in different pages like so:
document.body.style.backgroundColor = "red" });
this works nicely but now i want to use for example $primary instead of 'red'
I just can't make it work. does anybody have an idea?

You can use the sass :export keyword to pass variables from sass files to js files:
// colors.scss
$primary: #123456;
:export {
primary: $primary;
}
// main.js
import colors from './colors.scss'
colors.primary; // '#123456'
As far as I know this is a non-standard keyword, it is handled by webpack + sass-loader, but not all sass transpilers.

Related

Load mantine styles after Tailwind preflight

I'm trying to use Mantine and Tailwind together, however Tailwind's "preflight" base styles are overriding Mantine's resulting in a simple button being invisible.
You can disable preflight:
corePlugins: {
preflight: true
}
But I'd rather keep it enabled and load Mantine CSS after, per this suggestion.
Is there any way to specify order for this?
Create an Emotion cache using createEmotionCache from Mantine core, and set prepend to false. Then, call it inside MantineProvider's emotionCache prop:
import {
MantineProvider,
createEmotionCache
} from '#mantine/core';
const myCache = createEmotionCache({
key: 'mantine',
prepend: false
});
<MantineProvider emotionCache={myCache}>{children}</MantineProvider>
Two steps:
Add preflight: false in tailwind.config.js to disable the default
Copy out https://unpkg.com/tailwindcss#3.2.4/src/css/preflight.css refereed by https://tailwindcss.com/docs/preflight and import it in your entry point
So, in your global stylesheet where you imported the tailwind styles remove the base styles as they will override some mantine styles. It should look like this
#tailwind components;
#tailwind utilities;

Dynamically changing Less variables in React Gatsby app with Ant Design at runtime

We are building a White Label platform using React, GatsbyJs and Ant Design. We are stuck with Gatsby and Ant Design because we are migrating from an existing system and changing any of those would bring huge impact. Also, we must have a single deploy. Having a build for each White Label is not an option.
So, we need to be able to change style (mainly color) at runtime.
The problem is: Ant Design uses less variables to define it's themes and we're not able to change them at runtime, not even with less's modifyVars.
The thing is we MUST change less variables, and not global CSS or use other means
Ant Design derivates the main variables many times to get adjacent properties. So, for instance, if we define #primary-color as red, when we add a Button to the screen, Ant Design also defines it's border color, hover color, and many other details with different shades of red.
This means that, if we were to use other styling tool, we would need to generate those color derivations and replace every little property for every component. This would be chaos.
Scenario
We are using gatsby-plugin-antd and gatsby-plugin-less to load less and change vars at build time. Our gatsby-config.js looks like this:
module.exports = {
siteMetadata: {
siteUrl: 'https://www.yourdomain.tld',
title: 'yourtitle'
},
plugins: [
'gatsby-plugin-root-import',
'gatsby-plugin-typescript',
{
resolve: 'gatsby-plugin-antd',
options: {
style: true
}
},
{
resolve: 'gatsby-plugin-less',
options: {
lessOptions: {
javascriptEnabled: true,
modifyVars: {
'primary-color': '#FFFFFF',
'link-color': '#000000',
'success-color': '#FFFFFF',
'warning-color': '#000000'
}
}
}
}
]
};
We import styling in our gatsby-browser.js file:
import './src/styles/index';
Our styles/index has:
import 'tachyons';
import './global.css';
import './antd.less';
antd.less:
#import '~antd/dist/antd.less';
And global.css has some general CSS for the project.
It's working fine with the defined variables at build time.
What we attempted so far...
We have tried out this plugin:
https://github.com/mzohaibqc/antd-theme-webpack-plugin
Which supposedly does exactly what we need. But there's no example using Gatsby.
We then tried to add the plugin using the gatsby-node.js as mentioned here:
https://www.gatsbyjs.com/docs/how-to/custom-configuration/add-custom-webpack-config/
First, we tried using index.html as the indexFileName for the pluggin. It just doesn't work.
Then, following the plugin docs, we tried using indexFileName as false and importing the following scripts using Helmet at our pages/index.tsx:
<script> window.less = { async: false, env: 'production' };
</script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script> ```
Also didn't work. If we define indexFileName as false, we get memory over the heap.
If we keep indexFileName as 'index.html' and just add the scripts, we are able to call window.less.modifyVars and it returns successfully (we are logging the Promise's then and error) but it doesn't affect antd's variables.
We then tried doing something similar, but instead of loading less externally, we installed it as a node_module and imported it to the file and used it directly in a similar fashion. Got the same result: modifyVars runs and returns successfully but doesn't affect antd.
Then, we tried something a bit different: we removed gatsby plugins and tried importing less from antd directly, as suggested here:
https://ant.design/docs/react/customize-theme
So we imported it like this:
#import '~antd/lib/style/themes/default.less';
#import '~antd/dist/antd.less';
#import 'your-theme-file.less';
Also, no good. It's different from the previous scenario, because style gets updated after you save your code. No need to stop Gatsby, as the first solutions. But, modifyVars still has no affect on antd components.
Then, to isolate the issue, we tried to style a basic HTML component - a button - to check if the issue was with gatsby or antd. And... still no success. less.modifyVars didn't work to change a basic button style on runtime.
So, we think it's probably something between Gatsby and Less. We checked gatsby-plugin-antd and gatsby-plugin-less to see if we could find something, but found nothing useful.
We assume that the "less instance" or "less context" used by gatsby's less-loader during build time is not the same we are calling modifyVars on. So it doesn't affect the original vars.
Totally stuck. Please, help!
EDIT - SOLUTION
Ant Design team has just released - TODAY - a new alpha version that includes dynamic theming, using CSS Variables.
https://ant.design/docs/react/customize-theme-variable
It works fine, so far. Closing the issue.
EDIT 2
There's a more detailed solution on the accepted answer.
Ant Design team has just released - TODAY - a new alpha version that includes dynamic theming, using CSS Variables.
https://ant.design/docs/react/customize-theme-variable
It works fine, so far.
EDIT - Detailed solution
I removed gatsby-plugin-antd and gatsby-plugin-less from the project. Also removed the import of antd less file.
Instead, in my styles/index.tsx (which is imported in gatsby-browser.js), I'm importing the variables.min.css file:
import 'antd/dist/antd.variable.min.css';
Then, whenever I want to change Ant Design variables, I just use:
import { ConfigProvider } from 'antd';
...
ConfigProvider.config({
theme: {
primaryColor: '#[DESIRED_COLOR_HEX]'
}
});
Provider
Since this has to be done every time the site is loaded, I'm creating a ThemeProvider that wraps every page and defines the theme. It fetches theme data from the backend and sets Ant Design theme variables.
Example code:
import { Spin } from 'antd';
import React, { useEffect, useState } from 'react';
import { ConfigProvider } from 'antd';
import { Theme } from './theme.interface';
interface Props {
children: React.ReactNode;
}
export const ThemeProvider = ({ children }: Props): JSX.Element => {
const [themeVars, setThemeVars] = useState<Theme>(null);
useEffect(() => {
async function fetchMyAPI() {
const result = await getThemeFromBackend(); // Make API call with Axios
if (result) setThemeVars(result);
}
fetchMyAPI();
}, []);
useEffect(() => {
if (themeVars) {
ConfigProvider.config({
theme: {
primaryColor: `#${themeVars.primaryColor}`
}
});
}
}, [themeVars]);
return <div>{!themeVars ? <Spin size="large" /> : <>{children}</>}</div>;
};
And it can be used like this:
...
<ThemeProvider>
<h1>My page header</h1>
<p>Page content...</p>
</ThemeProvider>
...
Note: You can save theme data on local storage for performance improvement, so you don't have to call your backend everytime your site reloads. Maybe you'll just have to refresh it from time to time.

How to Use SVG with React and ReasonML?

With create-react-app and JavaScript/TypeScript, I understand I'm able to "import" an SVG as noted below. How may I do so with ReasonML?
import { ReactComponent as Logo } from './logo.svg';
function App() {
return (
<div>
{/* Logo is an actual React component */}
<Logo />
</div>
);
}
Create React App uses webpack to transform SVG files into React components. If you’re using Reason with CRA, then all you need to do is provide a binding to the generated component. However, CRA will only transform the SVG into a component if the import statement is written exactly a certain way, which isn't how BuckleScript outputs import statements. (There's a GitHub issue about it here.) You have to import it with raw JavaScript and then bind to the imported value:
%bs.raw
{|import {ReactComponent as _Logo} from "./logo.svg"|};
module Logo = {
[#react.component] [#bs.val] external make: unit => React.element = "_Logo";
};
/* And we can use it like a regular component: */
[#react.component]
let make = () =>
<div>
<Logo />
</div>;
According to the CRA docs:
The imported SVG React Component accepts a title prop along with other props that a svg element accepts.
For any of the other props you want to use, you'll have to add them to your external binding.
If you're not using CRA, then you'll need to configure your bundler to do the same transformation. I'm not familiar with the internals of CRA, but this seems to be the relevant code from its webpack configuration.
We can use SVGR to handle the webpack loading and then import the module as we normally would.
const webpack = require('webpack');
module.exports = {
entry: './src/index.js',
module: {
rules: [
//...
{
test: /\.svg$/,
use: ['#svgr/webpack'],
},
],
},
//...
};
module Logo = {
#bs.module(`../../../../src/img/logo.svg`) #react.component
external make: {.} => React.element = "default"
}
...
<Logo /> // works
source: https://blog.logrocket.com/how-to-use-svgs-in-react/
I am the author of another solution that doesn't involve webpack.
It's a tool that can transform your svg files directly into .re files: https://github.com/MoOx/react-from-svg
This can create files for react (dom) or react-native(-web) (=> files generated use react-native-svg).
Feel free to try it :)
For example you can do (when the tool is installed from npm)
$ react-from-svg src/SVGs src/SVGs/components --with-native-for-reason --remove-fill
This will turns the files from svg/SVGs into React components into src/SVGs/components compatible for React Native with the Reason syntax.
The last option remove all svg fill props so you can use them as icons.
Note that the generated components accept width, height & fill props so you can adjust them when used.
Last bonus: since webpack is not involved, you can use this transformation only when you update your SVGs files & use this code directly with a Node runtime (JSX from Reason gets removed when converted to JS so the code can be consumed directly via Node without any transformation - which can be handy for tiny static sites/pages).

how to use common less variable with styled component?

Say I have a styled component, in index.jsx
import './index.less';
class Input extends React.Component {
...
}
and my index.less files looks:
.input{
color: #whiteColor;
}
This index.less has to work with the mixin.less that imported in the root project.
So my question is, even though I imported the mixin.less, it prompts variable #whiteColor not found. Any idea to solve this?
I have felt the same pain, why isn't my styled component resolving less variables?
The syntax is simple JavaScript, just do:
.input{
color: ${props => props.whiteColor};
// or
color: ${props => props.theme.whiteColor};
}
But, at my company, we had thousands of less components, and we really thought that the less syntax was cleaner and definitely faster to write. We developed Styless.
It is a babel plugin that parses less and generates javascript code. Add it to your .babelrc file.
{
"plugins": ["babel-plugin-styless"]
}
Then, we can do!!
const Input = styled.input`
#highlight: blue; // can be overwritten by theme or props
background: darken(#highlight, 5%); // make green darken by 5%
`;
Check here to see how to use the theme provider and load variable from your index.less!
You can try import the mixin.less in index.less
I have been trying the same than you.
But then I thought.. it is that what I really want? Because styled-components propose a different approach to having a modular structure for your styles.
https://www.styled-components.com/docs/advanced Check theming, is amazing powerful.
Because in styled components you define the variables with javascript.
And if you want color manipulation like less, sass, you can check https://github.com/erikras/styled-components-theme
Its like forgetting about less, and sass and moving it to a new style modules.
Still, if you want to keep your defined style classes, you can do that:
class MyComponent extends React.Component {
render() {
// Attach the passed-in className to the DOM node
return <div className={`some-global-class ${this.props.className}`} />;
}
}
Check the existing CSS usage from docs:
https://www.styled-components.com/docs/advanced#existing-css

How do I apply custom CSS to Modal dialog - React-bootstrap

I am new to React here and I am trying to apply CSS to a Modal dialog.
I've created a css file: /css/mycss.css
/css/mycss.css
.test {
width: 90%;
color: red;
}
At the root level, I have my modal dialog JSX file:
MyModal.jsx
//more code above
<Modal
{...this.props}
show={this.state.show}
onHide={this.hideModal}
dialogClassName="test"
>
//more code below
As I understand it, I'm supposed to use the dialogClassName prop to apply CSS to the modal dialog. I'm trying to access the class selector in my CSS file and pass it into the prop as shown.
Do I have to import the CSS?
import test from '/css/mycss.css';
That didn't work. What do I do to get the CSS to show?
Edit:
I've tried
import styles from './css/mycss.css'; // dialogClassName='styles.test';
import { test } from './css/mycss.css'; // dialogClassName='test';
import .test from './css/mycss.css'; // dialogClassName='test';
import {.test} from './css/mycss.css'; // dialogClassName='.test';
import './css/mycss.css'; // dialogClassName='test';
None of that applies the CSS.
Edit 2:
I tried import styles from './css/mycss.css' again and then did dialogClassName = {styles.test};. That actually worked...but sort of. The text colors did change to red but the width of the Modal dialog is still pretty stagnant. It is not 90% of the screen or 10% of the screen no matter what I change the width attribute to. So first, why was the tutorial I was following telling me to pass a string to dialogClassName? And how do I get the width of the modal dialog to change?
You said that you are using webpack. If you don't have installed css loader.
npm install css-loader --save-dev
Now you can import your partial CSS files in React components. This example is when you have CSS files in the same direction as a js file.
import componentStyle from './componentStyle.scss';
There are more way how to import css files. This I use because you can go inside the file like this: className={componentStyle.classInside}.
Webpack example:
module.exports = {
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" }
]
}
};
Also, you can use SASS, LESS, etc. in the same way.
Try import './css/mycss.css';
Path should be relative to the file.
In .js file
import classes from './style.css';
dialogClassName= {classes.myModalStyle} as Modal attribute
In style.css
.myModalStyle{
width: 90%,
max-width: none!important;
}
Note: max-width: none!important is the most important part. Without it, resizing the width won't work

Resources