web pack css-loader generated css class names with react-bootstrap - reactjs

I'm using css-loader for web pack, and the configuration looks like this:
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?camelCase&modules')
}, ...]
And then in my jsx file I have something like this:
import styles from 'components/MyComponent/style.css'
export default class MyComponent extends React.Component {
render() {
return (
return <div className={styles.myComponent}>
<Media>
<Media.Left>
...
</Media.Left>
<Media.Body>
...
</Media.Body>
</Media>
</div>
)
}
}
And in my components/MyComponent/style.css file I have something like:
.myComponent .media-left {
vertical-align: middle;
}
And so my problem is, css-loader will generate random ids for both .myComponent and .media-left, which is seriously annoying. Because .media-left is a bootstrap class and I want it just left alone. Is there a way to make css-loader only generate an id for the top level css class?

You can have one loader for bootstrap and the other for the rest of your css, based on test config.
On another note, the modules part of your css-loader config is responsible random class names. You can use localIdentName config to format generated classnames to your liking.

So I figured this out. I need to use the global selector for every class that I want to remain global, something like this:
.myComponent :global(.media-left) {
vertical-align: middle;
}

Related

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 load css provided by webpack inside an IFrame created using "react-frame-component" library?

I'm trying to render my React component inside an iframe. I got it to work by using the library "react-frame-component". The problem is that the styles are loaded outside the iframe, at the end of "head" element. I want to change it to be loaded inside the "head" of "iframe" element.
I'm using Webpack to generate the bundles with JS and CSS included and I saw that I can change where "style-loader" will load the styles by setting the option "insertInto", but this is throwing an error:
Uncaught Error: Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.
This is my React component:
import Frame from 'react-frame-component'
...
ReactDOM.render(
<Frame id="someId">
<Provider store={Store.get()}>
<Container/>
</Provider>,
</Frame>,
document.body
);
This is my "style-loader" in Webpack configuration:
{
loader: 'css-loader',
options: {
insertInto: () => document.querySelector("#someId"),
},
}
I think the problem is that the component was not rendered when webpack tried to include the styles. How to solve this?
You would need to load the styles into a temporary element as placeholder, and then use Javascript to clone those styles into the new frame.
// index.html
...
<div id="dynamic-styles"></div>
...
// webpack.config.js
...
{
loader: 'css-loader',
options: {
insertInto: () => document.getElementById("dynamic-styles"),
},
}
...
// some.js
...
const stylesContainer = document.getElementById('dynamic-styles');
const frame = document.getElementById('someID');
const frameHead = frame.contentWindow.document.head;
[...stylesContainer.children].forEach(styleNode => {
const newStyle = document.createElement('style');
newStyle.textContent = styleNode.textContent;
frameHead.appendChild(newStyle);
});
I haven't tested the above snippet but I know the concept works. I feel it gets the point across.
There may be a better way to do this but I haven't looked into it enough to figure it out yet. It'd be nice to be able to get webpack to make separate style bundles so that each configured frame could just automatically lazy load it's own dedicated bundled css

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

Global Utility Classes with PostCSS / CSS Modules

Using CSS Modules, how can I apply a global utility class to multiple elements without duplicating the style declaration?
For example, here is a React component without CSS Modules. The relevant line is the div with two classes: widget and clearfix...
/* components/widget.jsx */
class Widget extends Component {
render() {
return (
<div className="widget clearfix">
<div className="widget-alpha">Alpha</div>
<div className="widget-beta">Beta</div>
</div>
);
}
}
.clearfix is a global utility class that I want to apply to many elements throughout my app:
/* util/clearfix.scss */
.clearfix {
&:before, &:after { content: " "; display: table; }
&:after { clear: both; }
}
I've seen various ways of importing .clearfix into a CSS Module, but in each case the style declarations are redefined for each occurrence where the class is applied. Here's one example:
/* widget.scss */
.widget {
// other styles
composes: clearfix from '../util/clearfix.scss';
}
Through trial and error, I found that you can declare :global in the selector where the utility class is employed (not where it's defined):
.widget {
// other styles
:global {
composes: clearfix;
}
}
To avoid messy and repetitive import and from statements, I used an index.scss file to import the utility files and then import that in any partial where a utility class is needed.

Resources