I would like to know how to customize the react datepicker, the main customizations I would like to do are when I click on the header, a grid appears to select the year and month, and if there is a way to disable and paint the weekends with a different color.
Here is my code:
function EditDatePicker(props: GridRenderEditCellParams<string>) {
const [startDate, setStartDate] = useState<Date | null>(new Date());
const openToDate = new Date('01/01/2022');
return (
<DatePicker
dateFormat="dd/MM/yyyy"
selected={startDate}
onChange={(date) => setStartDate(date)}
dateFormatCalendar={"MMM yyyy"}
minDate={subMonths(new Date(), 6)}
maxDate={addMonths(new Date(), 6)}
showMonthYearDropdown
openToDate={openToDate}
/>
);
};
You can check in the documentation:
Custom header
Custom weeks colors
This Custom Hook Example worked for me:
import React, { useState } from "react";
import DatePicker from "react-datepicker";
import { getMonth, getYear } from "date-fns";
import range from "lodash/range";
import "react-datepicker/dist/react-datepicker.css";
export default function UseDatepicker(props) {
const [startDate, setStartDate] = useState(new Date());
const years = range(1990, getYear(new Date()) + 0, 1);
const months = [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Décembre",
];
return (
<DatePicker
className="custom-input-style"
renderCustomHeader={({
date,
changeYear,
changeMonth,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}) => (
<div
style={{
margin: 10,
display: "flex",
justifyContent: "center",
}}
>
<button
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
>
{"<"}
</button>
<select
className="custom-select-style"
value={getYear(date)}
onChange={({ target: { value } }) =>
changeYear(value)
}
>
{years.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<select
className="custom-select-style"
value={months[getMonth(date)]}
onChange={({ target: { value } }) =>
changeMonth(months.indexOf(value))
}
>
{months.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
<button
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
>
{">"}
</button>
</div>
)}
selected={startDate}
onChange={(date) => setStartDate(date)}
/>
);
}
Hope this help! :)
Related
I am using a headless UI tab component and when I add padding to the buttons as in below code, I expect all the buttons to have uniform padding but there seems to be some issues here.
Headless UI tabs component:
<Tab.List className="flex sm:flex-col">
<Tab>
{({ selected }) => (
<button
className={`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`}
>
Frontend
</button>
)}
</Tab>
<Tab>
{({ selected }) => (
<button
className={`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`}
>
Backend
</button>
)}
</Tab>
<Tab>
{({ selected }) => (
<button
className={`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`}
>
Multimedia
</button>
)}
</Tab>
</Tab.List>
Result:
Possible Cause:
Button padding seems to be rendering twice by headless UI otherwise button itself has the required padding.
Also if it is of any help, I have added the .babelrc.js and updated the _document.js for making twin macro work:
.babelrc.js
module.exports = {
presets: [['next/babel', { 'preset-react': { runtime: 'automatic' } }]],
plugins: ['babel-plugin-macros', ['styled-components', { ssr: true }]],
}
_document.js
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
Any help or suggestion is greatly appreciated
EDIT:
Changing the button to a div solved the issue. I am still not quite sure how it solved though
Tab itself renders a button. So, to prevent nesting a button element inside another, you need to use the as prop on the Tab component:
<Tab.List className="flex sm:flex-col">
<Tab as={Fragment}>
{({ selected }) => (
<button
className={`px-6 py-4 ${
selected ? 'bg-white text-black' : 'bg-red-600 text-white'
}`}
>
Frontend
</button>
)}
</Tab>
{/*...*/}
</Tab.List>
You can also do:
<Tab.List className="flex sm:flex-col">
<Tab
className={({ selected }) =>
`px-6 py-4 ${selected ? 'bg-white text-black' : 'bg-red-600 text-white'}`
}
>
Frontend
</Tab>
{/*...*/}
</Tab.List>
Reference: https://headlessui.dev/react/tabs#styling-the-selected-tab
I have following react code.
My code
What I would like is to when I hover first image than other image should hide (or become transparent, so that the positioning does not collapse).
Аnd so it would be for other pictures, for example if you make a hover on a third picture, then the first, second and fourth pictures should become hide or transparent.
I look in other topics like:
How to affect other elements when one element is hovered and Hide element on hover of another element but I can't fix my code.
Maybe it will be more easy to fix using some reactJS code?
Please help me.
I would do it like this:
Track the index of hovered item, and changeing the style opacity depending on that hovered index.
// SolutionBox.jsx
import React, { useState } from "react";
import SolutionItem from "./SolutionItem";
import Ecommerce from "../img/a.png";
import Middleware from "../img/b.png";
import SalesMarketing from "../img/c.png";
import Analytics from "../img/d.png";
import _ from "lodash";
function SolutionsSectionBox({ onBGChanged }) {
const [focused, setFocused] = useState(0);
let callBGChanged = menuName => {
if (_.isFunction(onBGChanged)) {
onBGChanged(menuName);
}
};
return (
<div className="solutions-section-box-box">
<SolutionItem
solutionIMG={Ecommerce}
onHover={state => {
setFocused(1);
callBGChanged(state === true ? "Ecommerce" : "default");
}}
focused={focused}
index={1}
onLeave={() => setFocused(0)}
/>
<SolutionItem
solutionIMG={SalesMarketing}
onHover={state => {
setFocused(2);
callBGChanged(state === true ? "SalesMarketing" : "default");
}}
focused={focused}
index={2}
onLeave={() => setFocused(0)}
/>
<SolutionItem
solutionIMG={Analytics}
onHover={state => {
setFocused(3);
callBGChanged(state === true ? "Analytics" : "default");
}}
focused={focused}
index={3}
onLeave={() => setFocused(0)}
/>
<SolutionItem
solutionIMG={Middleware}
onHover={state => {
setFocused(4);
callBGChanged(state === true ? "Middleware" : "default");
}}
focused={focused}
index={4}
onLeave={() => setFocused(0)}
/>
</div>
);
}
export default SolutionsSectionBox;
Solution Item:
// Solution Item:
import React from "react";
import _ from "lodash";
function SolutionsSectionBoxItem({
onLeave,
solutionIMG,
onHover,
index = 0,
focused = 0
}) {
let callOnHover = state => {
if (_.isFunction(onHover)) {
onHover(state);
}
};
return (
<div className="solutions-section-item-box">
<img
style={{
opacity: focused && focused !== index ? 0.5 : 1
}}
src={solutionIMG}
alt=""
onMouseEnter={() => {
callOnHover(true);
}}
onMouseLeave={() => {
callOnHover(false);
onLeave();
}}
className="solutions-section-item-img"
/>
</div>
);
}
export default SolutionsSectionBoxItem;
You can use your existing bgImg state to infer which is visible.
If you pass it as a prop to SolutionBox like
<SolutionBox bgImage={bgImage} onBGChanged={onBGChanged} />
and then for each SolutionItem
<SolutionItem
solutionIMG={Ecommerce}
visible={bgImage === Ecommerce}
onHover={state => {
callBGChanged(state === true ? "Ecommerce" : "default");
}}
/>
and use it to style in SolutionItem
<div className="solutions-section-item-box" style={{ opacity: visible ? 1 : 0.5}}>
I have designed a form with validation using TypeScript Material UI and Formik. I want a material UI Icon to appear in my textfield area, here's my code:
import React from 'react'
import { Formik, Form, FieldAttributes,useField} from 'formik'
import { TextField } from '#material-ui/core'
import CalendarTodayIcon from '#material-ui/icons/CalendarToday'
import * as yup from 'yup'
import './MainInfo.css'
const MyTextField: React.FC<FieldAttributes<{}>> = ({
placeholder,type,className,style,
...props
}) => {
const [field, meta] = useField<{}>(props);
const errorText = meta.error && meta.touched ? meta.error : "";
return (
<div className='container'>
<TextField
placeholder={placeholder}
className={className}
style={style}
type={type}
{...field}
helperText={errorText}
error={!!errorText}
id="outlined-basic"
variant="outlined"
/>
</div>
);
};
export function MainInfo() {
return (
<div>
<Formik
validateOnChange={true} validationSchema={validationSchema} initialValues={{ Title: '', ActivationDate: '', ExpirationDate: '', DirectManager: '', HRBP: '' }} onSubmit={(data) => {
console.log(data)
}}
>
{({values, errors}) => (
<Form id='my-form' >
<div>
<label className='label'>عنوان</label>
<div >
<MyTextField style={{width:'60%'}} placeholder='طراح' name='Title' type='input' />
</div>
...
</div>
</Form>
)}
</Formik>
</div>
)
}
but the problem is that I can not add a new Icon property or InputProp since <FieldAttributes<{}>> doesnt accept it. how can I define a new property for the FieldAttributes or fix this issue?
Use the TextField Props InputProps to customize the input field
And use startAdornment, endAdornment to customize the prefix/suffix
Finally use icon inside InputAdornment would be fine
import { TextField, InputAdornment } from "#material-ui/core";
import ExpandLess from "#material-ui/icons/ExpandLess";
import ExpandMore from "#material-ui/icons/ExpandMore";
<TextField
id="standard-basic"
label="Standard"
InputProps={{
startAdornment: (
<InputAdornment position="start">
<ExpandLess />
</InputAdornment>
),
endAdornment: (
<InputAdornment position="end">
<ExpandMore />
</InputAdornment>
)
}}
/>
Refer:
MUI TextField Props API: InputProps, startAdornment, endAdornment
MUI InputInputAdornment Props API
online demo: https://stackblitz.com/edit/gzlbzm
I want to position selected items from Select isMulti elsewhere.
What I did before was hide the selected values, and save the selected values on some state and display in other place.
But this way I don't have the clear indicator for this element.
handleChange = (event) => {
this.setState({secondarySelectedOptions: event});
};
render() {
const { secondarySelectedOption } = this.state;
return (
<>
<Select
isMulti
name="secondary"
options={this.state.options}
styles={{
multiValue: base => ({
...base,
display: "none"
}),
}}
onChange={this.handleChange}
value={secondarySelectedOption}
/>
</>
)
<div className='half-width'>
{this.state.secondarySelectedOptions.map((item) => (
<div>{item.value}</div>
))}
</div>
I have the following:
--- before render ---
const fontArray = [
["Standard", "Standard"], ["Abril FatFace", "'Abril Fatface', cursive"],
["Alfa Slab One", "'Alfa Slab One', cursive"],
["Chonburi", "'Chonburi', cursive"], ["Comfortaa", "'Comfortaa', cursive"],
["Lobster", "'Lobster', cursive"], ["Pacfico", "'Pacifico', cursive"]
]
--- in render ---
<FormControl style={{margin: '10px'}}>
<InputLabel htmlFor="select-font">Font</InputLabel>
<Select
value={this.state.font[0]}
onChange={(evt)=>this.handleFontChange(evt)}
inputProps={{
name: 'font',
id: 'select-font',
}}
>
{fontArray.map((font, index)=>{
return(
<MenuItem key={font} value={font}>
<div style={{fontFamily: `${font[1]}`}}>
{font[0]}
</div>
</MenuItem>
)
})}
</Select>
</FormControl>
And as you can guess the current font is held in state.
--- Here is how I handle select change ---
handleFontChange = (event) => {
this.setState({ font: event.target.value })
};
So what I want is to be able to have a font select, where the font is shown. It almost works. For example, when I click the select I get:
However, the select itself is empty (even when I've confirmed that state is populated:
What am I doing wrong? Maybe material-ui can't handle stylized default text?
EDIT: The two answers below seem close, but not quite right for what I'm trying to do.
If you replace
<MenuItem key={font} value={font}>
with
<MenuItem key={font} value={font[0]}>
It does replace the font with the correct selected value. Great!
...but it also then replaces this.state.font with this.state.font[0]. I'm currently attempting to get this to work by changing the handle function like this:
handleFontChange = (event, fontArray, stateData) => {
let newFont = fontArray.filter(i=>{
if(i[0]==event.target.value){
return i
}
})
this.setState({ font: newFont })
};
Which seems to set this.state.font correctly, but it again doesn't
seem to want to make the select box show the selected font.
Hmmm....
SOLVED
Here is a modification of a solution below:
Using
renderValue = (value) => {
return(
<div style={{fontFamily: `${value[1]}`}}>
{value[0]}
</div>
)
}
and
<...>
<Select
value={this.state.font}
renderValue={() => this.renderValue(this.state.font)}
<...>
Gives...
You can use renderValue to solve this.
renderValue = (value) => {
return value && value[0];
}
in render method
<FormControl style={{margin: 10}}>
<InputLabel htmlFor="select-font">Font</InputLabel>
<Select
value={this.state.font}
renderValue={() => this.renderValue(this.state.font)}
onChange={evt => this.handleFontChange(evt)}
inputProps={{
name: "font",
id: "select-font"
}}
>
{fontArray.map((font, index) => {
return (
<MenuItem key={index} value={font}>
<div style={{fontFamily: `${font[1]}`}}>
{font[0]}
</div>
</MenuItem>
);
})}
</Select>
</FormControl>
<...>
<Select
value={this.state.font?this.state.font :defaultvlue}
renderValue={() => this.renderValue(this.state.font)}
<...>
you can use ternary operator ,if you have data show data else default value