feat: abstracts select component
This commit is contained in:
@@ -1,18 +1,20 @@
|
||||
import { OptionsType, GroupedOptionsType } from 'react-select';
|
||||
|
||||
export type Options = OptionsType<Value> | GroupedOptionsType<Value>;
|
||||
|
||||
export type Value = {
|
||||
label: string
|
||||
value: any
|
||||
options?: Value[]
|
||||
value: string
|
||||
options?: Options
|
||||
}
|
||||
|
||||
export type Props = {
|
||||
className?: string
|
||||
value?: Value | Value[],
|
||||
onChange?: (value: any) => void,
|
||||
onChange?: (value: Value) => void,
|
||||
disabled?: boolean,
|
||||
showError?: boolean,
|
||||
options: OptionsType<Value> | GroupedOptionsType<Value>
|
||||
options: Options
|
||||
isMulti?: boolean,
|
||||
isDisabled?: boolean
|
||||
onInputChange?: (val: string) => void
|
||||
|
||||
87
src/admin/components/forms/field-types/Select/Input.tsx
Normal file
87
src/admin/components/forms/field-types/Select/Input.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
import React from 'react';
|
||||
import Label from '../../Label';
|
||||
import Error from '../../Error';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import { SelectField } from '../../../../../fields/config/types';
|
||||
import { Description } from '../../FieldDescription/types';
|
||||
import ReactSelect from '../../../elements/ReactSelect';
|
||||
import { Value as ReactSelectValue, Options as ReactSelectOptions } from '../../../elements/ReactSelect/types';
|
||||
// import { FieldType } from '../../useField/types';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export type SelectInputProps = Omit<SelectField, 'type' | 'value'> & {
|
||||
showError: boolean
|
||||
errorMessage?: string
|
||||
readOnly?: boolean
|
||||
path?: string
|
||||
required?: boolean
|
||||
value?: string
|
||||
description?: Description
|
||||
onChange?: (value: ReactSelectValue) => void
|
||||
style?: React.CSSProperties
|
||||
width?: string
|
||||
hasMany?: boolean
|
||||
options?: ReactSelectOptions
|
||||
}
|
||||
|
||||
const SelectInput: React.FC<SelectInputProps> = (props) => {
|
||||
const {
|
||||
showError,
|
||||
errorMessage,
|
||||
readOnly,
|
||||
path,
|
||||
label,
|
||||
required,
|
||||
value,
|
||||
onChange,
|
||||
description,
|
||||
style,
|
||||
width,
|
||||
options,
|
||||
hasMany,
|
||||
} = props;
|
||||
|
||||
const classes = [
|
||||
'field-type',
|
||||
'select',
|
||||
showError && 'error',
|
||||
readOnly && 'read-only',
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
const selectedOption = options.find((option) => option.value === value);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes}
|
||||
style={{
|
||||
...style,
|
||||
width,
|
||||
}}
|
||||
>
|
||||
<Error
|
||||
showError={showError}
|
||||
message={errorMessage}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={path}
|
||||
label={label}
|
||||
required={required}
|
||||
/>
|
||||
<ReactSelect
|
||||
onChange={onChange}
|
||||
value={selectedOption}
|
||||
showError={showError}
|
||||
isDisabled={readOnly}
|
||||
options={options}
|
||||
isMulti={hasMany}
|
||||
/>
|
||||
<FieldDescription
|
||||
value={value}
|
||||
description={description}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectInput;
|
||||
@@ -1,17 +1,10 @@
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import withCondition from '../../withCondition';
|
||||
import ReactSelect from '../../../elements/ReactSelect';
|
||||
import useField from '../../useField';
|
||||
import Label from '../../Label';
|
||||
import Error from '../../Error';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import { select } from '../../../../../fields/validations';
|
||||
import { Option } from '../../../../../fields/config/types';
|
||||
import { Props, Option as ReactSelectOption } from './types';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const baseClass = 'select';
|
||||
import { Props, ReactSelectOption } from './types';
|
||||
import SelectInput from './Input';
|
||||
|
||||
const formatOptions = (options: Option[]): ReactSelectOption[] => options.map((option) => {
|
||||
if (typeof option === 'object' && option.value) {
|
||||
@@ -41,7 +34,7 @@ const Select: React.FC<Props> = (props) => {
|
||||
condition,
|
||||
} = {},
|
||||
value: valueFromProps,
|
||||
onChange: onChangeFromProps
|
||||
onChange: onChangeFromProps,
|
||||
} = props;
|
||||
|
||||
const path = pathFromProps || name;
|
||||
@@ -87,15 +80,8 @@ const Select: React.FC<Props> = (props) => {
|
||||
readOnly,
|
||||
hasMany,
|
||||
onChangeFromProps,
|
||||
setValue
|
||||
])
|
||||
|
||||
const classes = [
|
||||
'field-type',
|
||||
baseClass,
|
||||
showError && 'error',
|
||||
readOnly && `${baseClass}--read-only`,
|
||||
].filter(Boolean).join(' ');
|
||||
setValue,
|
||||
]);
|
||||
|
||||
let valueToRender;
|
||||
|
||||
@@ -108,35 +94,18 @@ const Select: React.FC<Props> = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes}
|
||||
style={{
|
||||
...style,
|
||||
width,
|
||||
}}
|
||||
>
|
||||
<Error
|
||||
showError={showError}
|
||||
message={errorMessage}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={path}
|
||||
label={label}
|
||||
required={required}
|
||||
/>
|
||||
<ReactSelect
|
||||
onChange={onChange}
|
||||
value={valueToRender}
|
||||
showError={showError}
|
||||
isDisabled={readOnly}
|
||||
options={options}
|
||||
isMulti={hasMany}
|
||||
/>
|
||||
<FieldDescription
|
||||
value={value}
|
||||
description={description}
|
||||
/>
|
||||
</div>
|
||||
<SelectInput
|
||||
onChange={onChange}
|
||||
value={valueToRender}
|
||||
name={name}
|
||||
options={options}
|
||||
label={label}
|
||||
showError={showError}
|
||||
errorMessage={errorMessage}
|
||||
description={description}
|
||||
style={style}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { SelectField } from '../../../../../fields/config/types';
|
||||
|
||||
export type Option = {
|
||||
label: string
|
||||
value: any
|
||||
}
|
||||
|
||||
export type Props = Omit<SelectField, 'type'> & {
|
||||
path?: string
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import { text } from '../../../../../fields/validations';
|
||||
import { Props } from './types';
|
||||
import TextInput from './Input';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const Text: React.FC<Props> = (props) => {
|
||||
const {
|
||||
path: pathFromProps,
|
||||
|
||||
@@ -77,7 +77,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
ignoreWhileFlattening,
|
||||
initialValue,
|
||||
stringify,
|
||||
condition
|
||||
condition,
|
||||
]);
|
||||
|
||||
// Method to return from `useField`, used to
|
||||
@@ -91,12 +91,11 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
setInternalValue(val);
|
||||
}, [
|
||||
setModified,
|
||||
modified,
|
||||
ignoreWhileFlattening
|
||||
ignoreWhileFlattening,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -116,7 +115,7 @@ const useField = <T extends unknown>(options: Options): FieldType<T> => {
|
||||
}, [
|
||||
valueToSend,
|
||||
sendField,
|
||||
field
|
||||
field,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -48,13 +48,10 @@ export type Labels = {
|
||||
|
||||
export type Validate<T = any> = (value?: T, options?: any) => string | true | Promise<string | true>;
|
||||
|
||||
export type OptionObject = {
|
||||
export type Option = {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export type Option = OptionObject | string
|
||||
|
||||
export interface FieldBase {
|
||||
name: string;
|
||||
label?: string | false;
|
||||
|
||||
Reference in New Issue
Block a user