Force ExpansionPanel to be expanded, when printing - reactjs

I am using an ExpansionPanel,
where I control the expanded state based on some conditions.
Although, I want the ExpansionPanel to be always expanded, when I am printing (window.print()).
What I intuitively wanted to try was:
//...
const isPrinting = useMediaQuery("print")
const controlledExpanded = useSomeMethodToControlExpanded()
const expanded = isPrinting || controlledExpanded
return (
<ExpansionPanel expanded={expanded}>
{/*...*/}
</ExpansionPanel>
)
Although this won't work because of a bug in browsers:
Maybe somehow override the global styling would help, but I cannot figure out how.
Any ideas?

You can use #media print in your css:
#media print {
div.MuiCollapse-container.MuiCollapse-hidden {
min-height: auto !important;
height: auto !important;
visibility: visible !important;
}
}
No need for anything in the react component

Related

Animating SVG group object - transform rotate with styled-components doesnt rotate around circle origin

I have an SVG circle and some line objects making a simple crosshair mouse cursor that i'm trying to animate with styled-components. When the cursor hovers over certain objects I'd like the line elements within the cursor to rotate around the origin of the circle element which makes up the cursor. A redux useSelector hook gives access to the mouseover/mouseout state of the components being hovered over. This part works well, as a simple stroke color change can be elicited using this method
const Cursor = (props) => {
const hoverState = useSelector(state => state.gameState.targetHovered);
// ...
return (
<Crosshair isHovering={hoverState} position={props.position}>
<circle
cx={cursorCoordinates.cx}
cy={cursorCoordinates.cy}
r={cursorCoordinates.outerRadius}
style={cursorStyle}
/>
<circle
cx={cursorCoordinates.cx}
cy={cursorCoordinates.cy}
r={cursorCoordinates.innerRadius}
style={cursorStyle}
/>
<line
id="top"
x1={cursorCoordinates.cx - cursorCoordinates.outerRadius}
y1={cursorCoordinates.cy}
x2={cursorCoordinates.cx - cursorCoordinates.innerRadius}
y2={cursorCoordinates.cy}
style={crossHairStyle}
/>
<line
id="bottom"
x1={cursorCoordinates.cx + cursorCoordinates.innerRadius}
y1={cursorCoordinates.cy}
x2={cursorCoordinates.cx + cursorCoordinates.outerRadius}
y2={cursorCoordinates.cy}
style={crossHairStyle}
/>
</Crosshair>
);
and the code for the styled components...
const lockOn = (x, y) => keyframes`
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(90deg);
}
`;
const Crosshair = styled.g`
transform-origin: ${props => props.position.x} ${props => props.position.y};
animation: ${props => props.isHovering ? lockOn : 'none'} 1s linear;
`;
i've tried to express the keyframes in a number of different ways, but each time, instead of rotating the elements within the styled group component, when a target object is hovered over by the cursor the animation instead flings it off to the right, as if the transform origin is incorrect somehow. Removing the transform-origin from Crosshair exhibits the same behaviour
I'm sure i'm making a simple syntax error. Any ideas?
Solution, as pointed out by #RobertLongson in the comments was to add
transform-box: fill-box;
inside the styled.g component, otherwise the transform-origin is the centre of the SVG object. More details on the MDN docs here: https://developer.mozilla.org/en-US/docs/Web/CSS/transform-box
Adding a transform-origin was also necessary. Note 'forwards' in the animation was required to prevent it from resetting while the cursor was still hovering over an object
const lockOn = (x, y) => keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(90deg);
}
`;
const Crosshair = styled.g`
transform-origin: 50% 50%;
transform-box: fill-box;
animation: ${props => props.isHovering ? lockOn : 'none'} 0.3s linear forwards;
`;

scss to styled-components conversion warning

In a project, I was using SCSS, where I wrote this code and it works like a charm:
.container {
padding: 0 1rem;
.container {
padding: 0;
}
}
Now, I am starting another project using styled-components. So, there I am writing these styles:
const Container = styled.div`
padding: 0 1rem;
${Container} {
padding: 0;
}
`;
Now I get a warning from compiler saying:
Container was used before it was defined.
I want to ignore this warning without making any changes to eslint-file or disabling eslint for the line itself. I also don't want to use var instead of const.
Also, I am not willing to use a class on the div and then use it again here. (I would consider this as the last option if I do not find any better way of doing this).
Is there any better way that I can change this code to ignore this warning?
If I understand your question/issue it seems you want to reference the same container component. Use & to refer back to the main component.
Using pseudoelements, pseudoselectors, and nesting
const Container = styled.div`
padding: 0 1rem;
& {
padding: 0;
}
`;

How to do SSR for responsive apps without knowing the device's screen size upfront?

I want to SSR my app for my users.
But my app code uses a useEffect to detect what is the size of the user's screen width, and only then the App is rendered.
Something like:
App.js
// THE LAYOUT INITIAL STATE IS NULL
useEffect(() => {
// CHECK FOR window.innerWidth AND DECIDE LAYOUT
// UPDATE LAYOUT STATE
});
return(
layout && <AppComponents> // IF THERE IS NO LAYOUT, NOTHING IS RENDERED
);
Component.js
// I SERVE THE LAYOUT THROUGH CONTEXT AND I ACCESS IT INSIDE OF THE COMPONENTS
const layout = useLayout();
return(
layout === "MOBILE" ? ComponentMobile : ComponentDesktop
);
QUESTION
I cannot rely on a code inside of a useEffect to render stuff on the server. So, somehow I need to "decide" which layout to use for the first and only render on the server.
So my options, at least the ones I've though of so far, are:
OPTION #1
Try to guess the user's device screen size, and render something that might not be optimal for their screen size.
Because right now, the CSS styles that I'm rendering depend on the user's screen size.
OPTION #2
Move entirely to media queries to handle responsiveness, so the CSS will always be the same and it will adapt automatically to whatever size of screen is being used.
So far I haven't been using media queries at all. All my layout decisions are made during the render, and all the component render the styles based on the layout that was decided from App.js state.
What is the best way of handling this? Is there a best practice for this?
NOTE:
I am using styled-components, so this is basically what I do:
This is a crude example, but that's the idea.
// THIS IS MUCH EASIER TO WRITE THAN A BUNCH OF MEDIA QUERIES (IMO)
const Styled_DIV = styled.div`
font-size: ${props =>
props.layout === "MOBILE" ? "16px"
: props.layout === "TABLET" ? "18px"
: "20px"
};
`;
Great, you're already using styled-components. Adding media queries is now trivial and actually more straightforward (IMO) than your suggested method.
In general, configuring layout with CSS performs better than with JS. And with SSR, like you said, the server can't determine the screen size yet with JS and useEffect.
If you're mobile first, you can write the above logic with media queries like this:
const Styled_DIV = styled.div`
font-size: 16px;
#media (min-width: 768px) {
font-size: 18px;
}
#media (min-width: 1024px) {
font-size: 20px;
}
`
I wrote a helper object export so I don't have to remember the pixel sizes or even the syntax for media queries:
export const size = {
tablet: 768,
desktop: 1024,
}
export const device = {
tablet: `#media (min-width: ${size.tablet}px)`,
desktop: `#media (min-width: ${size.desktop}px)`,
}
So now I just have to write:
const Styled_DIV = styled.div`
font-size: 16px;
${device.tablet} {
font-size: 18px;
}
${device.desktop} {
font-size: 20px;
}
`
Since device is an exported object, my VSCode editor automatically helps me import it when I start typing.

