Skip to content

Commit

Permalink
Adding bases components from Formuix (#35)
Browse files Browse the repository at this point in the history
* Inserido os componentes bases do Formuix

* Resolving lint errors

* Resolving comments

Co-authored-by: Sampaio Leal <samp14hd@gmail.com>
Co-authored-by: Yuri Pereira <yuri@eurekalabs.com.br>
  • Loading branch information
3 people committed Jan 31, 2022
1 parent 09dcad8 commit 027f8b2
Show file tree
Hide file tree
Showing 20 changed files with 994 additions and 1 deletion.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@
"dependencies": {
"inversify": ">=6.0.1",
"inversify-react": ">=1.0.1",
"ramda": ">=0.27.1"
"ramda": ">=0.27.1",
"react-input-mask": "^2.0.4",
"@types/react-input-mask": "^3.0.1",
"react-number-format": "^4.9.1",
"date-fns": "^2.28.0"
}
}
119 changes: 119 additions & 0 deletions src/components/Inputs/Autocomplete.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {
Autocomplete as MuiAutocomplete,
AutocompleteProps as MuiAutocompleteProps,
AutocompleteRenderOptionState,
Checkbox,
CircularProgress,
FilterOptionsState,
TextField,
TextFieldProps,
createFilterOptions,
} from '@mui/material';
import React, { useCallback, useEffect, useState } from 'react';

function filterOptions<T>(options: T[], state: FilterOptionsState<T>) {
const filteredOptions = createFilterOptions<T>();
return filteredOptions(options, state);
}

export type AutocompleteProps<T> = {
label?: string;
textFieldProps?: TextFieldProps;
checkbox?: boolean;
options: T[];
buildNew?: (value: string) => T;
debounce?: number;
onDebouncedInputChange?: (value: string) => void;
} & Omit<
MuiAutocompleteProps<any, true | false, true | false, true | false>,
'renderInput'
>;

function defaultFilterOptions<T>(buildNew: AutocompleteProps<T>['buildNew']) {
return (options: T[], state: FilterOptionsState<T>) => {
const filtered = filterOptions(options, state);
if (!!buildNew && state.inputValue !== '') {
filtered.push(buildNew(state.inputValue));
}
return filtered;
};
}

function Autocomplete<T>({
label,
textFieldProps,
checkbox,
options,
buildNew,
debounce,
onDebouncedInputChange,
...props
}: AutocompleteProps<T>) {
const [inputValue, setInputValue] = useState('');

useEffect(() => {
if (!debounce) {
return () => null;
}

const loadOptionsTimeout = setTimeout(() => {
if (onDebouncedInputChange) {
onDebouncedInputChange(inputValue);
}
}, debounce);

return () => {
clearTimeout(loadOptionsTimeout);
};
}, [inputValue]);

const withCheckboxOptionRenderer = useCallback(
(
params: React.HTMLAttributes<HTMLLIElement>,
option: T,
state: AutocompleteRenderOptionState
) => (
<li {...params}>
<Checkbox
color="primary"
style={{ marginRight: 8 }}
checked={state.selected}
/>
{(props?.getOptionLabel ?? ((option) => option))(option)}
</li>
),
[]
);

return (
<MuiAutocomplete
{...props}
options={options}
fullWidth
filterOptions={props.filterOptions || defaultFilterOptions(buildNew)}
loading={props.loading}
onInputChange={(e, value) => setInputValue(value)}
renderOption={checkbox ? withCheckboxOptionRenderer : undefined}
renderInput={(params) => (
<TextField
{...params}
{...textFieldProps}
label={label}
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{props.loading ? (
<CircularProgress color="inherit" size={20} />
) : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
)}
/>
);
}

export default Autocomplete;
58 changes: 58 additions & 0 deletions src/components/Inputs/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
Checkbox as MuiCheckbox,
CheckboxProps as MuiCheckboxProps,
FormControl,
FormControlLabel,
FormControlLabelProps,
FormControlProps,
FormGroup,
FormGroupProps,
FormHelperText,
} from '@mui/material';

export type CheckboxProps = {
label?: string;
formControlLabelProps?: Omit<FormControlLabelProps, 'control' | 'label'>;
formGroupProps?: FormGroupProps;
formControlProps?: FormControlProps;
helperText?: string;
CheckboxComponent?: (props: CheckboxProps) => React.ReactElement;
} & MuiCheckboxProps;

