First, I apologize for not explaining well.
When I create multiple Accordion using mui(each AccordionDetails height are 80vh). How can I see the entire content of that selected Accordion?
Thank you.
I attached a screenshot for better understanding and code.
SOLUTION
I solved this one using useref and scrollIntoView.
import React, {useState} from 'react';
import Accordion from '#mui/material/Accordion';
import AccordionSummary from '#mui/material/AccordionSummary';
import AccordionDetails from '#mui/material/AccordionDetails';
import Typography from '#mui/material/Typography';
import ExpandMoreIcon from '#mui/icons-material/ExpandMore';
export default function Example() {
const [data, setData] = useState([
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
{name:"hello",desc:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget."},
])
return (
<div>
{data.map((data) => {
return(
<Accordion>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1a-content"
id="panel1a-header"
>
<Typography>{data.name}</Typography>
</AccordionSummary>
<AccordionDetails style={{height:"100vh"}}>
<Typography>
{data.desc}
</Typography>
</AccordionDetails>
</Accordion>
)
})}
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Related
Here's the thing, it all works fine if I run it with the npm run dev script, but images in testimonials.avatar don't render with npm run build.
const Testimonials = ({ testimonials }) => {
return (
<div id='testimonials' className='mt-20'>
<div className='text-center mb-8'>
<p className='text-xs uppercase mb-4 md:text-base'>Testimonials</p>
<h1 className='text-3xl md:text-5xl font-bold capitalize mb-10'>Read What Other<br />have to Say</h1>
</div>
<div className='flex flex-col gap-4 items-center md:flex-row'>
{testimonials.map(item =>
<div className='bg-light-gray rounded-3xl p-8 transition-transform duration-300 hover:-translate-y-2'>
<div className='w-32 h-32 mx-auto mb-4'>
<img src={item.avatar} alt="Person's avatar" className='rounded-full border' />
</div>
<p className='font-bold text-center'>{item.fullName}</p>
<p className='text-center mt-6'>{item.feedback}</p>
</div>
)}
</div>
</div>
)
}
Here I have a component which receives an array testimonials through props and then renders them in a div.
This is the array in App.jsx file.
const testimonials = [
{
avatar: '../src/images/avatars/avatar-1.png',
fullName: 'Andrew Rathore',
feedback: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel. '
},
{
avatar: '../src/images/avatars/avatar-2.png',
fullName: 'Vera Duncan',
feedback: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel. '
},
{
avatar: '../src/images/avatars/avatar-3.png',
fullName: 'Mark Smith',
feedback: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel. '
}
];
I guess I know that the main reason why it does not work while deploying is because of a non-existent path since I will no longer have src/images/avatar during a deploy.
I also guess this is a dumb question because I am quite new to React and JavaScript in general, but would appreciate any answer regarding the problem.
You have to wrap the avatar path in require() like require('../src/images/avatars/avatar-1.png') I hope this works. thanks
Fixed this by creating an external file and then fetching it to the component like so.
data.js
import avatar1 from '../public/images/avatars/avatar-1.png';
import avatar2 from '../public/images/avatars/avatar-2.png';
import avatar3 from '../public/images/avatars/avatar-3.png';
export const testimonials = [
{
authorImg: avatar1,
authorName: 'Andrew Rathore',
authorText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel.'
},
{
authorImg: avatar2,
authorName: 'Vera Duncan',
authorText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel.'
},
{
authorImg: avatar3,
authorName: 'Mark Smith',
authorText: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ullamcorper scelerisque mi, in malesuada felis malesuada vel.'
}
];
Testimonials.jsx
import React from 'react';
import { testimonials } from '../data/data';
const Testimonials = () => {
return (
<div className='flex flex-col gap-4 justify-between items-center md:flex-row'>
{testimonials.map((testimonial, index) =>
<div key={index} className='bg-light-gray rounded-3xl p-8 transition-transform duration-300 hover:-translate-y-2'>
<div className='w-32 h-32 mx-auto mb-4'>
<img src={testimonial.authorImg} alt="Person's avatar" className='rounded-full border' />
</div>
<p className='font-bold text-center'>{testimonial.authorName}</p>
<p className='text-center mt-6'>{testimonial.authorText}</p>
</div>
)}
</div>
)
}
export default Testimonials;
The main reason why it didn't work well in the first place was the fact that I specified path to the images in the object itself like so:
{
key: '../../../value.png'
}
That is why I ran into as error every time while deploying, 'cause it simply couldn't find that path due to its non-existence.
help me please, I display the html markup of 6 posts, the first click works correctly, the second click I display the same posts. how should I add six new posts, and so every time I click?
I don't know what can be used instead of the slice method. demo https://jsfiddle.net/u9zc7p5v/13/
const content = mrd.map(function(data, elem) {
return `
<div class="blog__item">
<h2 class="blog__item-title">
${data.title}
</h2>
<input type="checkbox" class="read-more-state" id="post-${elem}" />
<p class="blog__item-text">
${data.body} <span class="blog__item-more">Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem itaque ducimus unde harum vitae quam provident. Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta sapiente odit laborum tempore sed quaerat a aliquam? Corrupti dolorum, tempora iste qui modi consectetur explicabo quia vel reiciendis nesciunt? Id!</span>
</p>
<label for="post-${elem}" class="blog__item-toggle" >Read More</label>
<div>${elem}</div>
</div>
`
}).slice(startNum, endNum).join('');
Increase the startNum value startNum+=6. then in slice function do startNum + endNum.
$(function(){
const blogs = document.querySelector('.blog__items')
const moreBtn = document.querySelector('.blog-btn')
let startNum = 0;
let endNum = 6;
async function getContent() {
let responce = await fetch('https://jsonplaceholder.typicode.com/posts');
let data = await responce.json();
return data;
}
$(moreBtn).on('click', async function(e) {
let mrd = await getContent();
console.log(mrd.length)
const content = mrd.map(function(data, elem) {
return `
<div class="blog__item">
<h2 class="blog__item-title">
${data.title}
</h2>
<p class="blog__item-text">
${data.body} <span class="blog__item-more">Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem itaque ducimus unde harum vitae quam provident. Lorem ipsum dolor sit amet consectetur adipisicing elit. Dicta sapiente odit laborum tempore sed quaerat a aliquam? Corrupti dolorum, tempora iste qui modi consectetur explicabo quia vel reiciendis nesciunt? Id!</span>
</p>
<label class="blog__item-toggle" >Read More</label>
<div>${elem}</div>
</div>
`
}).slice(startNum, startNum+endNum).join('');
console.log(startNum)
const el = $(content);
$(blogs).append(el)
el.on('click', function() {
});
startNum+= 6
});
});
I'm using ExpansionPanel with TransitionComponent property, when I set default value (Collapse) expansion panel is working fine, but if value is another (Fade, Grow and others), collapsed component has same height as expanded
<ExpansionPanel
expanded={expanded === '1'}
onChange={handleChange('1')}
TransitionComponent={Slide}
TransitionProps={{ mountOnEnter: true }}
className={classnames('accordion-item', expanded === '1' && 'selected')}
>
UPD: there is a snippet https://codesandbox.io/s/vigorous-tree-621cz?fontsize=14&hidenavigation=1&theme=dark
There are two aspects needed to get the Slide transition working appropriately.
In order for the height to adjust appropriately you need to specify both mountOnEnter and unmountOnExit in the TransitionProps.
The other aspect to deal with is the timeout prop. Accordion (previously ExpansionPanel) specifies the timeout as "auto", but "auto" is only supported as a timeout value by Collapse so you need to specify a valid timeout for Slide. In my modified version of your sandbox, I'm using the default values for Slide of 225 for enter and 195 for exit.
Here's a working example:
import React, { useState } from "react";
import {
Accordion,
AccordionSummary,
AccordionDetails,
Slide
} from "#material-ui/core/";
const slideProps = {
mountOnEnter: true,
unmountOnExit: true,
timeout: { enter: 225, exit: 195 }
};
export default function App() {
const [expanded, setExpanded] = useState(null);
return (
<>
<Accordion
TransitionComponent={Slide}
TransitionProps={slideProps}
expanded={expanded === "1"}
onChange={() => setExpanded("1")}
>
<AccordionSummary aria-controls="panel1d-content" id="panel1d-header">
First
</AccordionSummary>
<AccordionDetails>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada
lacus ex, sit amet blandit leo lobortis eget.
</AccordionDetails>
</Accordion>
<Accordion
TransitionComponent={Slide}
TransitionProps={slideProps}
expanded={expanded === "2"}
onChange={() => setExpanded("2")}
>
<AccordionSummary aria-controls="panel1d-content" id="panel1d-header">
Second
</AccordionSummary>
<AccordionDetails>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse
malesuada lacus ex, sit amet blandit leo lobortis eget. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada
lacus ex, sit amet blandit leo lobortis eget.
</AccordionDetails>
</Accordion>
</>
);
}
Is is possible to include a React component call within a block of text and then get React to execute the component?
For example, let's say I had:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id libero rutrum, volutpat nisi non, tempus ipsum. <InsertStuff props={props} /> Vestibulum vel sapien lacus. Pellentesque tristique erat a purus tempus, vitae vulputate nulla consequat
I'd like React to see <InsertStuff props={props} /> and execute the component so that I get:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In id libero rutrum, volutpat nisi non, tempus ipsum. HERE'S THE STUFF GENERATED BY THE COMPONENT Vestibulum vel sapien lacus. Pellentesque tristique erat a purus tempus, vitae vulputate nulla consequat
Can this be done?
It can be done - in your render() method (or in the return value if using a functional component) you need to guarantee that there is a top level tag, even if it renders nothing (e.g. <></> or <React.Fragment></React.Fragment>)
More info
JSX in Depth
React Fragments
Live example that does not add any new tags (div/span/etc) to the DOM - will print:
<div id="root">Inline text before a component with props: {"randomProp":"value"} and some text after</div>
const Component = (props) => (
<React.Fragment>
a component with props: {JSON.stringify(props)}
</React.Fragment>
);
ReactDOM.render(
<React.Fragment>
Inline text before <Component randomProp="value"/> and some text after
</React.Fragment>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" />
I have used bootstrap plugin to collapse and expand the <div>s. I am able to do it for individual <div>'s but if i leave one <div> expanded and do a collapseAll(), the expanded <div> only getting collapsed. Please provide me a solution on this
html:
<body ng-controller="MainCtrl">
<div class="panel panel-default" ng-repeat="item in items">
<div class="panel-heading" ng-click="isCollapsed = !isCollapsed">{{item.title}}</div>
<div class="panel-body" collapse="isCollapsed">{{item.content}}</div>
</div>
<div>
<input type="checkbox" id="collapse_all_cards" ng-model="isCollapsed"><label for="collapse_all_cards">Collapse All</label>
</div>
</body>
js:
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.items = [{'title':'Item1','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu'},
{'title':'Item2','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu'},
{'title':'Item3','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu'}
]
});
link: http://plnkr.co/edit/mcnqeLJcTyaAuTI9JHb9
Please see this Plunk
Pretty sure this is the behavour you are after :)
The problem before was that the same "isCollapsed" property on scope was being used for the "collapse all" and the individual collapses so they were tripping each other up.
See the new controller code which has an individual boolean "isCollapsed" property for each item in the collection:
{'title':'Item1','content':'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus maximus orci sodales, pellentesque urna eu', isCollapsed: true}
If you need any refinements to the code just ask :)