Custom React-Bootstrap Popover - reactjs

I want to create a custom react popover, based on Bootstrap Popover, just with my own design and maybe more props.
I created a new react component called MyTooltip :
import React, {Component} from 'react';
import { Popover } from 'react-bootstrap';
export default class MyPopover extends Component{
constructor(props){
super(props);
}
render() {
return (
<Popover id="popover-trigger-focus" title={this.props.title}>
{ return this.props.children }
</Popover>
);
}
}
and in my main component I tried to create a trigger:
export default class MyMainComponent extends Component{
render() {
const popoverFocus = (
<MyPopover id="tooltip-trigger-focus" title="My Title">
my text <b>my bold text</b> my text
</MyPopover >
);
return (
<div >
<OverlayTrigger trigger="focus" placement="bottom" overlay={popoverFocus}>
<Button>Focus</Button>
</OverlayTrigger>
</div>
);
}
}
But it doesn't work. The button does hide and show the popover with the right text, but the popover ignores the "placement" property and it doesn't have the fade animation.
Any help will be useful...

You've set the placement and overlay prop to the <OverlayTrigger/> element, but those belong on the Popover. You can quickly fix this by letting the popover inherit the props from the trigger element like so:
render() {
return (
<Popover id="popover-trigger-focus" title={this.props.title} {...this.props}>
{ this.props.children }
</Popover>
);
}
Here's your example with {...this.props}.
PS: You don't need to return JS in JSX (e.g. { return this.props.children }). You can just leave that out ({ this.props.children }).

Related

Why does react display my functional component at the bottom of my page?

My main page looks like this :
import React from "react";
import { Fragment } from "react";
import ModalA from "../components/Modal/ModalOptionA";
export default class AePage extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Fragment>
<div className="grid-intro">
<div className="text-intro">
Some Text
</div>
<div className="modal-component-insert">
<ModalA show={true}/>
</div>
<div className="text-outro">
Some text
</div>
</div>
</Fragment>
)
}
}
And my component looks like this :
import React from "react";
import ReactDOM from "react-dom";
const Modal = ({ show, closed}) => {
return (
ReactDOM.createPortal(
<>
<div className="modal">
My Component
</div>
</>,
document.body
)
)
}
export default Modal;
The code above display something like :
Some Text
Some Text
My Component
Why does my component not display between the texts ? Is there a specific way for React to display this component between my divs ?
That is what ReactDOM.createPortal is for. It will always move things to the bottom of the DOM. That way, you can then position it above everything else using CSS.
It seems you don't really need that, so I'd just replace your code for the Modal component with:
import React from "react";
const Modal = ({ show, closed}) => {
return (
<div className="modal">
My Component
</div>
)
}
export default Modal;

Why I can't use an imported component inside a functional component in React?

I am new to React. For the code readability, instead of in-line styled button, I want to write it as a separate class component. I created a customed button 'addImageButton'and imported it to another .js file. It doesn't render the customer button when I try to use it within a functional component. How can I make the functional component be able to use the imported button? Thanks!
//addImageButton.js
import React, { Component } from "react";
class addImageButton extends Component {
render() {
return (
<div>
<button
style={{
borderStyle: "dotted",
borderRadius: 1,
}}
>
<span>Add Image</span>
<span>Optional</span>
</button>
</div>
);
}
}
export default addImageButton;
//AddNewTaskButton.js
import React, { Component } from "react";
import Modal from "react-modal";
**import addImageButton from "../addImageButton";**
class AddNewTaskButton extends Component {
constructor(props) {
super(props);
this.state = {
show: false,
};
this.setShow = this.setShow.bind(this);
this.closeShow = this.closeShow.bind(this);
this.addTaskModal = this.addTaskModal.bind(this);
}
setShow() {
this.setState({
show: true,
});
}
closeShow() {
this.setState({
show: false,
});
}
addTaskModal = () => {
return (
<div>
<Modal
isOpen={this.state.show}
onRequestClose={() => this.closeShow()}
>
**<addImageButton />**
</Modal>
</div>
);
};
render() {
return (
<div>
<button onClick={() => this.setShow()}>
<img src={addIcon} alt={text}></img>;
<span>text</span>
</button>
<this.addTaskModal className="modal" />
</div>
);
}
}
export default AddNewTaskButton;
Easier way would be to just use functional components. Also, react components should be upper case, like so:
export default function AddImageButton() {
return (
<div>...</div>
)
}
create a different component for Modal
import Modal from './Modal'
import AddImageButton from './AddImageButton'
function AddTaskModal() {
return (
<div>
<Modal> <AddImageButton/> </Modal>
</div>
)
}
then
import AddTaskModal from './AddTaskModal'
function AddNewTaskButton() {
return (
<div>
<AddTaskModal/>
</div>
)
}
I don't know your file directories, so I just put randomly.
as for your question, try to make the AddImageButton as a class and see if it renders then. If it doesn't it might be due to something else. Do you get errors? Also maybe create the AddTaskModal class separately and render it out as a component. Maybe that'll help

