Styled Component prop inside a map - css

I'm trying to calculate the svg width based on a prop value.
It's an array of svg and each one should have a specific width.
It is perfectly calculating the width value but it's repeating the first value of the map for all others.
When I console.log the value inside the map it shows different values for each one.
Here's the map:
{example.map(v => (
<ComponentExample value={v.value} />
))}
Here's the styled component receiving prop:
const ComponentExample = styled(ExampleSVG)<{ value: number; }>`
width: ${props => (props.value * 100) / 5}%;`;

Related

Composition API: strange behavior of a computed property

I am using a computed property (in Vue 3 with the composition API) and binding it to an img src attribute.
const arrowUrl = computed(() =>
width.value > thresholds.value.xl
? '/img/elements/arrow.svg'
: '/img/elements/arrow_small.svg'
);
<img :src="arrowUrl"></img>
When I inspect the first call of the computed property (on load with a breakpoint):
The /img/elements/arrow_small.svg is already displayed.
It returns /img/elements/arrow.svg but it won't display it.
I changed the width of the frame lower than the thresholds.value.xl and then I changed it back to the initial width and the right img src (/img/elements/arrow.svg) is displayed.
I don't understand why the arrow_small.svg is displayed before the first call of the computed property and why when I change the width of the frame it works.
What am I missing?

Autoheight in MUI DataGrid

