Retrieve extended styles - styled-components

My code is:
styled(Button)`
color: ${(props: any) => COLOR_I_CHOOSE}
`
I was following the "extending styles" section in the docs - https://www.styled-components.com/docs/basics#extending-styles
Button is a custom styled component. I want to pass in a color so it overrides the internal setting of the color to COLOR_I_CHOOSE. I have control over the internals. In the internals I am trying to detect if any styled overrides were provided and use that.
Internally I set the CSS like this:
const primaryChildre
nCSS = css`
color: ${(props: any) => {
console.log('props:', props);
// TODO: test if props has override on color and use that
// PSEUDOCODE: if (props.styleExtensions.color) return props.styleExtensions.color
return props.inverse
? props.theme.ns().colors.brand
: props.theme.ns().colors.white;
}};
`;
I logged out props here, but can't figure out how to get that. I want to do as the pseudocode comment in the above.

<Button> Hello</Button> // default color
The following will override the default color of Button if the passed color is not red.
const MyRedTextButton = styled(Button)`
color: ${(props: any) => props.color === 'red' ? 'inherit' : props.color}
`
Then:
<MyRedTextButton color="red"> Hello </MyRedTextButton> // color of 'Hello' = the color of <Button/>
<MyRedTextButton color="blue"> Hello </MyRedTextButton> // color of 'Hello' = blue
Does this solve your problem?

Related

${StyledComponent}:hover & {...} Not triggering on hover

Below are two styled-components as and the JSX how they are used in a Gatsby project. I am using gatsby's specific styled-components plugin.
const PhotoWrapper = styled(Card)`
{...styles}
&:hover {
{...hoverStyles}
}
`
const CardTitle = styled.h3`
{...styles}
${PhotoWrapper}:hover & {
{...titleHoverStyles}
}
`
return (
<Slide>
<PhotoWrapper>
<GatsbyImage
image={projectPhoto}
alt={`Screenshot of ${project.name}`}
/>
</PhotoWrapper>
<CardSection>
<CardTitle>{project.name}</CardTitle>
<DetailsWrapper>
{frontEndContainer}
{backEndContainer}
</DetailsWrapper>
</CardSection>
</Slide>
);
The PhotoWrapper hover styles work, but the Title hover styles do not take effect when the PhotoWrapper is hovered over. Is it a prerequisite that the Title component be a child of the PhotoWrapper or is there a better selector to use?
One more thing to note {...styles} is used only in this code snippet. In my project, I list each style instead of deconstructing an object.
I have also tried this format with little luck but I believe this is specifically a 'children of' selector:
const PhotoWrapper = styled(Card)`
{...styles}
&:hover {
{...hoverStyles}
}
&:hover ${CardTitle} {
{...titleHoverStyles}
}
`

Background: url() using .attrs() function

I'm trying to display a different background depending on props with .attrs();
I have the following;
const Heart = styled.div.attrs(props => ({
background: `url(${props => props.filled ? "./media/heart-filled.png" : "./media/heart-empty.png"})`
}))`
//rest of styles here.
`;
However, it doesn't display anything. How exactly does this function work?
I don't know why you're trying to use .attrs here, but it's used to attache some props to a styled component.
https://styled-components.com/docs/api#attrs
To make your code work, you could try:
const Heart = styled.div.attrs(props => ({/* Some aditional props here ! */}))`
background: url(${props => (props.filled ? "./media/heart-filled.png" : "./media/heart-empty.png")}); /* props that you pass into your component can be used here */
/* rest of styles here. */
`;
https://codesandbox.io/s/condescending-brown-lx0lf?file=/src/App.js

Why is theme undefined in styled component props?

