Using variable in object method results in "Unknown Format" - javascript

When I'm trying to use the provided example at this pageenter link description here, react simply returns with "Unknown Format" at the first line using const color = chroma(data.color);
import chroma from "chroma-js";
const runeColorStyles = {
control: styles => ({ ...styles, backgroundColor: 'white' }),
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
const color = chroma(data.color); // First error is here
return {
...styles,
backgroundColor: isDisabled
? null
: isSelected
? data.color
: isFocused
? color.alpha(0.1).css()
: null,
color: isDisabled
? '#ccc'
: isSelected
? chroma.contrast(color, 'white') > 2
? 'white'
: 'black'
: data.color,
cursor: isDisabled ? 'not-allowed' : 'default',
':active': {
...styles[':active'],
backgroundColor: !isDisabled && (isSelected ? data.color : color.alpha(0.3).css()),
},
};
},
multiValue: (styles, { data }) => {
const color = chroma(data.color);
return {
...styles,
backgroundColor: color.alpha(0.1).css(),
};
},
multiValueLabel: (styles, { data }) => ({
...styles,
color: data.color,
}),
multiValueRemove: (styles, { data }) => ({
...styles,
color: data.color,
':hover': {
backgroundColor: data.color,
color: 'white',
},
}),
};
I've got no clue why this is happening on my side. It's very weird because it works perfectly fine in their example page.

This one occurred to me when using CreatableSelect and was trying to type a new option. I used const color = chroma(data.color ?? 'black'); to fix it.

const color = chroma(data.color);
The first step is to get your color into chroma.js. That's what the generic constructor chroma() does. This function attempts to guess the format of the input color for you. so the data.color requires a valid color.
colourStyles = {
control: styles => ({ ...styles, backgroundColor: 'white' }),
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
const color = chroma(data.color);
return {
......
};
}
colourOption object which you pass to the options will be available as the data - option: (styles, { data, isDisabled, isFocused, isSelected }). if the color is not present in the colourOption object it will through an error “Unknown Format”.
<Select className="basic-single" classNamePrefix="select" defaultValue={colourOptions[0]}
isDisabled={isDisabled} isLoading={isLoading} isClearable={isClearable}
isRtl={isRtl} isSearchable={isSearchable} name="color"
options={colourOptions} <!-- colourOptions object -->
styles={colourStyles} />
colourOptions object :
colourOptions:[
{ value: 'ocean', label: 'Ocean', color: '#00B8D9', isFixed: true },
{ value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true },
{ value: 'purple', label: 'Purple', color: '#5243AA' },
{ value: 'red', label: 'Red', color: '#FF5630', isFixed: true },
{ value: 'orange', label: 'Orange', color: '#FF8B00' },
{ value: 'yellow', label: 'Yellow', color: '#FFC400' },
{ value: 'green', label: 'Green', color: '#36B37E' },
{ value: 'forest', label: 'Forest', color: '#00875A' },
{ value: 'slate', label: 'Slate', color: '#253858' },
{ value: 'silver', label: 'Silver', color: '#666666' },
]
Note: Make sure that the color property exists in colourOptions.
Working Demo: https://codesandbox.io/s/react-codesandboxer-example-zxqg0

Related

React VictoryPie - How to scale slice on mouse hover

