the function ToHaveStyleRule doesn't work with hover - react-testing-library

I created a component to be an Icons wrapper, so I don't need to keep editing the icon in the style of the file I use... However, when testing a property that can be applied to the "hover" component , the test says that this property does not exist, even passing!
file index
export type IconsProps = {
hoverColor?: colorTypes
}
const Icons = ({ hoverColor }: IconsProps) => (
<S.Wrapper color={color} size={size} hoverColor={hoverColor}>
{children}
</S.Wrapper>
)
file style
const wrapperModifiers = {
hoverColor: (theme: DefaultTheme, hoverColor: colorTypes) => css`
& :hover {
color: ${theme.colors[hoverColor]};
}
`,
}
export const Wrapper = styled.main<IconsProps>`
${({ theme, hoverColor }) => css`
> ${StyledIconBase} {
${!!hoverColor && wrapperModifiers.hoverColor(theme, hoverColor)}
}
`}
`
test
import { Coffee } from '#styled-icons/boxicons-solid'
it('deve testar o hover e o transform', () => {
const { debug, container } = renderWithTheme(
<Icons color="primary" size="5rem" hoverColor="secondary">
<Coffee title="Coffee" />
</Icons>,
)
expect(screen.getByRole('img', { name: /coffee/i })).toHaveStyleRule(
'color',
'#0487cc',
{
modifier: ':hover',
},
)
})
error
No style rules found on passed Component using options:
{"modifier":":hover"}

In my opinion, the error that you are getting is that you haven't properly selected the element which is having a hover color. Because of that reason, jest-styled-component is not able to find the element with a hover modifier.
& :hover {
color: ${theme.colors[hoverColor]};
}
You added a space between & and : which is not right. The hover will not be applied to the selected element.
Solution: Remove the space between them.
&:hover {
color: ${theme.colors[hoverColor]};
}

Related

Multiple Doughnut chart as markers over Openstreetmap

I'm in trouble while implementing the doughnut chart over OpenStreetMap. I'm using react-chartjs2 for the doughnut chart and react-leaflet for Openstreetmap. Like we use the location icon on different coordinates over the map but here I want to use a Doughnut graph over the map instead of the location icon.
I want to achieve something like this
As per the react-leaflet documentation, the Marker icon property accepts two types of icons that is icon strings like image URL and divIcon which can be some HTML elements but while I'm rendering react component it does not accept and not showing it.
Here you can check in codesandbox I have added code to make it easy to try
https://codesandbox.io/s/doughnut-chart-over-osm-map-1indvl?file=/src/App.js
For what I know marker Icons can only be static, I use a function to create my only markers based on icons and plain html. Will be hard to do that with a component in your case.
My icon render function
import { divIcon } from "leaflet";
import { ReactElement } from "react";
import { renderToString } from "react-dom/server";
export const createLeafletIcon = (
icon: ReactElement,
size: number,
className?: string,
width: number = size,
height: number = size
) => {
return divIcon({
html: renderToString(icon),
iconSize: [width, height],
iconAnchor: [width / 2, height],
popupAnchor: [0, -height],
className: className ? className : "",
});
};
In your case I would try to cheese it and create blank markers and show the graph in popups instead and just force the popups to alway stay open.
EDIT: Added my custom Marker code below that have some nice options.
You can just use the defaultOpen option, and add the graph as a child component to the marker and it will show up in the popup. You can the change the styling of you liking to make it look like the graph is the marker.
import { LatLngLiteral } from "leaflet";
import React, { Children, ReactElement, useEffect, useRef } from "react";
import { Marker, Popup, useMap } from "react-leaflet";
import { MapPin } from "tabler-icons-react";
import { createLeafletIcon } from "./utils";
export interface LeafletMarkerProps {
position: LatLngLiteral;
flyToPosition?: boolean;
size?: number;
color?: string;
icon?: ReactElement;
defaultOpen?: boolean;
onOpen?: () => void;
children?: React.ReactNode;
markerType?: string;
zIndexOffset?: number;
}
const LeafletMarker: React.FC<LeafletMarkerProps> = ({
position,
flyToPosition = false,
children,
size = 30,
color,
defaultOpen = false,
onOpen,
icon = <MapPin size={size} color={color} />,
markerType,
zIndexOffset,
}) => {
const map = useMap();
const markerRef = useRef(null);
position && flyToPosition && map.flyTo(position);
const markerIcon = createLeafletIcon(icon, size, markerType); // Important to not get default styling
useEffect(() => {
if (defaultOpen) {
try {
// #ts-ignore
if (markerRef.current !== null && !markerRef.current.isPopupOpen()) {
// #ts-ignore
markerRef.current.openPopup();
}
} catch (error) {}
}
}, [defaultOpen, position.lat, position.lng]);
return (
<Marker
eventHandlers={{
popupopen: () => onOpen && onOpen(),
}}
ref={markerRef}
icon={markerIcon}
position={position}
zIndexOffset={zIndexOffset}
>
{/* autoPan important to not have jittering */}
<Popup autoPan={false}>{children}</Popup>
</Marker>
);
};
export default LeafletMarker;

