Adding controls to html classes in storybook - javascript

I am working on a tailwind + storybook component library where the theme colors change based on the class that is given to the html element.
Since components will have different colors in different themes, it would be great to have a theme toggle control in each story.
To achieve that, I was wondering if there is a way to add and remove a class to the html of each story preview with a control?

In order to get conditional classes on React you can use build the string for the className prop of your component like this:
render() {
let className = 'menu';
if (this.props.isActive) {
className += ' menu-active';
}
return <span className={className}>Menu</span>
}
Although it is recommended using the classNames utility in order to simplify this process like this:
render () {
var btnClass = classNames({
btn: true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
return <button className={btnClass}>{this.props.label}</button>;
}
You can read more about this in the React docs or in the classNames docs.

Related

How do you pass dynamic css classes in react?

I have an image where the CSS class on the image needs to be change dynamically. It is passed in dynamically from this object from the key "size":
export const decals = [
{ label: 'Nikola Tesla', img: `/images/decals/tesla.svg`, size: `decalMed` },
{ label: 'Tattoo Mom Heart', img: `/images/decals/ARF149.svg`, size: `decalSm`}
Into another component here:
import styles from ./Shirt.module.css';
<img key={decals[decal].label} src={decals[decal].img} alt={decals[decal].label} className={`${styles}.${decals[decal].size}`}/>
The className= is the issue. I've tried so many different ways to pass this class.
I've captured this (decals[decal].size) into a variable before passing to the image tag.
I've tried to use the style tag instead of className and created a variable to hold the class.
I've changed around the brackets. I've tried passing it into an outside div.
Nothing seems to work.
I'm wondering if anyone can clue a react newbie in. Thank you!
if I am not wrong, you trying to dynamically manage classes that are passing through to the image element.To do that, I recommend you to use "classnames"
https://www.npmjs.com/package/classnames
With this package, you can control classNames with variables in your component.
I will try explain usage with a little example.
Your style file like
.yourParentClass {
&.decalMedClass {
// your styles for this class
}
&.decalSmClass {
// your styles for this class
}
}
your component file like
import Style from '../style.scss'; // Your classes
var classNames = require('classnames/bind'); // classname package
const cx = classNames.bind(Style);
// your code
render() {
return (
<img className={
cx({
yourParentClass: true,
decalMedClass: this.state.sizeMed,
decalSmClass: !this.state.sizeMed,
})
}
/>
);
}
Basically, you telling that which class gonna be active.
Please do not stick with my example, there are good examples on the npm page.

Styling(tailwind/SCSS stylesheet) not getting applied to dynamically inserted HTML in React

I have a React App which uses typescript, scss & tailwind. Tailwind works fine and so does Sass.
The problem comes when I try to insert HTML from the useEffect hook into a div.
HTML:
<main className='mx-20 mt-12 text-gray-600'>
<div ref={mdContainerRef}></div>
</main>
useEffect & other related code:
const mdContainerRef = useRef<null | HTMLDivElement>(null);
useEffect(() => {
if (mdContainerRef.current) {
mdContainerRef.current.innerHTML = '<p className="text-8xl bg-green-600">Test</p>';
}
setArticle(data);
})();
}, [slug, mdContainerRef]);
The tailwind classes work on the other content like the render HTML(returned from function, eg: main element).
I've checked the devtools on chrome, there's no sign of the tailwind styles being applied(inline styling works though.)
Image of the devtools:
Let me know if you need any other details, thanks in advance!!!
You inserting html element outside of react ecosystem, so you need to use class instead of className
mdContainerRef.current.innerHTML = '<p class="text-8xl bg-green-600">Test</p>';

react.component equivalent for styled components return

I'm making a simple portfolio page and for the same, I have a few icons I want to render for which I have used Material UI icons
Now I added the same custom styling to them and since I'm new to styled-components I did it as follows
const iconsArray = [GitHubIcon, LinkedInIcon, CallIcon];
const styledIcons = iconsArray.map(
(item) => styled(item)`
//other styles
:hover {
cursor: pointer;
}
`
);
the iconsArray above is made from direct imports from Material UI icons
Now I want to render the icons as
{styledIcons.map(styledIcon=>(
<styledIcon>
<a href={correspondingLink}>
</a>
</styledIcon>
)}
This won't work for obvious reasons but I can't access the component even using styledIcon.component like we could for normal react components. Any suggestions on how to achieve this?

How to define css styles for a vue.js component when registering that component?

I am able to register a custom vue.js component with
// register
Vue.component('my-component', {
template: '<div class="my-class">A custom component!</div>'
})
Also see https://v2.vuejs.org/v2/guide/components.html
How can I include css classes for my component?
I would expect something like
Vue.component('my-component', {
template: '<div class="my-class">A custom component!</div>',
css: '#... my css stylesheet...'
})
but there does not seem to be a css option.
I know that I could
a) define all css classes in a global css stylesheet or
b) use singe-file-vue-components (would require build tool supporing *.vue files, see https://v2.vuejs.org/v2/guide/single-file-components.html)
but I would prefer to
c) specify a css stylesheet for the component when registering the component.
=> How to do so?
there does not seem to be a css option.
That is correct. You cannot do what you describe. The documentation on single file components is pretty clear that one of the advantages is that you can do this with them and cannot do it without them.
In many Vue projects, global components will be defined using
Vue.component, followed by new Vue({ el: '#container' }) to target a
container element in the body of every page.
This can work very well for small to medium-sized projects, where
JavaScript is only used to enhance certain views. In more complex
projects however, or when your frontend is entirely driven by
JavaScript, these disadvantages become apparent:
[...]
No CSS support means that while HTML and JavaScript are
modularized into components, CSS is conspicuously left out
Here is a way to achieve what you're looking for:
export const ContactUs = Vue.component(
'mycomponent-contact-us'
,{
props: {
backgroundColor: {
type: String
,required: false
,default: "red"
}
}
,data: function(){
return {
}
}
,template: `
<div>
<span class='contact_us_text' >Contact Us Component and its bg color will be {{backgroundColor}}</span>
</div>
`
,mounted: function(){
var css_text = `
.contact_us_text{
color: `+this.backgroundColor+`;
}
`;
var css = document.createElement('style');
css.type='text/css';
css.setAttributeNode( document.createAttribute('scopped') );
css.appendChild( document.createTextNode( css_text ) );
this.$el.appendChild( css );
}
}
);
Its true that you cannot add <style> inside a Vue template or add CSS within
component directly, unless you bind it or define your css globally. But you can create a custom component that will dynamically do it for you. sample
Keep in mind that Vue components are effectively macros.
Where render is the substitution function, and the vueDefinition (defn3 below) is effectively a class for the given tagName.
A template is just a convenient syntactic-sugar shorthand that will be compiled (with some vue-usage pattern restrictions) into a render function if you don't provide your own render function.
const defn3 = {
tagName: 'ae-css',
mounted() {
const vueDefinition = this.$options;
this.$el.appendChild(document.createTextNode(vueDefinition.css));
},
css: `
* {
color: blue;
}
`,
render(h) {
return h('style');
}
}
Vue.component(defn3.tagName, defn3);
With that solution in hand, there are a number of good reasons why you probably don't want something as simplistic as what I just provided.
Namely, you want to have your css modularized such that it does not affect any aspects of your page you did not intend it to. For that, you either need carefully designed css rules with your intended inheritance and scope; probably using a class=... But a better approach would be to just use Vue's facilities that offer similar capabilities automatically.
If you want to use modern browser architecture capabilities for this, then you might want your components to be real browser DOM WebComponents that make use of the shadowDOM and keep your internal elements and styles encapsulated within a shadowRoot. See this library, for doing that in Vue.
You can embed a style tag within your template root element:
Vue.component('my-component', {
template: `
<div class="my-class" my-component>
A custom component!
<style>
.my-class[my-component] {
// ... my-component styles
}
</style>
</div>
`
})
Try this:
this.$el.style.cssText = "border: 5px solid blue;"