I'm trying to scale a slice of this Victory Pie chart on mouse hover but I'm having a difficult time getting it to render correctly. Has anyone had any luck with this? I've tried adding things like transform: scale(1.2) to the mutation style but it moves the slice rather than scales (I believe this is because scale scales based on the point of (0,0)). I've also tried playing around with translate or matrix but I can't get it to work correctly. Here's my code:
<div style={{ width: '150px' }}>
<VictoryPie
data={[
{ x: 'Cats', y: 35, label: 'Cats \n 35%' },
{ x: 'Dogs', y: 40, label: 'Dogs \n 40%' },
{ x: 'Birds', y: 55, label: 'Birds \n 55%' }
]}
labelComponent={
<VictoryTooltip
cornerRadius={10}
pointerWidth={30}
pointerLength={20}
flyoutPadding={{ top: 10, bottom: 10, left: 25, right: 25 }}
style={{ fontSize: '36px', fill: '#FFF' }}
flyoutStyle={{ fill: '#414B5F' }}
orientation="right"
/>
}
colorScale={['tomato', 'orange', 'gold', 'cyan', 'navy']}
innerRadius={100}
events={[
{
target: 'data',
eventHandlers: {
onMouseOver: () => {
return [
{
target: 'data',
mutation: () => ({ style: { fill: 'red', width: 30 } })
},
{
target: 'labels',
mutation: () => ({ active: true })
}
]
},
onMouseOut: () => {
return [
{
target: 'data',
mutation: () => {}
},
{
target: 'labels',
mutation: () => ({ active: false })
}
]
}
}
}
]}
/>
</div>
I added a simple mutation that changes the slice to red on hover and that works great. I'm just having a difficult time finding the best way to make the slice scale up slightly without causing problems.
Thanks in advance
You can use a custom component to render slices
const CustomSlice = (props) => {
const [scale, setScale] = useState(1);
// modified transformation from here
// https://github.com/FormidableLabs/victory/blob/844109cfe4e40b23a4dcb565e551a5a98015d0c0/packages/victory-pie/src/slice.js#L74
const transform = `translate(${props.origin.x}, ${props.origin.y}) scale(${scale})`;
return (
<Slice
{...props}
style={{ ...props.style }}
events={{
onMouseOver: (e) => {
if (props.events.onMouseOver) {
props.events.onMouseOver(e);
}
setScale((c) => c * 1.2);
},
onMouseOut: (e) => {
if (props.events.onMouseOut) {
props.events.onMouseOut(e);
}
setScale(1);
}
}}
transform={transform}
/>
);
};
<div style={{ width: "150px" }}>
<VictoryPie
dataComponent={<CustomSlice />}
data={[
{ x: "Cats", y: 35, label: "Cats \n 35%" },
{ x: "Dogs", y: 40, label: "Dogs \n 40%" },
{ x: "Birds", y: 55, label: "Birds \n 55%" }
]}
labelComponent={
<VictoryTooltip
cornerRadius={10}
pointerWidth={30}
pointerLength={20}
flyoutPadding={{ top: 10, bottom: 10, left: 25, right: 25 }}
style={{ fontSize: "36px", fill: "#FFF" }}
flyoutStyle={{ fill: "#414B5F" }}
orientation="right"
/>
}
colorScale={["tomato", "orange", "gold", "cyan", "navy"]}
innerRadius={100}
events={[
{
target: "data",
eventHandlers: {
onMouseOver: (e) => {
return [
{
target: "data",
mutation: () => ({
style: { fill: "red", width: 30 }
})
},
{
target: "labels",
mutation: () => ({ active: true })
}
];
},
onMouseOut: () => {
return [
{
target: "data",
mutation: () => {}
},
{
target: "labels",
mutation: () => ({ active: false })
}
];
}
}
}
]}
/>
</div>

Pushing into an array object in react but not rendering on the screen

