Material UI - Change Font Size of TextField from Functional Component - reactjs

I have the following functional component and I would like to change the font size of the textfield, but for some reason I can't figure it out. I know if I have a traditional component I can export it withStyles and set the className or InputProps, but I'm not sure how to do that with my current setup:
Class Definition:
const FormObjectText = ({id, multiline, onBlur, onChange, onFocus, placeholder, value, style, ...additionalProps}) => (
<TextField
{...additionalProps}
fullWidth
id={id}
inputProps={additionalProps.maxLength != null ? {maxLength: additionalProps.maxLength} : {}}
margin="normal"
multiline={multiline}
onBlur={onBlur}
onChange={e => onChange({ value: e.target.value })}
onFocus={onFocus}
placeholder={placeholder}
style={{
...style
}}
value={value !== null ? value : ""}
/>
);
Export from that file:
export const FORM_OBJECT_DICT = {
text: FormObjectTextStyled,
date: FormObjectDate,
// Others
};
Where it is called in another file:
{FORM_OBJECT_DICT["text"]({
value: editing ? value : getFormObjectDisplayValue(configuration, value),
onChange: this.onChange
})}
Firstly, is there any way to change the font size of the TextField using inline styles (not withStyles()), or if not, where/how would i apply withStyles() in this instance?

You can change the font size with inline styles this way:
<TextField inputProps={{ style: { fontSize: "5rem" } }} />
There is nothing about withStyles that cares whether your component is a function component or a class, so if you want to use classes, you could do something like:
const FormObjectTextStyled = withStyles(styles)(FormObjectText);
and then access the classes prop inside FormObjectText.
Here's a sandbox showing both approaches:

Related

How to use RadixUI with React Hook Form's Controller