I'm using the MUI DataGrid component, and the behavior I hope to have is that:
When there's a small number of rows, the table is only the size it needs to for those rows.
When there's a large number of rows, more than the current viewport can hold (given whatever else is on the screen), the table takes up the available space in the layout (given its flex: 1) and the extra rows scroll inside the table.
I can achieve each of these behaviors, but only one at a time.
If I use the autoHeight property on the DataGrid, then the table will be as small as it can be. BUT it will also be as big as it can be, so with a large number of rows the container scrolls the entire table, rather than the rows scrolling within the table.
If I don't use autoHeight, and wrap the DataGrid in a container with flex: 1, then the table will grow to fill the available space and the rows will scroll within the table. BUT a table with only a few rows will also grow to fill its container, so that there is empty space under the rows (above the footer, "Table rows: #")
You can see the situation in this screenshot, showing the exact same page, with different data.
I've tried what feels like every permutation of heights and flexes under the sun. For example:
Setting autoHeight with a maxHeight (and .MuiDataGrid-main { overflow: scroll; } ) allows few-rows to be small, and many-rows to be not too small, but obviously any discrete maxHeight, be it px or %, is not the flexible layout I'm going for.
Turning off autoHeight (as in scenario #2) and setting flex-grow: 0 on the rows container within the table (.MuiDataGrid-main) just makes the rows disappear since they then shrink to a height of 0.
The code for the component:
const S = {
Wrapper: styled.div`
width: 100%;
display: flex;
flex: 1;
background: white;
border: solid thick red;
`,
DataGrid: styled(DataGridPro)`
&& {
.MuiDataGrid-main {
//overflow: scroll;
//flex-grow: 0;
}
background: lightgreen;
font-size: 14px;
}
`,
};
type Props = {
columns: ReadonlyColumns;
rows: AnyObject[];
filterModel?: GridFilterModel;
} & Omit<DataGridProps, 'columns'>;
const DataTable: React.FC<Props> = ({
columns = [],
rows = [],
filterModel,
className,
...props
}) => {
const memoizedColumns = useMemo(
() =>
columns.map(col => ({
headerClassName: 'columnHeader',
flex: 1, // all columns expand to fill width
...col, // but could override that behavior
})),
[columns],
);
return (
<S.Wrapper className={className}>
<S.DataGrid
// autoHeight
rows={rows}
columns={memoizedColumns}
filterModel={filterModel}
{...props}
/>
</S.Wrapper>
);
};
Using a combination of autoHeight and pageSize will create a table whose height is only as big as needed for the current number of rows as long as the number of rows is <= pageSize. Additional rows will be added to a new page.
<DataGrid
rows={rows}
columns={columns}
pageSize={20} //integer value representing max number of rows
autoHeight={true}
/>
Below solved the issue:
<DataGrid getRowHeight={() => 'auto'} />
Source:
https://mui.com/x/react-data-grid/row-height/#dynamic-row-height
I had a similar issue days ago and I solved recalculating the row height every time a new item was added to my row.
getRowHeight={(props: GridRowHeightParams) => {
const serviceRowHeight = 45 // <-- default height, if I have no data for the row
const addServiceBtnHeight = 45 // <-- a component that's always on the row
const height = props.model?.services // services is each dynamic item for my row, so you should access like props.yourObj
? props.model.services.length * serviceRowHeight + addServiceBtnHeight
: 115
return height < 115 ? 115 : height // final height to be returned
}}

Material-UI text field with dynamic rows

I'm trying to have a multiline TextField component that takes all available space depending on a device.
I know fullWidth but is there a way to have something like fullHeight in rows setting, depending on a device that it is displayed on?
You basically want your TextField element to take full height and width of the container.
For width you can simply add fullWidth prop to your TextField element,
<TextField fullwidth/>
For adding required height,
If you have prop Multiline={true} in your TextField element, Material Ui sets numbers of rows dynamically and height is adjusted according to number of row (everytime user hits enter new row is generated), due to this you can not set specific height.
Now to be able to set height manually, you must add prop rows={1}*
<Textfield multiline rows={1} fullwidth />
Now, you should be able to set height with JSS,
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles(() => ({
inputMultiline : {
"& .MuiInputBase-input" : {
height : '100vh', //here add height of your container
},
}
}));
Now simply add this to className of your TextField element,
<TextField multiline fullWidth row={1} className={classes.inputMultiline} />
For any doubt refer to,
material ui TextField API here and
material ui styles API here.
(although, no proper information regarding this is available in docs)
A solution is to manupulate Material-UI classes using JSS.
I change the height of the input base and align the text at start vertically.
const useStyles = makeStyles(() => ({
input: {
height: "100%",
"& .MuiInputBase-root": {
height: "100%",
display: "flex",
alignItems: "start"
}
}
}));
Add the input classes to your input and it's work.
All the exemple bellow on this codesandbox.

How do I set the width of a component in my React web-app based off the output of a variable

I have a component which I'm attempting to set the width of based off the result of a variable.
The variable returns a number between 1 and 100, and as such I want to set the width to reflect the result of the variable.
However, despite being able to render the result within the component, I can't set the width. This is the first time I've tried to conditionally render the width of a React component before, so figure I'm doing something obvious wrong.
Here's the render function in question:
const fetchLoans = this.state.debts.map(debt => {
const loanBalance = debt.balance
const loanBorrowed = debt.borrowed
const loanSum = Math.round(loanBalance / loanBorrowed * 100)
return (<div className="individual-loan-amount-outstanding" key={debt._id}>
<div className="individual-loan-amount-bar">
<div className="individual-loan-amount-indicator" style={{ width: {loanSum} }}>{loanSum}%</div>
</div>
</div>
)
})
As you can hopefully see, I'm attempting to set the 'width' based off the result of 'loanSum'.
I can render 'loanSum' in the div, but not with the width.
Can anyone point out where I'm going wrong?
Thanks!
You shouldn't put the curly brackets around loanSum, so your line should be:
<div className="individual-loan-amount-indicator" style={{ width: loanSum }}>{loanSum}%</div>

Using react-Beautiful-dnd, how can you change draggable dimensions before the drag begins (onBeforeCapture)

This is the code I've found to retrieve the correct draggable element and edit it's dimensions, during the onBeforeCapture() responder. Changing dimensions during this responder is in accordance with the documentation. This seems to work in only changing the dimensions, the other problems is that I am using the renderClone method, and so the draggable is just dragging with a huge offset that is not close to the correct mouse position. Also dnd is treating the drop placeholder as if the draggable is the original large size. Is there any way to correct for this mouse position, and placeholder dimensions? I've looked into adding mouseDown/mouseUp handlers on the inner element of the draggable but that doesn't seem to work either.
const cardSize = 140;
const draggableAttr = "data-rbd-drag-handle-draggable-id";
const getAttr = (key: string, value: string) => `[${key}=${value}]`;
const draggableQuery = getAttr(draggableAttr, update.draggableId);
const draggable = document.querySelector(draggableQuery);
draggable.setAttribute("style", `width: ${cardSize}px; height: ${cardSize}px;`);
I noticed onBeforeCapture was triggering after onDragEnd (therefore resizing the draggable improperly), so I created some state to remember the last beforeCaptureResult and return if it is equivalent to the current result.

Resources