Im using react and displaying some labels via the array object of labels. Now, I want to do this dynamically. So if a user clicks a button, the object updates and the user interface should update accordingly as well. The issue here is that I got the array to update after clicking on the button, as evidenced by a console log line that I wrote in the onclick handler. But the user interface does not update accordingly. Just the array shows the values. Here is what the inital array looks like:
const labelsArray = [
{ label: 'Hey There', sublabel1: 'How are you?' },
{
label: 'Greetings', sublabel1: 'Fellows'
},
{ label: 'Awesome', sublabel1: 'Youre doing great', sublabel2: 'cool' }
];
I want to append a warningLabel, and errorLabel to the 2nd object of this array. So since arrays are 0 indexed, I did the following in the onclick handler:
const appendLabel = async () => {
labelsArray[1].warningLabel = "Hello";
labelsArray[1].errorLabel = "Hello";
console.log(labelsArray)
};
The array updates, but not the user interface. Which is really weird.
Also, this is not related to react state mutation, which I know because of my research of this topic when I was trying to figure it out. So just to be clear, its not about state mutation, which might have someone put this as a duplicate question. Its more of a react/object structure question. But I could be wrong! Anyways, any help is appreciated. Thanks!
Here is my whole component for reference
import React, { useState } from 'react';
import { Button, Typography } from '#material-ui/core';
import { withStyles } from '#material-ui/core/styles/';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import StepConnector from '#material-ui/core/StepConnector';
import PropTypes from 'prop-types';
const styles = theme => ({
stepLabelRoot: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
},
checklistHeader: {
fontWeight: 'bold',
marginTop: '80px'
},
connectorIcon: {
color: theme.palette.text.secondary
},
stepper: {
background: 'none',
fontWeight: 'bold'
},
checkListImageContainer: {
display: 'flex',
flexDirection: 'row',
alignItems: 'center'
},
connector: {
},
activeConnector: {
border: 'solid 1px #6fef71'
},
stepIcon: {
height: '35px',
width: '35px',
'&:hover': {
backgroundColor: 'rgba(134, 141, 150, 0.37)',
borderRadius: '50%'
},
},
activeStepIcon: {
backgroundColor: 'yellow'
},
label: {
fontWeight: 'bold',
display: 'flex',
fontSize: '15px'
},
sublabel: {
fontWeight: 'normal',
fontSize: '13px'
},
errorLabel: {
color: 'red'
},
warningLabel: {
color: 'yellow'
},
step: {
'&$completed': {
color: 'lightgreen'
},
'&$active': {
color: 'pink'
},
'&$disabled': {
color: 'red'
},
},
alternativeLabel: {},
active: {
}, // needed so that the &$active tag works
completed: {
},
disabled: {
},
labelContainer: {
'&$alternativeLabel': {
marginTop: 0
},
},
});
const labelsArray = [
{ label: 'Random text?', sublabel1: 'Lorem Ipsum' },
{
label: 'Another random text', sublabel1: 'Hello World'
},
{ label: 'Cool', sublabel1: 'cool', sublabel2: 'ayo' }
];
const Checklist = ({ classes,activeStep }) => {
return (
<React.Fragment>
<Stepper alternativeLabel activeStep={2} connector={<StepConnector />} className={classes.stepper}>
{labelsArray.map(label => (
<Step key={label} completed>
<StepLabel active
completed
StepIconProps={{
classes: {
root: classes.step,
completed: classes.completed,
active: classes.active,
disabled: classes.disabled
}
}}>
<div className={classes.stepLabelRoot}>
<span className={classes.label}>
{label.label}
</span>
<span className={classes.sublabel}>
{label.sublabel1}
</span>
<span className={classes.sublabel}>
{label.sublabel2}
</span>
<span className={classes.sublabel}>
{label.sublabel3}
</span>
<span className={classes.errorLabel}>
{label.errorLabel && <img src="/static/images/lock-material.png" alt="img" style={{ height: '15px', width: '15px' }} />}
{label.errorLabel}
</span>
<span className={classes.warningLabel}>
{label.warningLabel && <img src="/static/images/warning-sign.png" alt="img" style={{ height: '15px', width: '15px' }} />}
{label.warningLabel}
</span>
</div>
</StepLabel>
</Step>
))}
</Stepper>
<Button onClick={() => appendLabel()}>Hello</Button>
</React.Fragment>
);
};
Checklist.defaultProps = {
activeStep: -1
};
Checklist.propTypes = {
classes: PropTypes.object.isRequired,
form: PropTypes.bool.isRequired,
activeStep: PropTypes.number
};
export default withStyles(styles, { withTheme: true })(Checklist);
You need to set the labelsArray in the state and update it accordingly in order to re-render the component when the user clicks the button
Edited:
A way of doing that with a state would be:
const LABELS =[
{ label: 'Hey There', sublabel1: 'How are you?' },
{ label: 'Greetings', sublabel1: 'Fellows' },
{ label: 'Awesome', sublabel1: 'Youre doing great', sublabel2: 'cool' }
];
const [labelsArray, setLabelsArray] = useState(LABELS);
const appendLabel = () => {
let editedLabels = [...labelsArray];
editedLabels[1].warningLabel = "Hello";
editedLabels[1].errorLabel = "Hello";
setLabelsArray(editedLabels);
};

Change background color of Material Ui datepicker

