Can't style slider (or maybe anything) in Material UI - material-ui

There was an issue requesting documentation for theming which the author subsequently closed. The author found their answer. A non-programmer will probably not. At least, the non-programmer designer I'm helping doesn't even know where to start (and I still don't have a working different colored slider). This kind of documentation would be great. Even if it's just a link to the code #jdelafon found with some explanation that would suffice to answer the following specific example.
Ultimately, we want a set of sliders with each one a different color. It seems like the appropriate way to do this is with per-element inline styles.
I made a simple example here. Can you change the color of the slider? (We started down the path of breaking out to CSS, but the widget is so dynamic that this approach ends up being quite ugly.)
Slider has two different slots for theming, neither of which seems to respond to an embedded object with a selectionColor key.
Should be simple. Probably it is, but it appears to be undocumented. Otherwise it's a rad UI toolkit, thanks devs!

Take a look at this line of getMuiTheme.js. You can find there that slider can have those styles overridden:
{
trackSize: 2,
trackColor: palette.primary3Color,
trackColorSelected: palette.accent3Color,
handleSize: 12,
handleSizeDisabled: 8,
handleSizeActive: 18,
handleColorZero: palette.primary3Color,
handleFillColor: palette.alternateTextColor,
selectionColor: palette.primary1Color,
rippleColor: palette.primary1Color,
}
In material-ui you need to use MuiThemeProvider in order to use your custom theme. Taking your example:
...
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import { Slider } from 'material-ui';
const theme1 = getMuiTheme({
slider: {
selectionColor: "red",
trackSize: 20
}
})
const theme2 = getMuiTheme({
slider: {
selectionColor: "green",
trackSize: 30
}
})
const HelloWorld = () => (
<div>
...
<MuiThemeProvider muiTheme={theme1}>
<Slider defaultValue={0.5}/>
</MuiThemeProvider>
<MuiThemeProvider muiTheme={theme2}>
<Slider defaultValue={0.5}/>
</MuiThemeProvider>
</div>
);
export default HelloWorld;
Your modified webpackbin: http://www.webpackbin.com/EyEPnZ_8M
The sliderStyle you tried to use is for different styles :-) Like marginTop / marginBottom, a full list can be found here.

Related

How to change MUI Chip's background color when filled?

I want to change Chip's background color when it's variants value is 'filled' because the default light gray doesn't feel satisfactory.
I read MUI docs and Chip API but it's too complicated for me..
You could make use of Chip's exported CSS classes
import Chip, { chipClasses } from "#mui/material/Chip";
import { styled } from "#mui/material/styles";
// ..
const CustomChip = styled(Chip)({
[`&.${chipClasses.filled}`]: {
backgroundColor: "red"
}
});
Codesandbox demo

Can I use an `sx` prop in a `styled` component

So my question really isn't should I, but rather can I.
If I opt to use styled components for my more common components then I style them once and export.
const MyBlueButton = styled('button')({
backgroundColor: 'blue'
})
Great export that and I have a blue button.
I can also use sx
const MyBlueButton = (props) => {
return <button sx={{backgroundColor: 'blue'}}>{props.children}</button>
}
My question is can I have both, one where I've already made my common component but then want to customize it just a bit unique for one use.
'components/buttons.jsx':
export const MyBlueButton = styled('button')({
backgroundColor: 'blue'
})
--------
'FooBar.jsx':
import {MyBlueButton} from 'components/buttons'
const FooBar = (props) => {
return (
<div>
<p>Some text</p>
<MyBlueButton sx={{fontSize: '20px'}}>Large Blue Button</MyBlueButton>
</div>
)
}
I didn't find anything stating that you couldn't do it. I'm sure you quite possibly can, but can you, and what would be the expected order of css properties?
If I have a styled component with a matching css property in the sx prop would sx win since it's closer to the render? Should I have to worry about injection order with the StyledEngineProvider?
I'm really just hoping I can use a healthy mix of both styled components and one off sx modifications.
I went ahead and made a codesand box to test my idea and it does work to combine both styled wrappers and sx props.
Again probably not for everyday use, but it's nice to know it is possible.
CodeSandbox: https://codesandbox.io/s/keen-roman-s6i7l?file=/src/App.tsx
I have been into such issue;
the way I had to implement the sx props to be passed before passing the component to styled engine was neglecting the props:
const AutoComplete = withThemeProvider(styled(Autocomplete)(autoCompleteStyles));
and when to use it, it gets neglected
<Autocomplete sx={neglectedProps}>