AgGrid: How to blink cell in different color depending on change

I'm using ag-grid-react like this:
import { AgGridReact } from "ag-grid-react";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-balham.css";
and declares it like this in render(some details removed for clarity):
return <div className="MarketGrid ag-theme-balham" >
<AgGridReact domLayout='autoHeight'
enableCellChangeFlash={true}
rowSelection={'single'}
onSelectionChanged={this.onSelectionChanged.bind(this)}
onGridReady={this.onGridReady.bind(this)} />
</div>;
the "enableCellChangeFlash" property works fine, and I know how to change the color of it, but what if I want to change the color depending on whether the new value is higher or lower than the previous?
My update code looks somewhat like this:
let row = this.gridApi.getRowNode(this.props.productIds.indexOf(id));
for (var f in data) {
row.setDataValue(f, data[f]);
}
}
I guess I should set the cell style somewhere, but I'm not sure where.
UPDATE: According to this page https://www.ag-grid.com/javascript-grid-data-update/#flashing I should do this:
"If you want to override how the flash presents itself (eg change the background color, or remove the animation) then override the relevant CSS classes."
Anyone knows how to do this?
I almost got this now. The answer I found out is based on CSS. Set the classname for blinking/stop-blinking like:
return (<div key={Math.random()}
className={some logic to set classname here, like "blink-red" or "blink-blue"}
onAnimationEnd={() => this.setState({ fade: false })}
> {this.state.value} </div>);
and use onAnimationEnd to set some state variable that will affect that logic.
Then add the fading logic like this to CSS:
.blink-red {
animation: redtotransparent 3s ease 5s;
}
#keyframes redtotransparent {
from {
background-color: red;
color: white;
}
to {
background-color: transparent;
color: black;
}
}
It's still not perfect, but almost there. Changing the key makes React think the DOM has changed. When I come up with anything better I will add it here.
Click on the Flashing Cell option in the dropdown at the top and then you can choose a different color for an up change and a down change. you can also set how long it will flash for.