I want to change the background color of my material ui datepicker modal
import { createMuiTheme } from "#material-ui/core";
const materialTheme = createMuiTheme({
overrides: {
MuiPickersToolbar: {
toolbar: {
backgroundColor: 'red',
},
},
MuiPickersDay: {
day: {
color: 'black',
},
daySelected: {
backgroundColor: '#33abb6',
},
dayDisabled: {
color: '#ccc',
},
current: {
color: 'red',
},
},
MuiPickersModal: {
dialogAction: {
color: '#33abb6',
},
},
},
});
export default materialTheme
In the above code i was able to change colors of date and few others but not the total background color
Are there any documentation from which i can get these class names or any other option
Try in CSS:
.MuiPaper-root {
background-color: #eaea87;
}
In recent version of MUI (v5.3.1) I resolved this issue by adding sx={{ backgroundColor: 'white' }} to TextField in renderInput prop as below:
<MobileDatePicker
label="Date"
value={date}
onChange={(newValue) => {
setDate(newValue);
}}
renderInput={(params) => (
<TextField
sx={{ backgroundColor: 'white' }}
fullWidth
{...params}
/>
)}
/>
You can use createTheme to provide component overrides (see docs):
const theme = createTheme({
components: {
// Name of the component
MuiInputBase: {
styleOverrides: {
// Name of the slot
root: {
// Some CSS
backgroundColor: "white",
// add variant styles like so
"&.Mui-disabled": {
"backgroundColor": "#cccccc"
}
},
},
},
},
});
You can see the name of the component to use by inspect element and looking at the class names, and you can find the slots in the component definition, e.g. this is the slots for the MuiInput component.
Also see this source on combining class names to target disabled, hover, active etc.
MuiPickers is using Dialog Material Ui, so override all dialog component that be used in this pickers. I'm not sure with this solution below. You can try this, hope it's worked.
const materialTheme = createMuiTheme({
overrides: {
MuiPickersToolbar: {
toolbar: {
backgroundColor: 'red',
},
},
MuiPickersDay: {
day: {
color: 'black',
},
daySelected: {
backgroundColor: '#33abb6',
},
dayDisabled: {
color: '#ccc',
},
current: {
color: 'red',
},
},
MuiPickersModal: {
dialogAction: {
color: '#33abb6',
backgroundColor: 'YOUR HEX HERE',
},
},
},
});
I think the good way is send style in DialogProps
https://material-ui-pickers.dev/api/DateTimePicker (section modal wrapper)
so then you can override all dialog modal.

I need help for merging values in object array - Javascript

I am working with one project , I have the data comes to me as Object Array and I need to combine the same keys in one key and make the value as an array of strings.
here is the data I have :
inputArray = [
{
colors: 'Red',
size: 'Small'
},
{
colors: 'Blue',
size: 'Large'
},
{
colors: 'Red',
size: 'Large'
},
{
colors: 'Pink',
size: 'X-Large'
}
]
and here is the required output :
outputArray = {
colors: ['Red','Blue','Pink'],
size: ['Large','X-large','Small']
}
You could use a simple dictionary structure to do this. And verify if every element already exists before adding it to array.
const outputArray = {
colors: [],
size: [],
};
for (elem of inputArray) {
if (!outputArray['colors'].includes(elem.colors)) {
outputArray['colors'].push(elem.colors);
}
if (!outputArray['size'].includes(elem.size)) {
outputArray['size'].push(elem.size);
}
}
which will give
{
colors: [ 'Red', 'Blue', 'Pink' ],
size: [ 'Small', 'Large', 'X-Large' ]
}
it's a basic one...
const inputArray =
[ { colors: 'Red', size: 'Small' }
, { colors: 'Blue', size: 'Large' }
, { colors: 'Red', size: 'Large' }
, { colors: 'Pink', size: 'X-Large'}
];
outputArray = inputArray.reduce((a,c)=>
{
if (!a.colors.includes(c.colors) ) a.colors.push( c.colors);
if (!a.size.includes(c.size) ) a.size.push( c.size);
return a
}
,{ colors:[], size:[]})
;
console.log (outputArray )
[edit] if you do not know the variety of entry keys, you can use:
inputArray =
[ { colors: 'Red', size: 'Small' }
, { colors: 'Blue', size: 'Large' }
, { colors: 'Red', size: 'Large' }
, { colors: 'Pink', size: 'X-Large', truc: 'bidule' }
];
outputArray = inputArray.reduce((a,c)=>
{
for (let key in c)
{
if (!a[key]) a[key] = []
if (!a[key].includes(c.colors) ) a[key].push( c[key])
}
return a
} ,{})
;
console.log (outputArray)
This seems to work...
let inputArray = [
{
colors: 'Red',
size: 'Small'
},
{
colors: 'Blue',
size: 'Large'
},
{
colors: 'Red',
size: 'Large'
},
{
colors: 'Pink',
size: 'X-Large'
}
]
let outputArray = [{colors: [], size: []}]
for (let i = 0; i<inputArray.length; i++){
outputArray[0].colors.push(inputArray[i].colors)
outputArray[0].size.push(inputArray[i].size)
}
console.log(outputArray)
Is this what you were after?
While this is not logically much different from the second part of the answer by Mister Jojo, it does the same thing without any mutations, in perhaps a more functional manner:
const gather = (xs) =>
xs .reduce (
(a, x) => Object .entries (x) .reduce ((a, [k, v]) => ({...a, [k]: (a[k] || []).concat(v)}), a),
{}
)
const inputArray = [{ colors: 'Red', size: 'Small'}, {colors: 'Blue', size: 'Large'}, {colors: 'Red', size: 'Large'}, {colors: 'Pink', size: 'X-Large'}]
console .log (gather (inputArray))
It is likely less performant than that version, for reasons described by Rich Snapp, but in practice I haven't seen this being a real issue.