Change color of selected row on Material UI table

How to change/customize the default color of selected rows in a Material-UI table (of type Sorting & Selecting)? By default it is secondary (red) color (Codesandbox here: https://codesandbox.io/s/3sjxh). How to change it to a custom color, or at least to primary (blue), as it appears in the new beta version (https://next.material-ui.com/components/tables/#main-content) (v5).
You have to pass your styles to the classes props in order to change the styles for the TableRow.
To achieve the background-color change you want to override the default classes: .MuiTableRow-root.Mui-selected and .MuiTableRow-root.Mui-selected:hover.
To override them you have to use a parent reference with a so called $ruleName in your makeStyles hook. Here is a very good explanation from #Ryan Cogswell if you are more interested how it works.
This would then look like this:
const useStyles = makeStyles((theme) => ({
// your other styles
...,
tableRowRoot: {
"&$tableRowSelected, &$tableRowSelected:hover": {
backgroundColor: theme.palette.primary.main
}
},
tableRowSelected: {
backgroundColor: theme.palette.primary.main
}
}));
...
<TableRow
// your other props
...
classes={{
root: classes.tableRowRoot,
selected: classes. tableRowSelected,
}}
>
...
</TableRow>;
For the checkboxes, you only have to add the color prop in order to change it:
<Checkbox
// other props
...
color="primary"
/>
and for your Toolbar, you only need to change the provided highlight class inside your useToolbarStyles in order to get things working:
import { alpha } from "#material-ui/core/styles";
...
const useToolbarStyles = makeStyles((theme) => ({
...,
highlight:
theme.palette.type === "light"
? {
color: theme.palette.primary.main,
backgroundColor: alpha(
theme.palette.primary.light,
theme.palette.action.selectedOpacity
)
}
: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.primary.dark
},
}));
Live demo:

createMuiTheme overrides, for a particular component style

