I am using reactjs-popup, and one of it's props is contentStyle, which allow you to pass css-in-js object to style an internal div in the library.
however when I pass css object with #media in it, the library doesn't deal with it.
I wonder if there is a way to tell emotion to "translate" this object, or somehow wrap the library element, so it can treat the #media query as needed.
this is a code to demonstrate:
/** #jsx jsx */
import { jsx } from '#emotion/core';
import ReactJsPopup from 'reactjs-popup';
import { FC, PropsWithChildren } from 'react';
const Modal: FC<{}> = props => {
const style = {
padding: 0,
minHeight: '100%',
'#media (min-width: 576px)': {
minHeight: 'auto' // <----------- Doesn't work
}
}
return (
<ReactJsPopup contentStyle={style}>
{(close): JSX.Element => (
<div>
BODY
</div>
)}
</ReactJsPopup>
);
};
export default Modal;
Inline style objects currently do not support media queries.
The viable option here is to use the className prop to style the content. As the docs reads:
this class name will be merged with the component element: ex className='foo' means foo-arrow to style arrow, foo-overlay to style overlay and foo-content to style popup content
When using emotion, you can make sure that the selectors are unique using this property.
import { css } from "emotion";
<ReactJsPopup
className={css`
&-content {
color: red;
}
`}
>
</ReactJsPopup>
Note: The & is for the random classname that is going to be added by emotion. Followed by content that is added by the library
Related
New to react and styled-components and have probably got myself in a muddle through not understanding how it all works.
Let's start from the top.
I have a simple page (App.js) that renders two components "Knobs".
I want to pass each 'Knob' one or more properties so it can calculate its size and other relevant instance props. In the example below, one know is 200px in size, and it's sister is a 100px.
import React from 'react';
import Knob from './components/knob.js'
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
hello world
<Knob size={200} />
<Knob size={100} />
</header>
</div>
);
}
export default App;
So far so good.
Now inside the Knob component, I do all my transformations and ultimately have a scaled Knob.
The knob is a svg based component (abbreviated below but still long, sorry).
So - the good news is that it all works! But I know I am approaching this wrong.
In order to get it to work and use the this.state.size to calculate the appropriate font size for the component , I had to move the styled-component object into the class...and create an empty declaration outside the class (Styles).
So - my ask is two-fold:
I think my approach is philosophically damaged...and would love experts here to unscramble my brain.
How would you edit the code to make it not just work, but work right!
a) It seems to me that the entire Styles declaration belongs outside the class.
b) No idea why I have to reference this.state.xxxx twice
c) I think I am also mixing up the use of props and state.
Other than that it's perfect (:. But -- as you see from the screenshot below...it actually works.
Ugh.
import React from 'react'
import { Knob, Pointer, Value, Scale, Arc } from 'rc-knob'
import styled from 'styled-components';
// this is my weird hack to get things working. Declare Styles outside of the class.
var Styles = {}
export default class MyKnob extends React.Component {
constructor(props) {
super(props)
this.state = {
size: props.size,
value: props.value,
radius: (props.value/2).toString(),
fontSize: (props.size * .2)
}
//Now define styles inside the class and i can use the fontsize that is derived from the size passed by the parent component!
Styles = styled.div`
.vpotText {
fill: green;
font-size: ${this.state.fontSize+'px'};
}
`
}
// no idea why I need this block....but without it I get a whole bunch of
// error TS2339: Property 'value' does not exist on type 'Readonly<{}>'.
state = {
value: 50,
size: 100,
radius: '50',
fontSize: 12
}
static defaultProps = { value: 50, size: 100};
render(){
const customScaleTick = ({}) //abbreviated for readability.
return (
<Styles>
<Knob size={this.state.size}
angleOffset={220}
angleRange={280}
steps={10}
min={0}
max={100}
// note use of this.state.value to set parameters that affect the sizing/display of the component
value={this.state.value}
onChange={value => console.log(value)}
>
<Scale steps={10} tickWidth={1} tickHeight={2} radius={(this.state.size/2)*0.84} color='grey' />
<Arc arcWidth={2} color="#4eccff" background="#141a1e" radius = {(this.state.size/2)*0.76} />
<defs>
{/* GRADIENT DEFINITIONS REMOVED FOR READABILITY */}
</defs>
{/* NOTE: EXTENSIVE USE OF this.state.size TO ENSURE ALL PARTS OF THE COMPONENT ARE SCALED NICELY */}
<circle cx={this.state.size/2} cy={this.state.size/2} rx={(this.state.size/2)*0.8} fill = "url(#grad-dial-soft-shadow)" />
<ellipse cx={this.state.size/2} cy={(this.state.size/2)+2} rx={(this.state.size/2)*0.7} ry={(this.state.size/2)*0.7} fill='#141a1e' opacity='0.15' ></ellipse>
<circle cx={this.state.size/2} cy={this.state.size/2} r={(this.state.size/2)*0.7} fill = "url(#grad-dial-base)" stroke='#242a2e' strokeWidth='1.5'/>
<circle cx={this.state.size/2} cy={this.state.size/2} r={(this.state.size/2)*0.64} fill = 'transparent' stroke='url(#grad-dial-highlight)' strokeWidth='1.5'/>
<Pointer width={(this.state.size/2)*0.05} radius={(this.state.size/2)*0.47} type="circle" color='#4eccff' />
{/* THIS IS THE TRICKY ONE! */}
{/* IN ORDER TO GET THE FONT SIZE RIGHT ON THIS ELEMENT (svg) I NEED THE STYLE */}
<Value
marginBottom={(this.state.size-(this.state.fontSize)/2)/2}
className="vpotText"
/>
</Knob>
</Styles>
)}
}
here's a pic of the output:
a) This is how we use props variables in styled components:
const Styles = styled.div`
.vpotText {
fill: green;
font-size: ${props => props.fontSize}px;
};
`;
b) That way you won't need to call the state twice
render(){
return(
<Styles fontSize={this.state.fontSize}>
...
</Styles>
)}
styled-components are really cool once you get the hang of them.
d) Also, I suggest you make value it's own component instead of wrapping it and calling the class.
const StyledValue = styled(Value)`
fill: green;
font-size: ${props => props.fontSize}px;
`;
This looks like it would be a good use case for passing a prop into a Styled Component. It would look something like this:
var Styles = styled.div`
.vpotText {
fill: green;
font-size: ${props => props.size};
}
`
<Styles size={someSize}>
...
</Styles>
You can find the documentation here:
https://styled-components.com/docs/basics#passed-props
I would like to set global style for the react-select. For my understanding I can do 2 ways:
Using className and classNamePrefix and then target elements using CSS.
PROS: I can use the same style everywhere
CONS: Every new component must use exactly the same className and classNamePrefix
Example:
className='react-select-container'
classNamePrefix="react-select"
Result:
<div class="react-select-container">
<div class="react-select__control">
<div class="react-select__value-container">...</div>
<div class="react-select__indicators">...</div>
</div>
<div class="react-select__menu">
<div class="react-select__menu-list">
<div class="react-select__option">...</div>
</div>
</div>
</div>
Create external javascript file with "Provided Styles and State"
PROS: more flexible then CSS
CONS: Every new component must use style property using imported external file.
Example:
const customStyles = {
option: (provided, state) => ({
...provided,
borderBottom: '1px dotted pink',
color: state.isSelected ? 'red' : 'blue',
padding: 20,
}),
control: () => ({
// none of react-select's styles are passed to <Control />
width: 200,
}),
singleValue: (provided, state) => {
const opacity = state.isDisabled ? 0.5 : 1;
const transition = 'opacity 300ms';
return { ...provided, opacity, transition };
}
}
const App = () => (
<Select
styles={customStyles}
options={...}
/>
);
What is the best way to style multiple react-select components? Will be possible to set style globally and every new react-select component use that style automatically?
One way to do it is to create your own select component like CustomSelect that you import instead of react-select where you set for one the custom style or theme like:
import React, { Component } from 'react'
import Select from 'react-select'
class CustomSelect extends Component {
render() {
const styles = {
...
// what ever you need
}
return <Select styles={styles} {...this.props} />
}
}
export default CustomSelect
I can't really tell if it's the best way or not but I've tried both of it and in a big project with many select it's the easiest way to maintain / modify it. Plus it's really convenient if at some point you need to have custom components.
I'm working on a large React project where each member of the team has been making components and stylesheets separately. I'm trying to find the common elements and re-write the code, creating re-usable components. At the moment each of these components has a stylesheet -- SCSS -- already written.
What I'd like to do is be able to pass styles to the component so that it can be customised (somewhat) in different locations. I know how to do this for the top-level HTML element in the component
export default class BoxWithSliderAndChevron extends Component {
render() {
const {
props: {
styles
},
} = this;
return (
<div className="BoxWithSliderAndChevron-main" style={styles}>
but as I understand it, these styles will only apply to this outer div? How can I pass styles such that I can re-style elements further down in the component's structure, using their classNames? As if I were passing a new stylesheet that would override the default stylesheet?
I suppose I could pass a number of style objects, but that seems cumbersome -- I'm wondering if there is a simpler way?
What you are trying to achieve kinda goes against the whole idea of inline styles (non-global, non-separated from implementation, etc), however you are right, passing a style prop and trying to apply it to a div will inmediatly result to only the parent having the styles applied.
One suggestion would be to merge the component styles with the props, ex:
import { StyleSheet } from 'react-native';
class Foo extends React.PureComponent {
render() {
return (
<div style={StyleSheet.merge([styles.parentStyle, styles.parentStyle])}>
<div style={StyleSheet.merge([styles.childStyle, styles.childStyle])}>
</div>
)
}
}
const styles = StyleSheet.create({
parentStyle: {
backgroundColor: 'red'
},
childStyle: {
backgroundColor: 'blue'
}
});
It is tedious work, but it is basically what you are trying to achieve, another approach is having theming globally applied:
import { StyleSheet } from 'react-native';
import { t } from '../theming'; // <- You switch themes on runtime
class Foo extends React.PureComponent {
render() {
return (
<div style={StyleSheet.merge([styles.parentStyle, t().parentStyle])}>
<div style={StyleSheet.merge([styles.childStyle, t().childStyle])}/>
</div>
)
}
}
const styles = StyleSheet.create({
parentStyle: {
backgroundColor: 'red'
},
childStyle: {
backgroundColor: 'blue'
}
});
/// Theming file would be something like:
// PSEUDO IMPLEMENTATION
import theme1 from 'theme1.json';
import theme2 from 'theme2.json';
availableThemes = {
theme1,
theme2
}
currentTheme = availableThemes.theme1
function setTheme(theme) {
currentTheme = availableThemes[theme]
}
export function t() {
return current theme
}
I am using the awesome "Styled-Components"
but I am now using another package that wraps an element inside it so I can't push my StyledComponents there as I don't want to change his package.
I saw glamor has a nice trick.
Is that supported with StyledComponents?
import { css } from 'glamor';
let rule = css({
color: 'red',
})
<div {...rule}>
zomg
</div>
If you think about why I need it, here is an example:
this is an external package I'm using:
External = props => (
<div>
<input style={props.inputStyle} className={props.inputClass} />
</div>
);
so you can see I need to pass in a json style or className
so Glamor will work here, but I dont want to use it just for this scenario.
I'm already enjoying StyledComponent
Thanks
If I understood your query, you can define css rules to a component, like this
import styled from 'styled-components'
const Wrapper = styled.div`
color: 'red';
font-weight: bold;
background-color: ${ props => props.color === 'primary' ? 'green' : 'red' }
`
export const Component = () => {
<Wrapper color='primary'>
I have a red text, and bold font-weight.
</Wrapper>
}
I am using reactjs and trying to get me css inside javascript and finally read the css from an external js file.
Here is the code:
import React from 'react';
import ReactDOM from 'react-dom';
var styles = {
container: {
padding: 20,
border: '5px solid green',
borderRadius: 2
}
};
var myComponent = React.createClass({
render: function() {
return (
<div style={styles.container}>
{this.props.name}
</div>
);
}
});
This works fine but what I need to do is to put the css in an external file.
So I've created a file called general.css.js
And I tried to import it:
import styles from './components/general.css';
I add this import to the top of the page with the other imports.
The problem is that it's not reading the styles.
What I'm I doing wrong here?
Make a new file and put this code in it.
export const style = { container : {
padding: 20,
border: '5px solid green',
borderRadius: 2 }
};
Now in your component file.
import * as styles from './style/location/filename'
Now you can use styles in your render function.
return (
<div style={styles.style.main}>
<h3 style={styles.style.header}>Vote for your favorite hack day idea</h3>
</div>
);
You can directly import your css file in js.
import './style/app.css';
app.css
.page {
background-color:#fafafa;
}
and you can use this class in React component like below.
<div className="page">
Hope it works!!!!
There is a little tool that automates translation from CSS to JSON representation.
Worth checking that out.
Note how the translation adds _ underscores:
div.redcolor { color:red; }
div:hover { color:blue; }
Into:
{"div_redcolor":{"color":"red"},"div_hover":{"color":"blue"}}
Note how the Vishwas Chauhan used starred method of ES6 import export:
In case you use this tool you get one big object, and you can use any method.