React Native button map for a button group

Trying to figure out how to change the styling on just the first and last button. How do I tell the button which one is which? Beginner in JS and React/React Native trying to find my way. Currently coming out with no rounded buttons on either end. The Button element in the child is my own wrapper on TouchableOpacity and only accepts an object for the buttonStyles. Any help appreciated.
Parent component:
export class Rating extends React.Component {
ratings = [
{ text: '1' },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5' },
];
onButtonPress = (e) => {
console.log(e.target.value);
};
render() {
return (
<View>
{this.ratings.length && (
this.ratings.map((rating, index) => (
<View key={index}>
<RatingButton rating={rating} onButtonPress={this.onButtonPress} />
</View>
))
)
}
</View>
);
}
}
Child component:
const buttonStyles = () => {
const allButtons = {
backgroundColor: sc.colors.white.white,
borderWidth: 1.5,
borderColor: sc.colors.blue.darker1,
padding: sc.padding.lg,
};
const startButton = {
borderTopLeftRadius: sc.borderRadius.sm,
borderBottomLeftRadius: sc.borderRadius.sm,
borderRightWidth: 0.75,
...allButtons,
};
const endButton = {
borderTopRightRadius: sc.borderRadius.sm,
borderBottomRightRadius: sc.borderRadius.sm,
borderLeftWidth: 0.75,
...allButtons,
};
return StyleSheet.create({
allButtons,
startButton,
endButton,
buttonText: {
color: sc.colors.blue.darker1,
fontSize: sc.font.size.largeContent,
},
});
};
class RatingButton extends React.Component {
render() {
const { onButtonPress, rating } = this.props;
const styles = buttonStyles();
return (
<Button
buttonStyles={styles.allButtons}
textStyles={styles.buttonText}
onPress={onButtonPress}
>
{rating.text}
</Button>
);
}
}
Inside of your ratings variable, you could store another attribute for style like so:
ratings = [
{ text: '1', style: {backgroundColor:'red'} },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5', backgroundColor: 'yellow' },
];
And then inside of <RatingButton/> you can add the style to the element
<Button
buttonStyles={styles.allButtons}
textStyles={styles.buttonText}
onPress={onButtonPress}
style={rating.style}
>
{rating.text}
</Button>
Note: You could also pass a class through the rating variable.
ratings = [
{ text: '1', buttonStyle: 'startButton' },
{ text: '2' },
{ text: '3' },
{ text: '4' },
{ text: '5', buttonStyle: 'endButton' },
];
and set your style like this:
<Button
buttonStyles={ratings.buttonStyle?styles[rating.buttonStyle]:styles.allButtons}
textStyles={styles.buttonText}
onPress={onButtonPress}
style={rating.style}
>
{rating.text}
</Button>

Categories

Resources