How to apply MathJax/KaTex to render a React component

I am making a web editor using React & SlateJS. There are LaTex code in the editor content and I want the user to see the rendered LaTex equations. MathJax and KaTex have auto-rendering feature by loading them as CDNs. Once they are loaded, the content on html body is rendered. But they are not live-rendering when I modify the content.
So I have made a button that opens a modal which renders the un-editable edior content in a smaller window, and I want the LaTex codes to be rendered in the modal.
The APP component:
import {Editor} from 'slate-react';
import ReactModel from 'react-modal';
import RenderedEditorDialog from "./RenderedEditorDialog";
class APP extends React.component {
...
render() {
return (
<div className={"editorContainer"}>
<div className={"editor"}>
<Editor
autoFocus
ref={this.ref}
value={this.state.value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
renderMark={this.renderMarks}
renderBlock={this.renderBlock}
/>
</div>
<ReactModal
isOpen={this.state.showMathDialog}
contentLabel="Rendered content"
onRequestClose={this.handleCloseMathDialog}
>
<button onClick={this.handleCloseMathDialog}>Close Dialog</button>
<RenderedEditorDialog value={this.state.value}/>
</ReactModal>
</div>
)
}
}
RenderedEditorDialog (modal) component:
import {Editor} from 'slate-react';
class RenderedEditorDialog extends React.Component {
// eslint-disable-next-line no-useless-constructor
constructor(props) {
super(props);
}
render() {
return (
<div>
<Editor
value={this.props.value}
renderMark={this.renderMarks}
renderBlock={this.renderBlock}/>
</div>
)
}
}
My question is how I can apply MathJax/KaTex to render the content in RenderedEditorDialog component?
Thanks in advance!
KaTeX can be applied to individual DOM elements on demand, instead of all at once, by calling renderMathInElement when desired. Calling this from componentDidUpdate should do the trick:
import {Editor} from 'slate-react';
class RenderedEditorDialog extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
}
render() {
return (
<div ref={this.ref}>
<Editor
value={this.props.value}
renderMark={this.renderMarks}
renderBlock={this.renderBlock}/>
</div>
)
}
componentDidUpdate() {
renderMathInElement(this.ref.current, katexOptions);
}
}
I'm more comfortable with hook-based components instead of classes, which would look like this:
function RenderedEditorDialog(props) {
const ref = useRef();
useEffect(() => {
renderMathInElement(ref.current, katexOptions);
});
return (
<div ref={ref}>
<Editor
value={props.value}
renderMark={props.renderMarks}
renderBlock={props.renderBlock}/>
</div>
)
};
I'm not sure whether you want this on RenderedEditorDialog or another more specific component, but this should give you the idea. For speed, you want to apply renderMathInElement to the smallest container that contains the updated math.

Clicking the button does not work - React

I use a component called "Modal" that I want to make global so I can use it in any other component. Modal will be used in all the components that need it.
My problem is that now the onclick {this.props.stateModal} in Widgets does not work and show nothing.
This is my Widgets.js
class Widgets extends Component {
render(){
return (
<aside className="widgets">
<div id="bq-datos">
<span>Todas tus campañas</span>
<a onClick={this.props.stateModal} className="content-datos orange" data-bq-datos="999"><div>Llamadas <span>ENTRANTES</span></div></a>
<a className="content-datos violet" data-bq-datos="854"><div>Llamadas <span>SALIENTES</span></div></a>
</div>
{
this.props.isModalOpen
? (
<Modal
stateModal = {this.props.stateModal}
isModalOpen={this.props.isModalOpen} >
<ModalWidgets/>
</Modal>
)
: null
}
<Comunicacion/>
</aside>
);
}
}
I need {this.props.stateModal} to work on my Modal component (in Modal.js)
This is my Modal.js with code for {this.props.stateModal} but not works.
import React, { Component } from 'react';
class Modal extends Component {
constructor(props) {
super(props);
this.state = {
isModalOpen: false,
};
this.stateModal = this.stateModal.bind(this);
}
stateModal() {
this.setState({
isModalOpen: !this.state.isModalOpen
});
alert('¡Ohhhh');
}
render(){
if(this.props.isOpen){
return (
<div id="modal">
{this.props.children}
<ModalWidgets/>
</div>
);
} else {
return null;
}
}
}
class ModalWidgets extends Component {
render(){
if(this.props.isModalOpen){
return(
<article id="md-descansos" className="medium">
hola tú!!
</article>
);
}
else{
return(
<div>k pasa!</div>
);
}
}
}
export default Modal;
I think that i need do something in my Modal.js but i don't know what it is
Edit:
I have changed the components to use Modal as the parent of all the other Modal that I want to use, such as ModalWidgets. But now when you click on the button of {this.props.stateModal} in Widgts not works.
Thanks!
You have to use stateModal function somewhere in your Modal component. Something like:
render(){
if(this.props.isOpen){
return (
<ModalGenerico>
<div id="modal">
<button type="button" onClick={this.stateModal}>Click here</button>
{this.props.children}
</div>
</ModalGenerico>
);
} else {
return <ModalGenerico />;
}
}
The button in the example above should be replaced with your backdrop of the modal (or anything else as you like).
Edited: You should take a look at this article State vs Props. Because I notice that you weren't clear the usage of them.
Besides, I don't think there's such thing called global component as you described. Every components in react are reusable and can be imported anywhere in the project.