Using ClojureScript, how to customize the ValueLabel in slider component of material-ui?

In here, there is an example showing how to do the customization of ValueLabel by using javascript.
import React from "react";
import { withStyles, makeStyles } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
import Slider from "#material-ui/core/Slider";
import ValueLabel from "#material-ui/core/Slider/ValueLabel";
const StyledValueLabel = withStyles({
offset: {
top: -28,
left: props => props.index === 0 ? "calc(-50% + -20px)" : "calc(-50% + 12px)"
},
circle: {
transform: props => props.index === 0 ? "rotate(-90deg)" : "rotate(0deg)"
},
label: {
transform: props => props.index === 0 ? "rotate(90deg)" : "rotate(0deg)"
}
})(ValueLabel);
const useStyles = makeStyles({
root: {
width: 300
}
});
const MySlider = withStyles({
root: {
color: "#3880ff",
height: 2,
padding: "15px 0"
},
track: {
height: 4
},
thumb: {
background: "transparent",
"&:focus,&:hover,&$active": {
boxShadow: "inherit"
}
},
rail: {
height: 4,
opacity: 0.5,
backgroundColor: "#bfbfbf"
},
mark: {
backgroundColor: "#bfbfbf",
height: 8,
width: 1,
marginTop: -2
}
})(Slider);
function valuetext(value) {
return `${value}°C`;
}
export default function RangeSlider() {
const classes = useStyles();
const [value] = React.useState([31, 37]);
return (
<div className={classes.root}>
<Typography id="range-slider" gutterBottom>
Temperature range
</Typography>
<MySlider
defaultValue={value}
valueLabelDisplay="on"
ValueLabelComponent={StyledValueLabel}
aria-labelledby="range-slider"
getAriaValueText={valuetext}
/>
</div>
);
}
I tried to changed it to the ClojureScript version, but it did not work.
(ns XXXX
(:require [reagent-material-ui.components :as mui]
[reagent.core :as reagent]
[reagent-material-ui.styles :as styles]
["#material-ui/core/Slider/ValueLabel" :as js-vl]))
...
(let [vlb (styles/with-styles {:circle {:width 40 :height 40}}
(reagent/adapt-react-class (.-default js-vl)))]
[mui/slider
{:valuelabelcomponent vlb}])
I got console error like:
Warning: Invalid value for prop `valuelabelcomponent` on <span> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM. For details, see https://reactjs.org/link/attribute-behavior
at span
at eval (http://localhost:5555/ui/cljs-runtime/module$node_modules$$material_ui$core$esm$Slider$Slider.js:16:209)
at WithStyles(ForwardRef) (http://localhost:5555/ui/cljs-runtime/module$node_modules$$material_ui$styles$withStyles$withStyles.js:4:435)
at div
First of all, I think this type of question is better suited for the Clojureverse forum because you have a better chance of reaching the Clojure community there. Also, I think there are ways to improve your original question. For example: explain what exactly you were trying to do in your example but didn't work? (Sorry for picking on this but it really doesn't make sense to me to expect 30 lines of JSX and 4 lines of Clojure to work the same way. They must be different.)
Issues
To have a complete answer, let's start with the issues I noticed in your Clojure snippet:
(The warnings aren't errors. However they might be closely related to errors. 😉)
The capitalization of the props. The correct keyword for ValueLabelComponent props is :ValueLabelComponet. Reagent is a thin wrapper around React and it converts react names into Clojure keywords directly without munging the names.
The usage of reagent-material-ui.styles/with-styles. From its doc-string:
Takes a styles-generating function or a styles object.
Returns a higher-order component that wraps another component and adds a :classes prop to it.
Note: input component has to take all its props (including children) in a single map.
The difference between React component and Reagent component. Here's a great read from the reagent documentation. Although it's kind-of deceivable how similar they are, they aren't. Especially when you are doing a lot of interop with an externed React library.
Example to customize ValueLabel for MaterialUI Slider in ClojureScript
I put together this example illustrating how to put the pieces together without solving everything for you, assuming your goal is to translate every bit of the JSX snippet above. I hope this is good enough for you to work out the rest.
Pay extra attention to the distinction between React component and Reagent component.
(ns example.core
(:require
[reagent-material-ui.core.slider :refer [slider]]
[reagent-material-ui.styles :as styles]
[reagent.core :as r]
[reagent.dom :as rdom]
["#material-ui/core/Slider/ValueLabel" :as MuiValueLabel]))
(def mui-value-label
(r/adapt-react-class (or (.-default MuiValueLabel)
(.-ValueLabel MuiValueLabel))))
(def with-my-styles
(styles/with-styles {:offset {:top 50 :left 50}}))
(defn styled-value-label
[props]
[(with-my-styles mui-value-label) props])
(defn main []
[slider
{:defaultValue [31 37]
:valueLabelDisplay "on"
:ValueLabelComponent (r/reactify-component styled-value-label)}])
;; Something that renders the component like:
;; (rdom/render [main] (js/document.getElementById "app"))
Result
The value labels are offset by 50px down and 50px right:
Feel free to comment on my answer so I can make edits to it.
Cheers!

Add "focusVisibleClassName" globally in Material UI

I want to disable the ripple effect since I don't want the effect when clicking on elements. Now this works but when doing this the :focus-visible state will also be disabled which is a bummer. Would be really nice to split this prop up into something like disableClickRipple, disableFocusRipple and so on...
Anyway, according to the docs I have to add focusVisibleClassName in order to style my own focus state but how would I do this to all elements that is affected by the disabled ripple effect? As I understand it I have to do this manually on each and every component? Can this be done globally? To me this would need to be a global setting?
I don't know if this is how MUI intended it to be, but this works:
import { createMuiTheme } from '#material-ui/core/styles';
const theme = createMuiTheme({
props: {
MuiButtonBase: {
// Disable ripple globally.
disableRipple: true,
// The class will be added (as is, ie `focus-visible`)
// To the ButtonBase root whenever the button gets focus via keyboard.
focusVisibleClassName: 'focus-visible',
},
},
overrides: {
MuiButtonBase: {
// And this is how we select it.
root: {
'&.focus-visible': {
backgroundColor: 'rgba(0, 0, 0, 0.12)', // theme.pallate.action.focus
},
},
},
},
});
export default theme;
PS. Spent an hour trying to solve this to no avail. Then I landed your question and "in order to style my own focus state" gave me the idea above.

Cytoscape.js changing style of node on click

I cannot seem to be able to change the style of a node on click. I need to do this programatically to keep track of two nodes in the graph, basically to have two nodes 'selected' at same time, with each being a different type I define. There are examples such at the one here (http://js.cytoscape.org/#eles.addClass) that 'drops' a new style in the sheet for certain nodes. I don't understand how these classes work, where they are defined in the stylesheet and on what event they can be used.
The docs for the library does not provide an actual explanation of classes, where to define them and what they can be used for. Any help is much appreciated.
I think of the classes as like css classes. When you first initialised cytoscape you can have an optional style parameter like ...
var cy = cytoscape({
style: [
{
selector: '.myFirstClass',
style: {
'background-color': 'red',
'shape': 'rectangle'
...
},
{
selector: '.mySecondClass',
style: {
'background-color': 'blue',
'shape': 'triangle'
...
}
});
Now when you change the style of a node it will reflect what you set in the stylesheet. So...
cy.$('#nodeA').classes('mySecondClass');, where #nodeA is the id of your node. This will turn your first node into a blue triangle.
Hope that helped.