Modify or override material-ui button css

I have a material UI RaisedButton and I want to change the background color.
I have this:
const style = {
backgroundColor: 'green'
};
export default class CreateLinksave extends React.Component {
<RaisedButton
label="Continue"
style={style}/>
}
but when I refresh the page the material-ui style remains, so how can I override the style?
A second question is, how to avoid doing inline styling? I was thinking on create a js file with constants with the styles I need for my components, import it and access to my styles that way, is that a good approach?
I'm new to React so some help would be nice...
Regards.
You can override the style by passing in the attribute. See the docs for which attributes are supported.
creating a JS file (or multiple files) with your styling sound like a good idea, as long as the rules are simple. if you find yourself merging & overriding styles it would be easier just keeping the style in the component file.
You'll end up with something like
import {green} from './my-style/colors';
...
<RaisedButton label="change min" backgroundColor={green} />
If you are using Material UI you should use jss as seen in their documentation. And use the withStyles HOC. Actual link https://material-ui.com/customization/css-in-js/
Here is an example:
import { withStyles } from '#material-ui/core/styles';
const style = {
back: {
background: green,
},
};
class CreateLinksave extends React.Component {
{classes} = this.props;
<RaisedButton
label="Continue"
style={classes.back}/>
}
export default withStyles(styles)(CreateLinksave );
I think you should check the documentation to have better and reusable components.

Categories

Resources