extend Mantine Accordion Item - javascript

Mantine accordion specifies that its content should be only of type Accordion.Item (or, AccordionItem) - see the documentation for the children props. This means that even functions that actually return AccordionItem will not be listed.
So, this simple component will display only AccordionItem(s) that were instantiated inline, yet, not one returned from another function (see MyAccordionItem in this simple app).
The code:
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Accordion } from '#mantine/core';
const MyAccordionItem = ({children, label}) =>
<Accordion.Item label={label}>
{children}
</Accordion.Item>;
function App() {
return (
<div style={{width: 200}}>
<div>pre</div>
<Accordion>
<Accordion.Item label="section0">
<div>sec0.item1</div>
<div>sec0.item2</div>
<div>sec0.item3</div>
</Accordion.Item>
{/* Section 1 is not displayed because it is no of type Accordion.Item
<MyAccordionItem label="section 1">
<div>sec1.item1</div>
<div>sec1.item2</div>
<div>sec1.item3</div>
</MyAccordionItem>
<Accordion.Item label="section2">
<div>sec2.item1</div>
<div>sec2.item2</div>
<div>sec2.item3</div>
</Accordion.Item>
</Accordion>
<div>post</div>
</div>
);
}
render(<App />, document.getElementById('root'));
The reason is the filter function defined here, and used by the accordion here.
My questions are:
Do you know of any work around that helps assigning the same type (or, appearing to be an Accordion.Item when defining your own component?
On a larger scale, What do you think is the right approach from the library's perspective (in this case mantine), i.e. should it suffice in checking that the returned type is An accordion item?

I came across this same issue and found this GitHub issue in the Mantine repository with more information about creating child components that return AccordionItems.
rtivital (Mantine's creator) states:
Yes, currently that is not supported, it will require breaking changes, so Accordion and other similar components will be Migrated to context with next major release (5.0)
As to a work around, I haven't found anything yet other than creating a custom component for the content inside the AccordionItem and then wrapping that with the Mantine AccordionItem component inline via mapping or explicitly listing them.

Related

How to send a usestate through props with interface in TypeScrips and react?

I'm trying to make a light / dark theme . And I have 2 components.
The first component is the one below. I succeeded to make a boolean to change my style in my component. It was good so far :
export interface Props{
theme:boolean;
}
const Theme: FC<Props> = ({theme}) => {
const [light,setLightMode]=useState(false);
return (
<div>
<div className="card__theme">
<div className={light ? "card__light" : "card__light--active"}>Light</div>
<Switch inputProps={{ "aria-label": "controlled" }} onChange={()=>setLightMode(!light)}/>
<div className={ light ? "card__Dark" : "card__Dark--active"}>Dark</div>
</div>
</div>
);
};
What I do right now is to use this component in my Home page where I want to do the same thing.
I want to change the style of my components , making 2 className like the code above with a boolean state.
The problem that I'm facing is that I can't make another function onChange={} in my home component. First I don't send in interface a function . I want my const [light,setLightMode]=useState(false); and my function onChange={()=>setLightMode(!light)} when I switch the button to work in my Home component from below
const Home: FC = () => {
const percentage = 91;
const [dark,setDark] = useState(false);
return (
<div>2
<div className="Container-body">
<div className="card">
<div className={dark ? "card__theme" : "card__theme--active"}>
<Theme theme={dark} onChange={()=>{setDark(!dark)}}/>
</div>
So to make it sort. I want to use just the light, setlightTheme boolean state from my Theme component in my Home component . I don't know how I can send this with props in TypeScript...
Here is a print with my code : enter link description here
I'm not sure if I understand correctly, but I think your goal is to pass the onChange function to the Theme component from the parent component.
If so, I hope this snippet can help you. Basically I added the onChange parameter in the interface as a function. I also renamed the theme parameter to dark.
To make the two components work together, I removed the useState in the Theme component and used the dark variable (taken from the parent component) to manage the styles.
export interface Props {
dark: boolean;
onChange?: () => void;
}
const Theme: FC<Props> = ({ dark, onChange }) => {
return (
<div>
<div className="card__theme">
<div className={dark ? 'card__light' : 'card__light--active'}>
Light
</div>
<Switch
inputProps={{ 'aria-label': 'controlled' }}
onChange={onChange}
/>
<div className={!dark ? 'card__Dark' : 'card__Dark--active'}>Dark</div>
</div>
</div>
);
};
So if I understand correctly you just want to provide an option for switching light and dark mode. From an architectural point of view you don't want to do this on a component-level since multiple component might need to change.
BEM Mistake
Before I address a proper solution you are currently making a BEM mistake with this line:
<div className={dark ? 'card__light' : 'card__light--active'}>
A modifier --modifier can only live together with an actual element card. So on a fully outputted HTML this is valid card__light card__light--active but in your example either card__light or card__light--active is being rendered.
Solution for theme switching
When it comes down to switching a dark/light theme you either want to make this value (true or false) available in a centralised state by using something like Redux or you might want to declare it on your root component (most often the <App />) and start using it from there.
I don't recommend prop drilling for this use case since it will make your code messy in the long run. This is a really nice use case for the Context API.
✅ See working example Playground.
P.s. I use Typescript for better code, you can ignore the syntax you don't know.
React documentation
The React documentation has an exact example for you see docs theme switching.

How to create an Style Object to bind with react component?

Here I created a sample example. As you can see I add applyColor Style object to apply styles.
import React from 'react'
const applyColor = {
color: 'red'
}
export const App = () => {
const renderData = () => {
return (
<>
<section style={applyColor}>
<p>Paragraph</p>
<div>
<h2>Heading</h2>
<span>Span</span>
</div>
</section>
</>
)
}
return <>
{renderData()}
</>
}
How can I modify applyColor Object to access the child from parent element <section />?
And I dont want to use any third party like styled-components and material-ui/styles.
Thanks:)
In short, no way unless you do it directly to the child.
<div style={{ color: red }} />
That's what the style is made for. However, everything is coded as Javascript code, so you can do it manually via props.
return <Child color="red" />
const Child = ({ color }) => {
return <div style={{ color }} />
}
Every big UI system has their unique way of handling this, ex. Material and etc.
But trusted me, unless you are making small css changes, styled-components like Css-in-Js approach isn't avoidable. Because passing the flag from Parent to Child is just too much work to manage by your own, not difficult but tedious. This is just my two cents.
Or you can use a traditional CSS approach, just put everything through CSS class. This way you can just include one copy of css. But the problem of that approach is that you can't pass a flag into the CSS so in the end you come back to the same boat above :)

React Props Is Creating A Empty Div

So This is the code I am learning from a tutorial and it works but it creates a empty div container I think this is because when I created the props from react I think the h1 and p elements were empty so I think thats why this makes a empty div. Does any one know how to slove this
import React from 'react'
function Note(props) {
return (
<div className="note">
<h1>{props.title}</h1>
<p>{props.content}</p>
</div>
)
}
export default Note

Lifting State Up or how to get the value in another component without import

I have a lot of components I need to get a value called "values" from the SideBarBlurChange component to the SideBar component. I drew a diagram of my components so you can navigate easier
I read articles and how I understood there are two main options, the first is "Lifting State Up" and the second is "Redux" or "Context". I tried to apply these approaches but I failed.
The main problem is that inside the SideBarBlurChange component, I cannot import anything, since my entire project is collapsing. In addition to all this, I will leave a link to this project in the github if you want to see GitHub Project
Now I want to explain my problem in more detail.
Please pay attention to the changing number I showed with the mouse this number and there is a value with the name "values". I need to apply this value to the SideBar component to adjust the blur of the Sidebar.
And finally, before I demonstrate my code, I imported the SideBar inside the SideBarBlurChange, took out a value called "values" and applied it to the SideBar component like this <div style = {{backdropFilter: blur(${props.values}px)}}...
Now look my project has collapsed, I mean that there is a catastrophe for my components, but I got "values" and everything works for me.
Now I think that the problem is understandable, in order not to confuse you, I will show you three SideBar components, SideBarBlurChange and DraggableDialog where I imported SideBarBlurChange, + delete all personal code and show only the most important thing, but if you need to look at all the other components, I will remind you that I left a link to project in github, or as a last resort, tell me I will edit my question and show what you need in advance. I want to thank you for taking the time to solve my problem
SideBar.jsx
export default function SideBar(props) {
return (
<div style={{backdropFilter: "blur(60px)"}}>
// jsx code
</div>
);
}
SideBarBlurChange.jsx
const MIN = 0;
const MAX = 100;
export default function SideBarBlurChange(props) {
const ls = parseInt(window.localStorage.getItem('values'));
const [values, SetValues] = useState(ls ? [ls] : [20]);
const SaveChanges = () => {
localStorage.setItem('values', values);
}
return (
<>
<div>
<Range
// code
/>
<output style={{ marginTop: "30px" }} id="output">
{values[0].toFixed(1)}
</output>
<button onClick={() => SaveChanges()}>Save</button>
</div>
</>
);
}
DraggableDialog.jsx
const DraggableDialog = (props) => {
return (
<>
<div>
<SideBarBlurChange {...props}/>
</div>
</>
);
};
export default DraggableDialog;
I removed a lot of code from these three components, I left only the most important. Sorry in advance, I don't know English, I wrote it all with the help of translate

React Bootstrap custom checkbox without id?

I'm having a hard time understanding why this simple Bootstrap custom checkbox doesn't work. I'm using React, Bootstrap, and React-Boostrap.
import React from "react";
import ReactDOM from "react-dom";
import { Button, Form, FormCheck } from "react-bootstrap";
import "bootstrap/dist/css/bootstrap.min.css";
function App() {
return (
<div className="p-3">
<FormCheck custom label="Checkbox">
</FormCheck>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Online Example
Adding id="test" to FormCheck seems to cause the checkbox to work, but is is possible to not have to use id? (The checkbox is used within the component of an object in my actual code, and it would be unnecessarily complicated to come up with a unique id for every checkbox)
Try this:
<FormCheck>
<FormCheck.Label>Allow us to contact you?
<FormCheck.Input isInvalid type={radio} />
</FormCheck.Label>
<Feedback type="invalid">Yo this is required</Feedback>
</FormCheck>
The basic idea is that you need to change the way it's rendered.
By default it has label and input on the same level, meaning that you have to bind them using id and for. And you want to put input inside of the label to bind it without id.
You might need some custom css as mentioned in this answer: https://stackoverflow.com/a/57901478/4536543
If you do want to use the React Bootstrap components you will have to use an ID to use the FormCheck component. This is as within the FormCheck component the ID is used to call useContext() so that the component can access the element through the DOM.
Source Code:
/** A HTML id attribute, necessary for proper form accessibility. */
id: PropTypes.string,
const { controlId } = useContext(FormContext);
const innerFormContext = useMemo(
() => ({
controlId: id || controlId,
custom,
}),
[controlId, custom, id],
);
Source
Ended up finding the solution here (Normal bootstrap 4)
<FormCheck custom>
<FormCheck.Label>
<FormCheck.Input type="checkbox" name="checkbox-name" />
<div className="custom-control-label"></div>
</FormCheck.Label>
</FormCheck>
It involves a bit of a work around, nesting labels with checkboxes. Bootstrap 4 custom buttons seem to have strange behaviour

Categories