React-diagrams invisible

Following the installation guide in projectstorm/react-diagrams docs, I have trouble with the diagram not rendering properly. Inspecting the page reveals the positions of the nodes - but they are invisible. Using sass, I have imported into app.scss
#import "~storm-react-diagrams/src/sass/main";
I have also tried using the raw minified css with no improvement.
I still assume this is an error on my end, possibly I create the engine in the wrong place? I have a engineReducer to provide the default engine.
import * as SRD from "storm-react-diagrams";
//1) setup the diagram engine
var engine = new SRD.DiagramEngine();
engine.installDefaultFactories();
//2) setup the diagram model
var model = new SRD.DiagramModel();
//3-A) create a default node
var node1 = new SRD.DefaultNodeModel("Node 1", "rgb(0,192,255)");
let port1 = node1.addOutPort("Out");
node1.setPosition(100, 100);
//3-B) create another default node
var node2 = new SRD.DefaultNodeModel("Node 2", "rgb(192,255,0)");
let port2 = node2.addInPort("In");
node2.setPosition(400, 100);
// link the ports
let link1 = port1.link(port2);
link1.addLabel("Hello World!");
//4) add the models to the root graph
model.addAll(node1, node2, link1);
//5) load model into engine
engine.setDiagramModel(model);
const initialEngine = engine;
export default function (state = engine, action) {
return state;
}
Then, my main component looks like this:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import * as SRD from "storm-react-diagrams"
import {connect} from 'react-redux';
class Main extends Component {
render() {
console.log(this.props.engine); // Looks good!
return (
<div className="app">
<SRD.DiagramWidget className="srd-demo-canvas" diagramEngine={this.props.engine} />
</div>
);
}
}
function mapStateToProps(state) {
return { engine: state.engine };
}
export default connect(mapStateToProps)(Main)
Quite honestly I dont understand the docs reference to
In your library code
that is, where should I initialize the engine? What else am I missing?
You need to set a explicit height for the widget. Something like:
.srd-demo-canvas {
height: 100vh;
}
.srd-demo-canvas {
height: 100vh;
background-color: rgb(60,60,60)
}
Setting the background-color in addition to the height helped me see the links against the white background that Chrome gave me by default.
If you want the grid that the demos show, then install sass and:
.srd-demo-canvas{
height: 100%;
min-height: 300px;
background-color: rgb(60,60,60) !important;
$color: rgba(white, .05);
background-image:
linear-gradient(0deg,
transparent 24%,
$color 25%,
$color 26%,
transparent 27%,
transparent 74%,
$color 75%,
$color 76%,
transparent 77%,
transparent),
linear-gradient(90deg,
transparent 24%,
$color 25%,
$color 26%,
transparent 27%,
transparent 74%,
$color 75%,
$color 76%,
transparent 77%,
transparent);
background-size:50px 50px;
.pointui{
fill: rgba(white,0.5);
}
}
I tried following the suggested fixes but nothing worked for me.
Here's what really fixed the issue for both the nodes and the elements not showing properly.
I removed the importing of the storm-react-diagrams/dist/style.min.css
and instead, I created a custom CSS file which is the above file with the following modifications (You can find it under "node_modules/storm-react-diagrams/dist/" style.min.css):
.srd-diagram{position:unset;flex-grow:1;display:flex;cursor:move;overflow:visible}
(position to unset and overflow to visible)
.srd-link-layer{position:unset; ...}
(position to unset)
In general , the wrapper element (div for example) should have those css properties.
display:grid;
height: 100vh;
min-height: 100%;
width: 100vw;
Hello guys I have decided to start my own flowchart open project with ReactJs, but if you need, you can adapt it to pure javascript, please feel free to contribute.
https://github.com/lmoraobando/lmDiagram

Resources