Clarification on React components declared as static property within Parent component

I'm pretty new in React world, and I'm trying to create a dialog box component with some help from react bootstrap modal.
Here's the way I have components built.
Parent (Messages Component)- Messages.tsx
<DialogBox modalOpen={this.state.modalOpen} onCloseModal={() => this.onCloseModal()} title="Retry">
<DialogBox.Body>
<p>You have selected the messages to be retried. This action will cause the messages to be put back on to the original queues.</p>
<p>Do you want to proceed?</p>
</DialogBox.Body>
<DialogBox.Footer>
<div className='col-sm-2 button button-action button-primary' onClick={() => this.retryMessages()}>
Ok
</div>
<div className='col-sm-2 button button-action button-cancel' onClick={() =>this.onCloseModal()}>
Cancel
</div>
</DialogBox.Footer>
</DialogBox>
Child Component- DialogBox.tsx
import * as React from 'react';
import { Component } from 'react';
import { Modal } from 'react-bootstrap';
import PropTypes from 'prop-types';
import './DialogBox.scss';
import Body from './Body';
import Footer from './Footer';
export interface IDialogInterface {
onCloseModal: PropTypes.func.isRequired;
modalOpen: PropTypes.bool.isRequired;
title: PropTypes.string.isRequired;
}
export default class DialogBox extends Component<IDialogInterface> {
constructor(props) {
super(props);
}
static Body = Body;
static Footer = Footer;
public render() {
return <Modal show={this.props.modalOpen} onHide={() => this.props.onCloseModal()}>
<Modal.Header closeButton>
<Modal.Title>{this.props.title}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Body>{}</Body> *what goes in here?*
<Body>{this.props.children}</Body> * I expected this to get only the stuff that's between `DialogBox.Body` in the Parent but it gets Footer stuff as well.*
</Modal.Body>
<Modal.Footer>
<Footer> {DialogBox.Footer} </Footer> *what goes in here? *
</Modal.Footer>
</Modal>;
}
}
Body.tsx -
export default class Body extends Component {
constructor(props) {
super(props);
}
public render() {
return <div>{this.props.children}</div>;
}
}
Footer.tsx:
export default class Footer extends Component {
constructor(props) {
super(props);
}
public render() {
return <div>{this.props.children}</div>;
}
}
I'm declaring Body and Footer as static properties so I can call them as I did in the Parent directly and it's clear as well.
The main issue I have is not knowing what to include within the Body and Footer tags. I'd like to pass the contents of <DialogBox.Body> and <DialogBox.Footer> from Messages Component to DialogBox component. this.props.children gets everything in between <DialogBox> tag. How do I pass the contents of Body and Footer separately to my child component from parent component?
Any help is highly appreciated. Thanks in advance.
I would create your Footer and Body as stateless components or just fragments, then pass them in as props of a component to render them. Something like this:
Messages.tsx
const Body = (
<React.Fragment>
<p>You have selected the messages to be retried. This action will cause the messages to be put back on to the original queues.</p>
<p>Do you want to proceed?</p>
</React.Fragment>
)
const Footer = (
<React.Fragment>
<div className='col-sm-2 button button-action button-primary' onClick={() => this.retryMessages()}>
Ok
</div>
<div className='col-sm-2 button button-action button-cancel' onClick={() => this.onCloseModal()}>
Cancel
</div>
</React.Fragment>
)
<DialogBox
modalOpen={ this.state.modalOpen }
onCloseModal={ () => this.onCloseModal() }
title="Retry"
body={ <Body /> }
footer={ <Footer /> }
/>
DialogBox.tsx
export default class DialogBox extends Component<IDialogInterface> {
render() {
const { body, footer } = this.props;
return (
<Modal show={ this.props.modalOpen } onHide={ () => this.props.onCloseModal() }>
<Modal.Header closeButton>
<Modal.Title>{ this.props.title }</Modal.Title>
</Modal.Header>
<Modal.Body>{ body }</Modal.Body>
<Modal.Footer>{ footer }</Modal.Footer>
</Modal>
)
}
}

Resources