Switch storybook background through global parameter - reactjs

I have the following globalTypes to enable a toolbar in storybook that lets me select the theme:
export const globalTypes = {
theme: {
name: 'Theme',
description: 'Global theme',
defaultValue: MyTheme.Light,
toolbar: {
icon: 'mirror',
items: [MyTheme.Light, MyTheme.Dark],
showName: true,
dynamicTitle: true,
},
},
};
This works fine and I can switch the theme through the toolbar:
Now I want to set the background color of the story (background-color of the body) according to the theme, but I cannot figure out how to do that for all stories globally.
I know how to configure different background colors, but I have no idea how to switch them based on the theme set in context.globals. How does this work?

You can use decorators to set global view and se
Like here
import { useEffect } from "react";
import "./preview.css";
enum MyTheme {
Light = "light",
Dark = "dark",
Tomato = "tomato"
}
export const globalTypes = {
theme: {
name: "Theme",
description: "Global theme",
defaultValue: MyTheme.Light,
toolbar: {
icon: "mirror",
items: [
{
title: "light",
value: MyTheme.Light
},
{ title: "dark", value: MyTheme.Dark },
{ title: "tomato", value: MyTheme.Tomato }
],
showName: true,
dynamicTitle: true
}
}
};
const clearStyles = (element: HTMLElement) => {
for (const className of Object.values(MyTheme)) {
element.classList.remove(className);
}
};
const applyStyle = (element: HTMLElement, className: string) => {
element.classList.add(className);
};
const WithThemeProvider = (Story, context) => {
useEffect(() => {
const body = window.document.body;
clearStyles(body);
applyStyle(body, context.globals.theme);
return () => {
clearStyles(body);
};
}, [context.globals.theme]);
return <Story />;
};
export const decorators = [WithThemeProvider];
I know it might feel "dirty" to work directly with body. But it is suggested way for instance addons decorator.

Related

Is there a way to specify defaultProps for a variant?

I created variant for MuiButton like so...
const theme = createTheme({
components: {
MuiButton: {
variants: [{
props: {
variant: 'myVariantX'
},
style: {
backgroundColor: 'blue'
}
}]
}
},
});
...I know I can do this...
const theme = createTheme({
components: {
// Name of the component
MuiButton: {
defaultProps: {
// The props to change the default for.
disableRipple: true, // No more ripple, on the whole application 💣!
},
},
},
});
... but is there a way I could specify defaultProps for my 'myVariantX' variant? Dont want to target all MuiButtons. Something like...
const theme = createTheme({
components: {
MuiButton: {
variants: [{
props: {
variant: 'myVariantX',
defaultProps: {
disableRipple: true
}
},
style: {
backgroundColor: 'blue'
}
}]
}
},
});

react-tsparticles change color on click of component i made for dark mode