Here I access theme by passing a callback function to the styled tag. I guess styled calls this callback function with the props as first argument. This works well.
export default function SectionHeading(props: SectionHeadingProps) {
const Heading = styled.h2`
${props => props.theme.green && `
color: green;
`}
`;
return (
<Heading>{propss.children}</Heading>
);
}
In this example I pass an expression that contains the props the component has received. Here, theme is undefined.
export default function SectionHeading(props: SectionHeadingProps) {
const Heading = styled.h2`
${props.theme.green && `
color: green;
`}
`;
return (
<Heading>{props.children}</Heading>
);
}
Why is theme undefined in the second example?
The reason is that these are different "props" and they are evaluated in different times, in the first example, the props are the props passed to the styled component, augmented with theme (provided you used <ThemeProvider .../>. In the second example, it is the props passed to your component.
The injection of the theme is done by styled-component library and only to styled components. Your component doesn't get it (because it is not a styled component).
Btw, your code has redundant nesting and creates a styled component each time it is invoked.
The way to do it is to simply define:
const SectionHeading = styled.div`
${props => (props.theme && props.theme.green && {color: 'green'})};
`;
and then:
export default SectionHeading;
Note that your sample code has a typo in the first part, you wrote {propss.children} (an extra 's').

Styled Components - why does prop position affect styling?

I'm using styled-components to style a parent and child element in a component:
function StyledDemo({
name,
light,
...props
}) {
return (
<Parent {...props}>
<Child>{name}</Child>
</Parent>
);
}
I have a light prop which is true/false - but I'm having an issue with styling the elements based on the value of that property:
const Parent = styled.div`
background-color: #000;
width: 100%;
${props => props.light && `
background-color: #ccc;
`}
`;
The styling only seems to work when I remove the prop being passed into the function individually.
Parent element uses correct styling based on light prop value when:
function StyledDemo({ name, ...props })
Parent element does NOT use correct styling based on light prop value when:
function StyledDemo({ name, light, ...props })
I can get it all working by setting the prop on the Parent and Child component, but this doesn't seem like it's the best way:
return (
<Parent {...props} light={light}>
<Child light={light}>{name}</Child>
</Parent>
);
Is this the correct way to apply styles to components based on props, or is there an issue with my approach?
I have a demo to tinker with if it helps:
https://www.webpackbin.com/bins/-Kfcsujw99cjU7ttqgTz
This is not related to styled-components but to the rest parameter.
When you do the rest operator, any property you "pick" out by name won't be contained in the ...rest variable. So when you do
const Button = ({ light, ...rest }) => ()
<Button light primary />
rest will only contain the primary property, but not light, that's now it's own variable.
If you did
const Button = ({ ...rest }) => ()
<Button light primary />
instead rest would also contain light.
So in your example, you're picking out light from ...props, so when you pass {...props} on to the parent it doesn't contain light anymore, so styled-components doesn't know it exists! Either you go with your first version, or you have to manually apply it to each component.
See MDN for more information about the rest parameter!

AmChart export change font color on export

i have i problem and tried different solutions, but no success.
I have an amChartXY chart, which has white labels and legend text is white, but when i want to build custom pdf report, i cannot convert those white text into black.
First i have a function which exports chart to base64 string, and i want there to convert the text color to black, but it won't work.
Here is a code snippet of a menu item, that converts to SVG that is saved to global array object.
menu: [
{
class: "",
label: "Save to draft",
click: function() {
var overrideObject = {
backgroundColor : "rgba(255,255,255,1)",
color : "#000",
legend : {
color : "#000"
}
};
var chartObject = this;
chartObject.capture(overrideObject, function () {
chartObject.toJPG({}, function (base64) {
// charts is global array
charts.push({
name: customName,
chart: base64
});
});
});
}
},
Here the overrideObject is changing the backgroundColor attribute with white ( before is was transparent ) but it's not changing font color. Also i have tried different attributes to add, but nothing seems to work.
Is this possible at capture time ?
Here are some images preview of what i want to accomplish :
AmChart for export isn't that well documented, so any feedback would be welcome
The overrideObject you're passing only accepts the same parameters listed in the list of export settings. If you need to change the appearance of specific elements on the chart, you need to use the reviver callback mentioned in the annotation settings section to selectively apply your modifications. For example, here's how to target the value axis labels:
"export": {
"enabled": true,
"reviver": function(nodeObj) {
if (nodeObj.className === 'amcharts-axis-label' && nodeObj.svg.parentNode.classList.contains('amcharts-value-axis')) {
nodeObj.fill = 'rgba(255,0,0,1)';
}
},
// ...
}
Note that you need to use SVG attributes to change the appearance, so you'll have to set the fill to change the color of the text element.
Codepen demo

Resources