I'm trying to programmatically trigger a onCancel event on Inline edit view component of Atlaskit, But I couldn't find any API docs where I can trigger on cancel event on this inline component.
import React from 'react';
import styled from 'styled-components';
import Textfield from '#atlaskit/textfield';
import { gridSize, fontSize } from '#atlaskit/theme';
import InlineEdit from '#atlaskit/inline-edit';
const ReadViewContainer = styled.div`
display: flex;
font-size: ${fontSize()}px;
line-height: ${(gridSize() * 2.5) / fontSize()};
max-width: 100%;
min-height: ${(gridSize() * 2.5) / fontSize()}em;
padding: ${gridSize()}px ${gridSize() - 2}px;
word-break: break-word;
`;
interface State {
editValue: string;
}
export default class InlineEditExample extends React.Component<void, State> {
state = {
editValue: 'Field value',
};
render() {
return (
<div
style={{
padding: `${gridSize()}px ${gridSize()}px ${gridSize() * 6}px`,
}}
>
<InlineEdit
defaultValue={this.state.editValue}
label="Inline edit"
editView={fieldProps => <Textfield {...fieldProps} autoFocus />}
readView={() => (
<ReadViewContainer>
{this.state.editValue || 'Click to enter value'}
</ReadViewContainer>
)}
onConfirm={value => this.setState({ editValue: value })}
/>
</div>
);
}
}
In my opinion the best way to do this is to use the InlineEditUncontrolled component and make it a controlled component using the following props: onConfirm, onCancel, isEditing. After that you can change internal isEditing state to false.
Related
I like to add styling to a styled component that is in a different dom.
Like this Material-ui Menu component example, the dashboard button is highlighted gray, and the menu drop is highlighted light blue.
They are written in the same component file but they are in different dom.
I like to add styling to the Menu component from Button component.
Is that possible?
Demo sandbox: https://codesandbox.io/s/si8tr5?file=/demo.js
Menu material ui official doc: https://mui.com/material-ui/react-menu/#basic-menu
index.jsx
import * as React from 'react';
import MenuItem from '#mui/material/MenuItem';
import {DisplayMenu, DisplayButton} from './styles'
export default function BasicMenu() {
const [anchorEl, setAnchorEl] = React.useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<div>
<DisplayButton
id="basic-button"
aria-controls={open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
>
Dashboard
</DisplayButton>
<DisplayMenu
id="basic-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button',
}}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</DisplayMenu>
</div>
);
}
styles.js
import styled from 'styled-components';
import Button from '#mui/material/Button';
import Menu from '#mui/material/Menu';
export const DisplayMenu = styled(Menu)`
padding: 20px;
`;
DisplayMenu.displayName = 'DisplayMenu';
export const DisplayButton = styled(Button)`
margin: 10px;
${DisplayMenu}{
& .MuiPaper-root {
width: 300px;
}
}
`;
DisplayButton.displayName = 'DisplayButton';
I know just doing this below will work but this is just an example and the reality is more complicated.
I just made it simple to ask this question here.
export const DisplayMenu = styled(Menu)`
padding: 20px;
& .MuiPaper-root {
width: 300px;
}
`;
Your current code won't work because you are applying styles to descendent DisplayMenu components (DisplayButton is a sibling). I don't really think it makes sense to do this but you could select the sibling:
export const DisplayButton = styled(Button)`
margin: 10px;
& + ${DisplayMenu}{
& .MuiPaper-root {
width: 300px;
}
}
`;
I think styling DisplayMenu directly makes the most sense (your last approach).
However If this is a permutation of DisplayMenu when used with a button, I think you should consider making the wrapper div into a styled component since that allows you to apply contextual styles to the menu (change its style based on 'where' it was used):
const MenuButton = styled.div`
${DisplayMenu}{
& .MuiPaper-root {
width: 300px;
}
`
// And use this in your component
<MenuButton>
<DisplayButton {...} />
<DisplayMenu {...} />
</MenuButton>
This way we only add the width to DisplayMenu when used within the context of MenuButton
i want to know how can i use React.memo, useMemo and useCallback correct way.
I know if dependency or props have object and array, it doesnt work properly.
So I'm trying to apply it to my project as small as possible because I have a lot of object and array type props and dependency
// email is props
const onRequestOTP: () => void = useCallback(async () => {
const res = await resendEmail(email);
if (res?.data?.status === 1) {
setIsResponseError(false);
setIsRequest(true);
setStep(2);
} else if (res?.data?.status === 0) {
setIsResponseError(true);
}
}, [email]);
import styled from 'styled-components';
import { memo } from 'react';
// lib
import { selectpalette } from 'lib/styles/palette';
// components
import Font from 'components/atoms/Font';
// #mui
import { Grid } from '#mui/material';
import MdiIcon from 'components/atoms/Icon';
const Alert: ({ text, isError }: Props) => JSX.Element = ({ text, isError }: Props) => {
const bgColor = isError ? 'red_op_12' : 'primary_op_12';
return (
<Wrapper bgColor={selectpalette(bgColor)}>
<Grid
container
alignItems="center"
direction="row"
flexWrap="nowrap"
justifyContent="space-between"
>
<Grid item sx={{ paddingRight: '8px' }}>
{isError ? (
<MdiIcon width={20} height={20} src="/icons/warning/ic_warning_red_round.svg" />
) : (
<MdiIcon width={20} height={20} src="/icons/mail/ic_mail_primary.svg" />
)}
</Grid>
<Grid item flex="1 1 auto">
<Font className="body-1" color={isError ? 'error' : 'primary'}>
{text}
</Font>
</Grid>
</Grid>
</Wrapper>
);
};
const Wrapper = styled.div<{ bgColor: string }>`
padding: 16px;
border-radius: 8px;
display: -webkit-flex;
margin-bottom: 24px;
width: 100%;
background-color: ${props => props.bgColor};
box-sizing: border-box;
`;
interface Props {
text: string;
isError: boolean;
}
export default memo(Alert);
const FormControlSX = useMemo(
() => ({
width: '100%',
'& .MuiFilledInput-root': {
borderTopLeftRadius: '8px',
borderTopRightRadius: '8px',
backgroundColor: palette.white,
},
}),
[],
);
Let me know there is an incorrect use.
All three are related to optimization. If you don't have a performance issues then don't use them. If you have — measure first.
The Alert component is a single and not heavy (I guess) so using memo doesn't improve a performance
useCallback is rarely used. For example, if you use onRequestOTP as prop for a lot of children (or one heavy child) and want to prevent rerendering you can use useCallback in conjunction with memo for a child component
The function inside useMemo is cheap so nothing to do here
I am working on a React project, In my project I have two buttons, for First button I assigned a state for second button I written a function and I assigned a state as well. but my onClick function is not working. please help me to resolve this isssue.
This is App.js
import React, { useState } from "react";
import { Button } from "antd"
import 'antd/dist/antd.css';
import "./App.css";
const App = () => {
const [buttonOne, setButtonOne] = useState("red")
const [buttonTwo, setButtonTwo] = useState("blue")
const buttonTwoBackgroundColor = () => {
setButtonTwo({
backgroundColor: "red",
border: "red"
})
}
return (
<div>
<Button style={{backgroundColor: buttonOne, border: buttonOne}} className="one" type="primary">First</Button>
<Button style={{backgroundColor: buttonTwo, border: buttonTwo}} onClick={buttonTwoBackgroundColor} className="two" type="primary">Second</Button>
</div>
)
}
export default App
This is App.css
.one {
margin-right: 5px;
margin-left: 250px;
margin-top: 50px;
}
.two, .three, .four, .five {
margin-right: 5px;
}
In the function buttonTwoBackgroundColor you set setButtonTwo to a object. it should be a string.
const buttonTwoBackgroundColor = () => {
setButtonTwo("red")
}
change
onClick={buttonTwoBackgroundColor}
to
onClick={setButtonTwo("red")}
you are using useState as string at initialization and assigning an object in function below, which is not proper way!
You are trying to set state to be an object when you have defined the defualt state as a string.
Update the default state to an object and then access properties like this:
import React, { useState } from "react";
import { Button } from "antd";
import "./styles.css";
export default function App() {
const [buttonOne, setButtonOne] = useState("red");
const [buttonTwo, setButtonTwo] = useState({backgroundColor: "blue", border: "blue"});
const buttonTwoBackgroundColor = () => {
setButtonTwo(prevState => ({
...prevState,
backgroundColor: 'blue',
border: 'red'
}));
};
return (
<div>
<Button
style={{ backgroundColor: buttonOne, border: buttonOne }}
className="one"
type="primary"
>
First
</Button>
<Button
style={{ backgroundColor: buttonTwo.backgroundColor, border: buttonTwo.border }}
onClick={buttonTwoBackgroundColor}
className="two"
type="primary"
>
Second
</Button>
</div>
);
}
I tried to create a button which gives me a popup window on click. The popup window contains a form which should let me type in any new entry. On submit, the entry should be passed to the main component.
I have two components. The main component is the 'App' component and the other component is the 'Popup' component.
Here is my code:
App.js
import React, { Component } from "react";
import Popup from "./Popup.js";
import "./styles.css";
class App extends Component {
showPopup = false;
createEntry = () => {
this.showPopup = true;
this.setState({ showPopup: this.showPopup });
};
handleSubmit = (value) => {
console.log("New Entry: " + value);
this.showPopup = false;
this.setState({ showPopup: this.showPopup });
};
render() {
return (
<React.Fragment>
<button onClick={this.createEntry}> + </button>
{this.showPopup ? <Popup handleSubmit={this.handleSubmit} /> : null}
</React.Fragment>
);
}
}
export default App;
Popup.js
import React, { Component } from "react";
import "./styles.css";
class Popup extends Component {
constructor(props) {
super(props);
this.state = {
value: ""
};
// I want to pass the submitted value to the App Component
this.handleSubmit = this.props.handleSubmit.bind(this, this.state.value);
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
this.setState({ value: event.target.value });
};
render() {
return (
<React.Fragment>
<div className="popup">
<div className="popup_inner">
<div> Create New Entry </div>
<form onSubmit={this.handleSubmit}>
<label>
<input
type="text"
name="name"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
</div>
</React.Fragment>
);
}
}
export default Popup;
styles.css
.App {
font-family: sans-serif;
text-align: center;
}
.popup {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.popup_inner {
position: absolute;
left: 25%;
right: 25%;
top: 25%;
bottom: 25%;
margin: auto;
background: white;
}
I tried to pass the 'value' to the 'handleSubmit' method by using handleSubmit as a prop method but that doesn't work.
What is an appropriate way to pass the value to the App component?
I'm still new to React, so please bear with me.
Thanks in advance.
The answer is in your question. You're passing it as a prop method and so you'll have to access it from the props.
In your Popup.js you can call the method passed from your parent as
onSubmit = {this.props.handleSubmit}
I have created a CodeSandBox to demonstrate the flow of data from parent to child components and vice versa
I have a button component that can be of different types eg primary, secondary, etc:
export const buttonTypes = [
'primary',
'secondary',
'tertiary',
'positive',
'negative',
]
const Button = ({ text, type }) => {
return(
<button className={type}>{text}</button>
)
}
Button.propTypes = {
text: PropTypes.string,
type: PropTypes.oneOf(buttonTypes),
}
In my Storybook file I'm mapping through the options. This means you can see all the variants on a single page and if another string was added to the buttonTypes array it would automatically be added to the style guide:
import ButtonComponent, { buttonTypes } from './Button';
const Button = () => {
return(
<div>
{
buttonTypes.map(type=>(
<ButtonComponent key={type} text={type} type={type} />
))
}
</div>
)
}
export default {
title: 'Components',
component: Button,
};
The problem is that this doens't work with with many of the add-ons eg knobs. For knobs to work you need Button to be the actual component, not a wrapper as I did above.
import ButtonComponent, { buttonTypes } from './Button';
const Button = () => {
return (
<ButtonComponent
type={select('type', buttonTypes, buttonTypes.primary)}
text="Button"
/>
);
};
Is there a way to use knobs and show all the variations on a single page? Ideally without having to create each component manually as this is more work and then won't automatically update if a new string is added to buttonTypes.
Use the grouping feature of knobs, that way each instance of your component will get its own knob instance instead of all the knob instances being shared between all of the component instances. You can even mix grouped knobs with non-grouped nobs if you want certain things to be shared and other not to be.
In the following example, I have a <Button/> story where each instance has its own copy of the type and disabled properties, but the text is shared between them all.
Each button type gets its own panel where you can set its type and disabled. The "Other" group contains any knobs that didn't have their group set (such as text).
src/Button/Button.component.jsx
import * as React from "react";
import "./Button.style.css";
export const Button = ({
text,
type,
disabled,
onClick
}) => (
<button
className={`button button--${type} ${disabled ? "button--disabled" : ""}`}
disabled={disabled}
onClick={onClick}
children={text}
/>
);
src/Button/Button.stories.jsx
import * as React from "react";
import {withKnobs, text, boolean, select} from "#storybook/addon-knobs";
import {action} from "#storybook/addon-actions";
import {Button, buttonTypes} from "./";
export default {
title: "Button",
component: Button,
decorators: [withKnobs]
};
export const ButtonStory = () => {
const buttontext = text("Text", "Click Me");
return (
<div>
{buttonTypes.map(buttonType => (
<div key={buttonType}>
<Button
type={select("Type", buttonTypes, buttonType, buttonType)}
disabled={boolean("Disabled", false, buttonType)}
onClick={action(`${buttonType} clicked`)}
text={buttontext}
/>
</div>
))}
</div>
);
};
ButtonStory.story = {
name: "All"
}
src/Button/Button.types.js
export const buttonTypes = [
"primary",
"secondary",
"tertiary"
];
src/Button/Button.style.css
.button {
padding: 0.5em;
font-size: 1.25em;
border-radius: 10px;
border-width: 2px;
border-style: solid;
border-color: black;
}
.button--primary {
background-color: rgb(132, 198, 106);
color: black;
border-color: black;
}
.button--secondary {
background-color: rgb(194, 194, 194);
color: black;
border-color: black;
}
.button--tertiary {
background-color: transparent;
color: inherit;
border-color: transparent;
}
.button--disabled {
background-color: rgb(194, 194, 194);
color: rgb(105, 102, 102);
border-color: rgb(105, 102, 102);
}
src/Button/index.js
export {Button} from "./Button.component";
export {buttonTypes} from "./Button.types";