I'm unable to use Radix UI's select component with React Hook Form's Controller and don't understand why the following doesn't work in this CodeSandbox. Any ideas?
For example, the Radix UI documentation shows passing value and onChange props to <SelectPrimitive.Root> as well as the ref to <SelectPrimitive.Trigger>
export const Select = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<SelectPrimitive.Root {...props}>
<SelectPrimitive.Trigger ref={forwardedRef}>
<SelectPrimitive.Value />
...
</SelectPrimitive.Root>
How I implemented it:
const SelectItem = forwardRef(({ value, onValueChange }, forwardedRef) => {
return (
<Select.Root value={value} onValueChange={onValueChange}>
<Select.Trigger
ref={forwardedRef}
className="text-md border-solid border-2 border-slate-500 px-2"
>
...
</Select.Root>
How I pass value and onChange in WrapperSelect using RHF's Controller
<Controller
control={control}
name={name}
render={({ field: { onChange, value, ref, ...props } }) => (
<SelectItem
valueOnChange={onChange}
value={value}
forwardedRef={ref}
/>
)}
/>
I had similar problem, also with Radio button and I found out that you need to use custom <Select.Value> component with asChild prop
<Select.Value asChild>
<span>{props.value ?? "Select something..."}</span>
</Select.Value>
Here is a working sandbox: https://codesandbox.io/s/admiring-sun-xwupmz?file=/src/atoms/SelectItem.tsx

React Material UI TextField type=number onStepChange analog?

I building a React component using Mui TextField. Its a number field so there are two ways to update the TextField component: Editing the text itself and using the step arrows. When "blurring" the field, I want to snap the value to the nearest multiple of 5. I also set the step="5" as well.
The component itself has an onChange event that passes the number value but I only want this event to fire when the user "steps" the value or the user "blurs" the field. Here's what I've got so far:
interface WeightFieldProps {
name?: string
placeholder?: string
label?: string
value?: number
onChange?: (value: number) => void
}
const WeightField: React.FC<WeightFieldProps> = ({
name,
placeholder,
label,
value = 0,
onChange
}) => {
const [weight, setWeight] = useState(value)
// Update the component but do not fire the parent onChange event.
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = parseInt(event.target.value)
setWeight(value)
}
// Update the component as usual but notify the parent component that
// the value has changed.
const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {
const value = snapWeightValue(parseInt(event.target.value))
setWeight(value)
if (onChange) onChange(value)
}
// Ideally, I want the parent component only be notified when the user
// is changing the input value via the step arrows.
// const handleStepChange = (event: React.SomeEvent) => {
// const value = parseInt(event.target.value)
// setWeight(value)
// if (onChange) onChange(value)
// }
return <TextField
name={name}
type="number"
placeholder={placeholder}
label={label}
InputProps={{
endAdornment: <InputAdornment position="end">lbs</InputAdornment>
}}
inputProps={{
step: "5",
style: {
fontSize: "2em",
padding: "10px",
textAlign: "right"
}
}}
value={weight}
onChange={handleChange}
onBlur={handleBlur}
// onStepChange={handleStepChange}
fullWidth
/>
}
What I'm hoping for is some kind of event handler specifically for when a user updates the field via the numeric step buttons or maybe a way to determine how the field is being updated during the onChange event so I can fire the component's onChange event only when the user is stepping the value?
I would suggest hiding the native arrow buttons, adding custom arrow buttons like in number inputs from UI-libraries, and then adding to these custom arrow buttons whenever handler you like. There is no such event that would be only triggered by clicking native arrow buttons.
you should move inputProps inside InputProps. else you will have eslint warning, no duplicate props allowed.
You can use onInput event handler inside inputProps as shown in below code.
ref: https://www.w3schools.com/jsref/event_oninput.asp
<TextField
name={name}
type="number"
placeholder={placeholder}
label={label}
InputProps={{
endAdornment: <InputAdornment position="end">lbs</InputAdornment>,
inputProps:{
step: "5",
onInput:()=> console.log('input changed'),
style: {
fontSize: "2em",
padding: "10px",
textAlign: "right"
}
}
}}
value={weight}
onChange={handleChange}
onBlur={handleBlur}
// onStepChange={handleStepChange}
fullWidth
/>

React.forwardRef warning but no ref passed or how to pass custom component to another component

I want to pass a custom input proponent to another proponent this way:
<FormTextField
name="startTime"
label="startTime"
type="time"
error={!!errors.startTime}
CustomTextField={TextFieldColorTimeIcon} <-- custom TextField
...
/>
The code for FormTextField:
export default function FormTextField({ name, CustomTextField, ...other }) {
const { control } = useFormContext();
let LocalCustomTextField = CustomTextField ? CustomTextField : TextField;
return (
<Controller
name={name}
control={control}
render={
({ field, fieldState: { error } }) => (<LocalCustomTextField {...field} fullWidth error={!!error} helperText={error?.message} {...other} />)
}
/>
);
}
And the code for TextFieldColorIcon:
export function TextFieldColorIcon({ sx, ...other }: TextFieldColorIconProps) {
return <TextField
sx={{
...sx,
'& input[type="time"]::-webkit-calendar-picker-indicator': {
filter:
'invert(41%) sepia(24%) saturate(301%) hue-rotate(166deg) brightness(101%) contrast(89%)',
},
}}
{...other} />
}
But I've got warning:
Warning: Function proponents cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Check the render method of Controller.
at TextFieldColorIcon
at Controller
at FormTextField
at div
despite of the fact that there is no ref passed.
What is the reason of this warning and am I passing custom TextFieldColorIcon right way?

Dynamically style components passed as props

The goal is to style a prop inside a function (if the prop exists).
More specifically, I basically pass an icon (from styled-icons) as a prop to it and it is supposed to add styling to that icon.
This works with warnings:
const InputRounded = ({ type, placeholder, icon }) => {
const Icon = styled(icon)`
color: #807da0;
width: 1.75rem;
margin: 0 1.25rem 0 0.75rem;
`
return (
<Container>
<Input type={type} placeholder={placeholder} />
<Icon />
</Container>
)
}
Here is how I call it:
import { LockPassword } from '#styled-icons/remix-line'
<Input type="password" placeholder="Password" icon={LockPassword} />
I am aware that one shouldn't create a component inside a function, but I have tried numerous ways otherwise and haven't reached anywhere. Any help for a better method would be greatly appreciated.
You can, very simply, pass a style prop to icon.
const InputRounded = ({ type, placeholder, icon: Icon }) => {
return (
<Container>
<Input type={type} placeholder={placeholder} />
<Icon style={{ color: '#807da0', ... }} />
</Container>
)
}
You could probably use the cloneElement method in React
https://reactjs.org/docs/react-api.html#cloneelement
return (
<>
{ React.cloneElement( icon, [props] }
</>
)
It is similar to
<element.type {...element.props} {...props}>{children}</element.type>
To override some values you can do inline styling.
or otherwise you could use some css classes to override with selectors as well.
if you are going to use styled-icons
you can just simply provide it the props directly.
Styled Icons accept all the valid props of an <svg /> element
https://github.com/styled-icons/styled-icons#props

KeyboardDatePicker #material-ui/pickers how to show days outside of month

How do I add all dates outside of the month while keeping the selection logic
now
i want
If i give TextField type='date', then all dates are displayed, but all my styles are lost.
My component
<MuiPickersUtilsProvider utils={MomentUtils} libInstance={momentLib}>
<DefaultKeyboardDatePicker
open={open}
value={value ?? null}
onChange={onChange}
disableIcon={disableIcon}
helperText={typeof userError === 'string' ? userError : errorNode || helperText}
error={!!userError || !!errorNode}
onClose={onClose}
renderDays={renderDay ? renderDays : void 0}
TextFieldComponent={TextField}
InputProps={{
inputRef,
inputProps: readOnly
? { readOnly: true, className: classes.readonly, onClick: onOpen, 'id-qa': idqa }
: { 'id-qa': idqa },
}}
InputAdornmentProps={{ onClick: onOpen }}
PopoverProps={{ anchorEl: inputRef.current }}
}}
{...props}
/>
</MuiPickersUtilsProvider>
I tried passing all the props and overwriting styles, nothing worked. Can i leave all styles
const WrapperTextField = () => <TextField {...props} type="date" className={clsx('MuiPickersDay-day')} />;
...
TextFieldComponent={WrapperTextField}
Wasted a lot of time. It is strange that in such a library there is no flag to show all numbers and work with them.
I would be grateful for your help!
You need to write custom renderDay function to be able to show not current month dates. Here is the example of this function in docs. To be able to select those days you need to go further and override IconButton onClick inside renderDay function. For example of code take a look at this question. As I see there is no simple way.

Resources