i Want to change theme of the react-tsparticle
function Particle() {
const particlesInit = (main) => {};
const particlesLoaded = (container) => {
<DarkMode />;
container.loadTheme("dark"); //dark mode
};
////////////////////////
themes: [
{
name: "light",
default: {
value: true,
mode: "light",
},
options: {
background: {
color: "transparent",
},
particles: {
color: {
value: "#20f0",
},
},
},
},
{
name: "dark",
default: {
value: true,
mode: "dark",
},
options: {
background: {
color: "transparent",
},
particles: {
color: {
value: "#2fff",
},
},
},
},
in container.loadtheme("dark/light)"
can be set so i want to set a onclick on the dark mode button so that dark and light can be set by on click on this container
<DarkMode />; //want onclick on this This is the button which i imported and i want this button to change the particle theme
const DarkMode = () => {
return (
<div className="toggle-theme-wrapper">
<span>☀️</span>
<label className="toggle-theme" htmlFor="checkbox">
<input
type="checkbox"
id="checkbox"
onChange={toggleTheme}
const toggleTheme: ChangeEventHandler<HTMLInputElement> = (e) => {
if (e.target.checked) {
setDark();
} else {
setLight();
}
};
You can find how to get the container on GitHub here
import Particles from "react-tsparticles";
const App = () => {
const particlesInit = (main) => {
console.log(main);
// you can initialize the tsParticles instance (main) here, adding custom shapes or presets
};
const particlesLoaded = (container) => {
console.log(container);
};
return (
<Particles id="tsparticles" url="http://foo.bar/particles.json" init={particlesInit} loaded={particlesLoaded} />
);
};
In the particlesLoaded function you can store the container in a local variable (or state) and use that to call the loadTheme function

Theme override support for custom components

After the migration to mui v5 for react-admin, we realized that supporting theme overrides for our custom components seems to require more code than we expected. As it looks that this could be handled by the styled API, I would like to know if this is really required.
Here's an example of our Navigation link:
const PREFIX = 'RaMenuItemLink';
export const MenuItemLinkClasses = {
root: `${PREFIX}-root`,
active: `${PREFIX}-active`,
icon: `${PREFIX}-icon`,
};
const StyledMenuItem = styled(MenuItem, {
name: PREFIX,
// Why do I have to do this?
overridesResolver: (props, styles) => [
{ [`&.${MenuItemLinkClasses.active}`]: styles.active },
{ [`& .${MenuItemLinkClasses.icon}`]: styles.icon },
styles.root,
],
})(({ theme }) => ({
[`&.${MenuItemLinkClasses.root}`]: {
color: theme.palette.text.secondary,
},
[`&.${MenuItemLinkClasses.active}`]: {
color: theme.palette.text.primary,
},
[`& .${MenuItemLinkClasses.icon}`]: { minWidth: theme.spacing(5) },
}));
In your case, I think that I would start to simplify the code to:
const PREFIX = 'RaMenuItemLink';
export const MenuItemLinkClasses = {
root: `${PREFIX}-root`,
active: `Mui-active`,
icon: `${PREFIX}-icon`,
};
const StyledMenuItem = styled(MenuItem, {
name: PREFIX,
overridesResolver: (props, styles) => [
styles.root,
{ [`&.${MenuItemLinkClasses.active}`]: styles.active },
{ [`& .${MenuItemLinkClasses.icon}`]: styles.icon },
],
})(({ theme }) => ({
color: theme.palette.text.secondary,
[`&.${MenuItemLinkClasses.active}`]: {
color: theme.palette.text.primary,
},
[`& .${MenuItemLinkClasses.icon}`]: { minWidth: theme.spacing(5) },
}));
The overridesResolver property is meant to resolve this object:
const theme = {
components: {
[PREFIX]: {
styleOverrides: /* this object, it's the 'styles' arg of overridesResolver */,
},
},
};

Storybook hide or show args specific to a story

I have a Storybook project and a component that looks like this:
export default {
title: 'MDButton',
argTypes: {
label: {
name: "Label",
defaultValue: "Button",
control: {
type: "text"
}
},
disabled: {
name: "Disabled",
defaultValue: false,
control: {
type: "boolean"
}
}
}
};
These are the stories:
export const Default = Template.bind({});
Default.args = {};
export const WithDisabled = Template.bind({});
WithDisabled.args = {};
I want the first story to not have the disabled arg.
Is that possible?
I know I can go over args and filter out the things I don't want, but what if I have tons of args?
You can disable specific arg prop with a next code. Example in MDX-format.
<Meta
title="Title"
component={YourComponent}
argTypes={{
icon: { table: { disable: true } },
label: { table: { disable: true } },
onClick: { table: { disable: true } },
}}
/>
Good luck!

react-select change singleValue color based on options

I would like to modify the 'selected' singleValue color in my styles object based on the options that are provided.
const statusOptions = [
{ value: "NEW", label: i18n._(t`NEW`) },
{ value: "DNC", label: i18n._(t`DNC`) },
{ value: "WON", label: i18n._(t`WON`) },
{ value: "LOST", label: i18n._(t`LOST`) },
];
For example, if the option selected in "NEW", I want the font color to be red, if it's "WON", then green, and so on. I am having trouble putting an if statement into the styles object. I see that its simple to put a ternary statement in, but how to you add more "complex" logic?
const customStyles = {
...
singleValue: (provided) => ({
...provided,
color: 'red' <----- something like if('NEW') { color: 'green' } etc..
})
};
Use an style map object:
import React from 'react';
import Select from 'react-select';
const statusOptions = [
{ value: 'NEW', label: 'NEW' },
{ value: 'DNC', label: 'DNC' },
{ value: 'WON', label: 'WON' },
{ value: 'LOST', label: 'LOST' },
];
const styleMap = {
NEW: 'red',
DNC: 'blue',
};
const colourStyles = {
singleValue: (provided, { data }) => ({
...provided,
color: styleMap[data.value] ? styleMap[data.value] : 'defaultColor',
// specify a fallback color here for those values not accounted for in the styleMap
}),
};
export default function SelectColorThing() {
return (
<Select
options={statusOptions}
styles={colourStyles}
/>
);
}

Resources