I'd like to access the public method recomputeGridSize on one of the Grids that I'm rendering. I've created the ref but when I try call the method it appears that the method is not available.
See below where the ref is defined in the final Grid:
render() {
const { structure, columnHeaderIndex, variables } = this.props;
const {
sidebarWidth,
headerHeight,
headerRowCount,
height,
gridHeight,
gridWidth
} = variables;
const rowCount = structure.length;
const columnCount = columnHeaderIndex.length;
if (structure.length === 0 || columnCount.length === 0) return null;
console.log(this.bodyGrid);
return (
<div>
<ScrollSync>
{({
clientHeight,
clientWidth,
onScroll,
scrollHeight,
scrollLeft,
scrollTop,
scrollWidth
}) => {
return (
<div>
<div
className="LeftSideGridContainer"
style={{
position: 'absolute',
top: 0,
left: 0,
backgroundColor: 'black',
borderBottom: '1px solid black',
color: 'white'
}}
>
<Grid
cellRenderer={this.renderLeftHeaderCell}
className="header-grid"
width={sidebarWidth + 1}
columnWidth={sidebarWidth + 1}
height={headerHeight}
rowHeight={headerHeight}
rowCount={1}
columnCount={1}
/>
</div>
<div
className="LeftSideGridContainer"
style={{
position: 'absolute',
top: headerHeight,
left: 0,
borderTop: '1px solid black',
backgroundColor: 'white',
color: 'black'
}}
>
<Grid
cellRenderer={this.renderLeftSideCell}
columnWidth={sidebarWidth + 1}
columnCount={1}
className="left-side-grid"
height={height}
rowHeight={gridHeight}
rowCount={rowCount}
scrollTop={scrollTop}
width={sidebarWidth + 1}
/>
</div>
<div className="grid-column">
<AutoSizer disableHeight>
{({ width }) =>
<div>
<div
style={{
height: headerHeight,
width: width - scrollbarsize(),
overflow: 'hidden'
}}
>
<Grid
className="header-grid"
cellRenderer={this.cellRenderer}
cellRangeRenderer={this.renderHeaderCells}
columnWidth={gridWidth}
columnCount={columnCount}
height={headerHeight}
rowHeight={headerHeight / headerRowCount}
rowCount={headerRowCount}
scrollLeft={scrollLeft}
width={width - scrollbarsize()}
/>
</div>
<div
style={{
height: height,
width: width,
borderLeft: '1px solid black',
borderTop: '1px solid black'
}}
>
<Grid
className="calendar-body"
cellRenderer={this.cellRenderer}
cellRangeRenderer={this.cellRangeRenderer}
columnWidth={gridWidth}
columnCount={columnCount}
height={height}
rowHeight={gridHeight}
rowCount={rowCount}
width={width}
onScroll={onScroll}
ref={ref => {
this.bodyGrid = ref;
}}
/>
</div>
</div>}
</AutoSizer>
</div>
</div>
);
}}
</ScrollSync>
</div>
);
}
And you can see that if I console.log(this.bodyGrid) that none of the public methods defined in the documentation are available:
Am I doing something wrong here?
I don't think the screenshot shows what you think it shows. The Grid API methods should be within a __proto__ proprety further down:
Without seeing your full code it's not really possible to tell what's going on, but Grid definitely defines a method recomputeGridSize. The CellMeasurer component, for example, works by calling this method.
Related
I want to upload a csv file and later parse it in json format, I have created a state in which i am setting the file using the HTMLEvent Property.I am using typescript I have defined the possible types while defining the state but I am still getting the error.
import {
Box,
Button,
IconButton,
Modal,
Stack,
LinearProgress,
Typography
} from '#mui/material';
import React, { useState } from 'react';
import UploadIcon from '#mui/icons-material/Upload';
import CancelIcon from '#mui/icons-material/Cancel';
import { csvFileParser } from '../../../utils/csvFileParser';
type Props = {};
const BulkServiceUpload = (props: Props) => {
const [openModal, setOpenModal] = useState(false);
const [filename, setFileName] = useState<File | undefined | null>();
console.log(filename);
const style = {
position: 'absolute' as 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 600,
bgcolor: 'background.paper',
border: '2px solid #000',
boxShadow: 24,
borderRadius: '1rem',
borderWidth: 0,
p: 4
};
const serviceMasterParser = async () => {
if (filename === null) {
alert('Please select a file');
} else {
const parsedCSVData: object[] = csvFileParser(filename);
console.log(parsedCSVData);
}
};
return (
<>
<Box>
<Button
variant="contained"
color="success"
onClick={() => setOpenModal(true)}
>
<UploadIcon />
Add Service
</Button>
</Box>
<Modal open={openModal} onClose={() => setOpenModal(false)}>
<Stack padding={3} sx={style} spacing={3}>
<Typography marginY={3} variant="h5" fontWeight={600}>
Upload Service in Bulk
</Typography>
<Box
sx={{
border: 'dashed 1px black',
borderRadius: '1rem',
position: 'relative',
background: '#f0f0f0',
'&:hover': {
backgroundColor: '#EFFAF5'
}
}}
>
<Box position="absolute" width="100%" height="100%" p={3}>
<Box display="flex" justifyContent="center" alignItems="center">
<UploadIcon />
<Typography>Bulk Upload Service Master</Typography>
</Box>
<Typography fontSize="10px" textAlign="center">
only .csv file is supported
</Typography>
</Box>
<input
type="file"
accept=".csv"
onChange={(e: React.FormEvent<HTMLInputElement>) =>
setFileName((e.target as HTMLInputElement).files[0]!)
}
style={{
width: '100%',
height: '150px',
cursor: 'pointer',
opacity: '0'
}}
/>
<Box
p={1}
display={`${filename === null ? 'none' : 'flex'}`}
justifyContent="space-between"
alignItems="center"
sx={{
background: '#f5f5f5',
borderRadius: '15px'
}}
margin={2}
>
<Typography fontSize={14}>{filename?.name!}</Typography>
<IconButton
color="inherit"
aria-label="delete file"
component="label"
onClick={() => {
setFileName(undefined);
}}
>
<CancelIcon fontSize="small" />
</IconButton>
</Box>
{/* <LinearProgress variant="determinate" value={50} /> */}
</Box>
<Button
variant="contained"
color="success"
onClick={() => serviceMasterParser()}
>
<UploadIcon />
Bulk Upload
</Button>
<Button color="success" fullWidth variant="contained">
Add Single Service
</Button>
</Stack>
</Modal>
</>
);
};
export default BulkServiceUpload;
I don't want any initial value for my file.But If i will take useState value empty it will be by default an undefined value. Which is creating this problem. Please let me know how can I solve this .This is my first question so if I have made any mistake my appologies in advance.
Make sure files exists in the target
onChange={(e: React.FormEvent<HTMLInputElement>) =>
setFileName((e.target as HTMLInputElement)?.files?.[0])
}
Hi Everyone I think I have made a small typo error while setting the value of a file
<input
type="file"
accept=".csv"
onChange={(e: React.FormEvent<HTMLInputElement>) =>
setFileName((e.target as HTMLInputElement).files[0]!)
}
style={{
width: '100%',
height: '150px',
cursor: 'pointer',
opacity: '0'
}}
/>
I should have used the ! after files and it resolved the issue
<input
type="file"
accept=".csv"
onChange={(e: React.FormEvent<HTMLInputElement>) =>
setFileName((e.target as HTMLInputElement).files![0])
}
style={{
width: '100%',
height: '150px',
cursor: 'pointer',
opacity: '0'
}}
/>
const Btn = () => {
const options = ['test1', 'test2', 'test3'];
return (
<div style={{ position: 'absolute', left: '8px', widht: 'auto', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', backgroundColor: '#006C84' }}>
{options.map(opt => (
<span style={{ paddingRight: '10px' }}>{opt}</span>)
)}
</div>
)
}
Above is my code and after the end of the text, there is some extra space are left. How to remove that space.
So you are giving paddingRight: 10px to the span, so at the end of the last child it's showing some space left.
There are two ways you can achive this
JS way
Css way
JS way
{options.map((opt,index) => (
<span style={{ paddingRight: options.length - 1 === index ? '10px' : "0px" }}>{opt}</span>)
)}
Css way
you need to change the inline style to explicit style for this, I would say this is the recommended way of giving css over inline style or may be you can create one style object for that.
<div className="parent">
{options.map(opt => (
<span style={{ paddingRight: '10px' }}>{opt}</span>)
)}
</div>
.parent{//parent css goes here}
.parent span:not(::last-of-type){padding-right: 10px}
const Btn = () => {
const options = ['test1', 'test2', 'test3'];
return (
<div style={{ position: 'absolute', left: '8px', widht: 'auto', flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', backgroundColor: '#006C84', display: 'flex', gap: '10px' }}>
{options.map(opt => (
<span>{opt}</span>)
)}
</div>
)
}
use display: flex and gap inside the parent div style
https://codesandbox.io/s/keen-ganguly-kl4ys7?file=/src/App.js
Using Material-UI, the width of the Masonry Component doesn't fill the width of the parent container. The width of this missing space is exactly the width of the spacing, which makes sense if there's an element next to it.
I tried to calculate the width of the masonry to be the width of the Box element plus 8 * spacing, but this breaks as soon as there is a scrollbar involved.
How can I use the full width of the container for Masonry?
mwe (just an example from the documentation with a Box added on top):
const heights = [150, 30, 90, 70, 110, 150, 130, 80, 50, 90, 100, 150, 30, 50, 80];
const Item = styled(Paper)(({ theme }) => ({
...theme.typography.body2,
color: theme.palette.text.secondary,
border: '1px solid black',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}));
<Container>
<Box style={{ border: '1px solid black', padding: '20px' }}>
<Typography variant="h5">
An Element to show the width of the contianer
</Typography>
</Box>
<Box style={{ marginTop: '20px' }}>
<Masonry columns={4} spacing={4}>
{heights.map((height, index) => (
<Item key={index} sx={{ height }}>
{index + 1}
</Item>
))}
</Masonry>
</Box>
</Container>
Screenshot of the MWE. Missing Area marked in red:
You can fix this by setting marginRight with the negation of your masonry spacing in the sx prop.
<Box sx={{ marginTop: '20px', marginRight: -4 }}>
{/* Masonry code */}
</Box>
I fix it simply by changing Masonry component width from "100%" to "auto",
I don't know why, but it works great.
<Masonry columns={4} spacing={4} sx={{ width: "auto" }}>
{* Masonry items *}
</Masonry>
Currently I am using ReactMapGL as my Map component. Here I'm using its HTMLOverlay feature to bring a full screen popup whenever I hover above a marker. I have currently set different image data for all my markers, but when I hover over the marker I only get the 1 same image for all of them. How do I get the marker to show its respective image?
I've added a codesandbox for better reference:
https://codesandbox.io/s/full-popup-mapbox-stackoverflow-forked-p8934?file=/src/App.js:1540-1551
Here's my code:
<ReactMapGL
{...viewport}
mapboxApiAccessToken={YOURMAPBOXTOKEN}
mapStyle="mapbox://styles/mapbox/dark-v9"
onViewportChange={(viewport) => {
setViewport(viewport);
}}
>
{posts &&
posts.map((item) => (
<HTMLOverlay
redraw={(props) => {
{
/* todo: grow animation from center */
}
return (
<div
style={{
backgroundColor: "rgba(255, 0, 0, 0.5)",
width: isPopupShown ? props.width : 0,
height: isPopupShown ? props.height : 0,
transition: "all .2s ease-in-out",
transform: "scale(1.1)",
overflow: "hidden",
alignItems: "center",
justifyContent: "center"
}}
>
{/* todo: text/content position */}
<img src={item.backgroundImage} alt="bg" />
</div>
);
}}
/>
))}
{posts &&
posts.map((item) => (
<Marker
key={item.id}
latitude={item.latitude}
longitude={item.longitude}
>
<button className="marker-btn">
<img
style={{
width: 48,
height: 48
}}
onMouseEnter={() => {
setSelectedProperty(item);
setIsPopupShown(true);
}}
onMouseOut={() => {
setSelectedProperty(null);
setIsPopupShown(false);
}}
alt="Marker"
/>
</button>
</Marker>
))}
</ReactMapGL>
You'd have to selectively render the HTMLOverlap for whatever pin is currently hovered over.
{selectedProperty && (
<HTMLOverlay
redraw={(props) => {
{
/* todo: grow animation from center */
}
return (
<div
style={{
width: isPopupShown ? props.width : 0,
height: isPopupShown ? props.height : 0,
transition: "all .2s ease-in-out",
transform: "scale(1.1)",
overflow: "hidden",
alignItems: "center",
justifyContent: "center",
backgroundImage: `url(${selectedProperty.backgroundImage})`,
backgroundSize: "cover",
backgroundRepeat: "no-repeat"
}}
>
{/* some text */}
</div>
);
}}
/>
)}
Here's a sandbox with working example.
Hy, I'm trying to disable/hide the arrow buttons of a horizontal scroller on start and end of the scroll.
I tried to use useEffect lifecycle by by setting its dependency document.getElementById('hscroll').scrollLeft, so that i can fire a function on scrollLeft change... but on load it shows an error "Cannot read property 'scrollLeft' of null" which is obviously right.
code is here ... hscroll CodeSandBox
how can I be able to do that?
need your help!
Thank you in advance <3.
You can do that only with useState hook and conditional rendering.
Here's a fully-working solution assuming we know width of the div that wraps your slides:
const HorizontalScroll = () => {
const [slideLeft, setSlideLeft] = useState(0);
const sliderWidth = 1900;
//on arrow click
const moveRight = () => {
const el = document.getElementById(`hscroll`);
setSlideLeft(el.scrollLeft += 200);
};
const moveLeft = () => {
const el = document.getElementById(`hscroll`);
setSlideLeft(el.scrollLeft -= 200);
};
return (
<div className="homepageMargin">
<section style={{ display: "flex", justifyContent: "space-between" }}>
{slideLeft > 0 ? <IconButton onClick={moveLeft}>
<ArrowBackIcon
style={{
paddingTop: ".2rem",
cursor: "pointer"
}}
/>
</IconButton> : <div />}
{slideLeft < sliderWidth ? <IconButton onClick={moveRight}>
<ArrowForwardIcon
style={{
paddingTop: ".2rem",
cursor: "pointer"
}}
/>
</IconButton> : <div />}
</section>
<hr style={{ backgroundColor: "black" }} />
<div class="flex-container" id={`hscroll`}>
{data.map((item) => (
<div style={{ minWidth: "300px" }}>
<img src={item.imgSrc} alt="images" style={{ width: "18rem" }} />
<h6>{item.title}</h6>
</div>
))}
</div>
</div>
);
};
Above example works becouse React component re-render every time you update the state. Also, you can get width of your slider like that:
const sliderWidth = yourRefName.current.style.width;
But it has to be declared explicitly in your CSS.