function Checkbox({
label,
CheckboxComponent,
formControlLabelProps,
formGroupProps,
formControlProps,
helperText,
...props
}: CheckboxProps) {
if (label) {
return (
<FormControl {...formControlProps}>
<FormGroup {...formGroupProps}>
<FormControlLabel
{...formControlLabelProps}
control={
CheckboxComponent ? (
<CheckboxComponent {...props} />
) : (
<MuiCheckbox {...props} />
)
}
label={label}
/>
</FormGroup>
{helperText && <FormHelperText>{helperText}</FormHelperText>}
</FormControl>
);
}
return CheckboxComponent ? (
<CheckboxComponent {...props} />
) : (
<MuiCheckbox {...props} />
);
}

export default Checkbox;
34 changes: 34 additions & 0 deletions src/components/Inputs/CurrencyField/CurrencyField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
InputAdornment,
InputBaseComponentProps,
TextField,
TextFieldProps,
} from '@mui/material';
import React from 'react';

import BaseNumberFormat from './NumberFormat';

const MoneyFormat = React.forwardRef<
React.PropsWithChildren<InputBaseComponentProps>,
any
>(function MoneyFormat(props, ref) {
return (
<BaseNumberFormat {...props} ref={ref} decimalScale={2} fixedDecimalScale />
);
});

function CurrencyField(props: TextFieldProps) {
return (
<TextField
{...props}
fullWidth
InputProps={{
...props.InputProps,
startAdornment: <InputAdornment position="start">R$</InputAdornment>,
inputComponent: MoneyFormat,
}}
/>
);
}

export default CurrencyField;
54 changes: 54 additions & 0 deletions src/components/Inputs/CurrencyField/NumberFormat.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint-disable react/prop-types */
import React from 'react';
import {
default as RNFNumberFormat,
NumberFormatProps,
} from 'react-number-format';

export type CustomProps = {
onChange: (value: {
target: {
name: string | undefined;
value: string | undefined;
};
}) => void;
} & NumberFormatProps;

const NumberFormat = React.forwardRef<HTMLElement, CustomProps>(
function NumberFormat(props, ref) {
const { onChange, decimalScale, thousandSeparator, ...rest } = props;
return (
<RNFNumberFormat
{...rest}
getInputRef={ref}
onValueChange={(values) => {
onChange({
target: {
name: props.name,
value: values.value,
},
});
}}
isNumericString
allowNegative={false}
thousandSeparator={thousandSeparator}
decimalSeparator=","
decimalScale={decimalScale}
isAllowed={(values) => {
const { formattedValue, floatValue } = values;
const correctedFloatValue = floatValue || 0;
return (
formattedValue === '' || correctedFloatValue <= 9999999999999.99
);
}}
/>
);
}
);

NumberFormat.defaultProps = {
decimalScale: 2,
thousandSeparator: '.',
};

export default NumberFormat;
2 changes: 2 additions & 0 deletions src/components/Inputs/CurrencyField/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as CurrencyField } from './CurrencyField';
export { default as NumberFormat } from './NumberFormat';
49 changes: 49 additions & 0 deletions src/components/Inputs/DatePicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
DatePicker as MuiDatePicker,
DatePickerProps as MuiDatePickerProps,
LocalizationProvider,
LocalizationProviderProps,
} from '@mui/lab';
import AdapterDateFns from '@mui/lab/AdapterDateFns';
import { TextField, TextFieldProps } from '@mui/material';

export type DatePickerProps = {
label?: string;
textFieldProps?: TextFieldProps;
localizationProviderProps?: Omit<LocalizationProviderProps, 'dateAdapter'>;
dateAdapter?: LocalizationProviderProps['dateAdapter'];
onDatePickerChange: (
date: unknown,
keyboardInputValue: string | undefined
) => void;
datePickerValue: Date | string | undefined;
} & Omit<MuiDatePickerProps, 'renderInput' | 'onChange' | 'value'>;

function DatePicker({
label,
textFieldProps,
dateAdapter,
localizationProviderProps,
onDatePickerChange,
datePickerValue,
...props
}: DatePickerProps) {
return (
<LocalizationProvider
{...localizationProviderProps}
dateAdapter={dateAdapter || AdapterDateFns}
>
<MuiDatePicker
{...props}
value={datePickerValue}
onChange={onDatePickerChange}
label={label}
renderInput={(params) => (
<TextField {...params} fullWidth {...textFieldProps} />
)}
/>
</LocalizationProvider>
);
}

export default DatePicker;
Loading

0 comments on commit 027f8b2

Please sign in to comment.