Is it possible to override the default style of a particular Material UI component style? Let's say I want have different types of MuiButton's...
<Button color="primary" variant="contained">Foo</Button>
<Button variant="text">Foo</Button>
With the default styles the first button will have a white text color and the second one will have a black text color. If I would like to change the text color default globally (which in this case I won't) I should use the following options for createMuiTheme:
const options = {
overrides: {
MuiButton: {
root: {
color: 'white',
}
}
}
};
However in this case I would only like to change the text color of the primary colored and contained variant button. How do I do this?
From the documentation it was not very clear to me but apparently you can target different classes in the component like so:
const options = {
overrides: {
MuiButton: {
containedPrimary: {
'& > .MuiButton-label': {
color: 'white'
},
}
}
}
};

Unable to pass parameter from command to converter

I'm trying to edit the actual existing plugin of highlight to be able to add text color customizable from command argument, which means that if you put RGB or hex color it will take it on the selection create a view attribute style = 'color: PARAMETER'
What I got so far just surround the text with font tag and the style attribute with color but with a color value incorrect.
Which mean the value on the command is not being passed to the converter.
I'm being unable to find a way to transfer input information from a command to use directly in the converter to make this feature works.
The normal behavior in this plugin make it impossible to use the 16 million colors from RGB, and it requires an obsolete model of defined colors.
You can see/edit/use what i've done so far in this repo
https://github.com/klys/ckeditor5-highlight-inline
In this part the converter create the font element with the style color but with a incorrect value for color value.
editor.conversion.attributeToElement( {
model: HIGHLIGHT,
view: {
name: 'font',
styles: {
'color': true
},
priority: 5,
model: {
key: 'highlight',
value: viewElement => viewElement.getAttribute( 'color' )
},
type:'pen'
}
} );
And this the edited command executor from the original plugin, which i edit to meet the needs of this feature.
execute( color ) {
const model = this.editor.model;
const document = model.document;
const selection = document.selection;
//const highlighter = options.value;
/*var __model;
for ( const option of options ) {
__model = new Model( {
model: 'color model',
class: 'color-class',
title: 'color pen',
color: option.value,
type: 'pen'
} );
}
const highlighter = __model;*/
model.change( writer => {
const ranges = model.schema.getValidRanges( selection.getRanges(), 'highlight' );
if ( selection.isCollapsed ) {
const position = selection.getFirstPosition();
// When selection is inside text with `highlight` attribute.
if ( selection.hasAttribute( 'highlight' ) ) {
// Find the full highlighted range.
const isSameHighlight = value => {
return value.item.hasAttribute( 'highlight' ) && value.item.getAttribute( 'highlight' ) === this.value;
};
const highlightStart = position.getLastMatchingPosition( isSameHighlight, { direction: 'backward' } );
const highlightEnd = position.getLastMatchingPosition( isSameHighlight );
const highlightRange = writer.createRange( highlightStart, highlightEnd );
// Then depending on current value...
if ( !color || this.value === color ) {
// ...remove attribute when passing highlighter different then current or executing "eraser".
writer.removeAttribute( 'highlight', highlightRange );
writer.removeSelectionAttribute( 'highlight' );
} else {
// ...update `highlight` value.
writer.setAttribute( 'highlight', color, highlightRange );
writer.setSelectionAttribute( 'highlight', color );
}
} else if ( color ) {
writer.setSelectionAttribute( 'highlight', color );
}
} else {
for ( const range of ranges ) {
if ( color ) {
writer.setAttribute( 'highlight', color, range );
} else {
writer.removeAttribute( 'highlight', range );
}
}
}
} );
}
I have been almost a week in this problem.
If you can a least point me out in the right direction, you won't imagine how much you will help me.

How do I make multiline hilighter on draft-js?

Now I make markdown highlighter.
Highlight inline is not so difficult. I use CompositeDecorator to rewrite text. https://facebook.github.io/draft-js/docs/advanced-topics-decorators.html
But I can't use multiline syntax (for example, codeblock). By default, newline becomes next block and decorator is handled by block to block.
Below image is example of my implementation. I can't decorate codeblock syntax.
How do I make multiline highlighter on draft-js?
Depends on what 'Highlight' style you want. Mostly the inline style should be enough if you just want some color or font size. check the color example.
While for block style, you need a custom CSS class and map the block to your class, refer this.
I found work around. Detecting markdown codeblock by dand on blockRendererFn.
// use blockRedererFn
<Editor
blockRendererFn={(block) => blockRenderer(block, this.state.editorState)}
editorState={this.state.editorState}
/>;
// detect code block and add fontFamily: monospace
// Example
//
// ```
// here
// ```
function blockRenderer(contentBlock, editorState) {
const type = contentBlock.getType();
if (type === "unstyled") {
const allText = editorState.getCurrentContent().getPlainText();
const allCount = countCodeBlockHeader(allText);
if (allCount > 0 && allCount % 2 === 0) {
const contentText = contentBlock.getText();
const [before, after] = allText.split(contentText);
const beforeCount = countCodeBlockHeader(before);
const afterCount = countCodeBlockHeader(after);
if (beforeCount % 2 === 1) {
if (afterCount % 2 === 1) {
return {
component: (_props) => {
return <code style={{
fontFamily: "monospace",
direction: "ltr",
unicodeBidi: "bidi-override",
}}>{contentText}</code>;
},
editable: true
};
}
}
}
}
}
function countCodeBlockHeader(text) {
return text
.split("\n")
.filter(l => l.match(new RegExp("^(```)")))
.length;
}
but it's dirty.