Update List and Selectbox components to support different data id type and custom label rendering
All checks were successful
forgejo/Procyon/procyon/pipeline/head This commit looks good
All checks were successful
forgejo/Procyon/procyon/pipeline/head This commit looks good
This commit is contained in:
parent
451adb4942
commit
fbbdc3825c
6 changed files with 51 additions and 23 deletions
|
@ -5,15 +5,16 @@ import { FlatList, GestureResponderEvent, StyleProp, ViewStyle } from 'react-nat
|
|||
import { ListItem, ListItemProps } from '@procyon/components/ListItem';
|
||||
|
||||
export type ListData = {
|
||||
id: number;
|
||||
label: string;
|
||||
id: number | string;
|
||||
label?: string;
|
||||
};
|
||||
|
||||
export type ListProps<Items extends ListData[]> = {
|
||||
Item?: FC<ListItemProps<Items[0]>>;
|
||||
Item?: FC<ListItemProps<Items[0] | ListData>>;
|
||||
color?: 'primary' | 'secondary' | 'positive' | 'negative';
|
||||
compact?: boolean;
|
||||
data?: Items;
|
||||
getLabel?: (items: Items[0]) => string;
|
||||
mode?: 'view' | 'interactive';
|
||||
onClick?: (event: GestureResponderEvent, id: ListData['id']) => void;
|
||||
selected?: ListData['id'];
|
||||
|
@ -28,6 +29,7 @@ export const List = <Items extends ListData[]>({
|
|||
style,
|
||||
data,
|
||||
selected,
|
||||
getLabel,
|
||||
Item = ListItem,
|
||||
...props
|
||||
}: ListProps<Items>) => {
|
||||
|
@ -38,10 +40,10 @@ export const List = <Items extends ListData[]>({
|
|||
style={[style?.list]}
|
||||
renderItem={({ item }) => (
|
||||
<Item {...props} item={item} selected={item.id === selected}>
|
||||
{item.label}
|
||||
{item.label ? item.label : getLabel?.(item)}
|
||||
</Item>
|
||||
)}
|
||||
keyExtractor={(item) => item.label.toString()}
|
||||
keyExtractor={(item) => item.id.toString()}
|
||||
/>
|
||||
</ListContainer>
|
||||
);
|
||||
|
|
|
@ -5,19 +5,24 @@ import { GestureResponderEvent, StyleProp, View, ViewProps } from 'react-native'
|
|||
import { useAnimatedRef } from 'react-native-reanimated';
|
||||
import Values from 'values.js';
|
||||
|
||||
import { ListData, ListProps } from '@procyon/components/List';
|
||||
import { ListData } from '@procyon/components/List';
|
||||
import { RippleEffect } from '@procyon/components/RippleEffect';
|
||||
import { isDark } from '@procyon/utils/color';
|
||||
import { debounceAfter } from '@procyon/utils/debounce';
|
||||
|
||||
export type ListItemProps<Item> = {
|
||||
export type ListItemProps<Item extends ListData> = {
|
||||
children: ReactNode;
|
||||
color?: 'primary' | 'secondary' | 'positive' | 'negative';
|
||||
compact?: boolean;
|
||||
item: Item;
|
||||
mode?: 'view' | 'interactive';
|
||||
onClick?: (event: GestureResponderEvent, id: ListData['id']) => void;
|
||||
selected?: boolean;
|
||||
size?: 'sm' | 'md' | 'lg' | 'xl';
|
||||
style?: {
|
||||
container?: StyleProp<ViewProps>;
|
||||
};
|
||||
} & Omit<ListProps<any>, 'selected' | 'data' | 'style' | 'Item'>;
|
||||
};
|
||||
|
||||
export const ListItem = <Item extends ListData>({
|
||||
style,
|
||||
|
|
|
@ -11,11 +11,14 @@ import { InputElementType } from '@procyon/types/form';
|
|||
|
||||
import { TextField, TextFieldProps } from './TextField';
|
||||
|
||||
export type SelectboxProps<Items extends ListData[]> = InputElementType<number> & {
|
||||
export type SelectboxProps<Items extends ListData[]> = InputElementType<
|
||||
number | string
|
||||
> & {
|
||||
Input?: FC<TextFieldProps & { data: Items }>;
|
||||
Item?: FC<ListItemProps<Items[0]>>;
|
||||
clearable?: boolean;
|
||||
data?: Items;
|
||||
getLabel?: (items: Items[0]) => string;
|
||||
};
|
||||
|
||||
export const Selectbox = <Items extends ListData[]>(props: SelectboxProps<Items>) => {
|
||||
|
@ -28,6 +31,7 @@ export const Selectbox = <Items extends ListData[]>(props: SelectboxProps<Items>
|
|||
data,
|
||||
Input = FieldInput,
|
||||
Item,
|
||||
getLabel,
|
||||
...others
|
||||
} = props;
|
||||
|
||||
|
@ -42,9 +46,10 @@ export const Selectbox = <Items extends ListData[]>(props: SelectboxProps<Items>
|
|||
Item={Item}
|
||||
selected={value}
|
||||
data={data}
|
||||
onClick={(event, value) => {
|
||||
getLabel={getLabel}
|
||||
onClick={(event, id) => {
|
||||
event.preventDefault();
|
||||
onChange?.(event, value);
|
||||
onChange?.(event, id);
|
||||
closeModal();
|
||||
}}
|
||||
style={{
|
||||
|
@ -99,7 +104,14 @@ export const Selectbox = <Items extends ListData[]>(props: SelectboxProps<Items>
|
|||
onFocus={(e) => {
|
||||
others.onFocus?.(e, value);
|
||||
}}
|
||||
Input={(props) => <Input {...props} data={data} value={value?.toString()} />}
|
||||
Input={(props) => (
|
||||
<Input
|
||||
{...props}
|
||||
data={data as any}
|
||||
getLabel={getLabel}
|
||||
value={value?.toString()}
|
||||
/>
|
||||
)}
|
||||
message={message}
|
||||
onClick={handleOpenOptions}
|
||||
RightIcon={(props) => (
|
||||
|
@ -114,10 +126,18 @@ export const Selectbox = <Items extends ListData[]>(props: SelectboxProps<Items>
|
|||
);
|
||||
};
|
||||
|
||||
const FieldInput: FC<TextFieldProps & { data: SelectboxProps<any>['data'] }> = ({
|
||||
const FieldInput = <Items extends ListData[]>({
|
||||
value,
|
||||
data,
|
||||
}) => <FieldText>{data?.find((item) => item.id === value)?.label}</FieldText>;
|
||||
getLabel,
|
||||
}: TextFieldProps & {
|
||||
data?: SelectboxProps<Items>['data'];
|
||||
getLabel?: SelectboxProps<Items>['getLabel'];
|
||||
}) => {
|
||||
const item = data?.find((item) => item.id === value && !!value);
|
||||
if (!item) return null;
|
||||
return <FieldText>{getLabel ? getLabel(item) : item.label}</FieldText>;
|
||||
};
|
||||
|
||||
const FieldText = styled.Text<{
|
||||
size?: SelectboxProps<any>['size'];
|
||||
|
|
|
@ -36,7 +36,7 @@ export const Default: Story = {
|
|||
onClick={onValueChange}
|
||||
data={[
|
||||
{
|
||||
id: 1,
|
||||
id: 'aa',
|
||||
label: 'Tiger',
|
||||
},
|
||||
{
|
||||
|
@ -114,7 +114,7 @@ export const Custom: Story = {
|
|||
<ListItem item={item} color="negative">
|
||||
<ListItemView>
|
||||
<FlagIcon color="red" strokeWidth={1} />
|
||||
<ListItemText style={[{ fontWeight: 'bold' }]}>{value}</ListItemText>
|
||||
<ListItemText style={[{ fontWeight: 'bold' }]}>{children}</ListItemText>
|
||||
</ListItemView>
|
||||
</ListItem>
|
||||
);
|
||||
|
|
|
@ -40,8 +40,8 @@ export const Default: Story = {
|
|||
name: 'name1',
|
||||
label: 'I am Selectbox',
|
||||
data: [
|
||||
{ value: 'item1', name: 'Item 1' },
|
||||
{ value: 'item2', name: 'Item 2' },
|
||||
{ id: 'item1', label: 'Item 1' },
|
||||
{ id: 'item2', label: 'Item 2' },
|
||||
],
|
||||
},
|
||||
render: function Component(args) {
|
||||
|
|
|
@ -13,7 +13,7 @@ type FormData = {
|
|||
checkbox: boolean;
|
||||
datePicker: Date;
|
||||
radiobutton: string;
|
||||
selectBox: string;
|
||||
selectBox: number;
|
||||
text: string;
|
||||
timePicker: Date;
|
||||
};
|
||||
|
@ -23,7 +23,7 @@ export const ExampleForm = () => {
|
|||
text: yup.string().required(),
|
||||
checkbox: yup.boolean().required(),
|
||||
radiobutton: yup.string().required(),
|
||||
selectBox: yup.string().required(),
|
||||
selectBox: yup.number().required(),
|
||||
datePicker: yup.date().required(),
|
||||
timePicker: yup.date().required(),
|
||||
});
|
||||
|
@ -32,7 +32,7 @@ export const ExampleForm = () => {
|
|||
schema,
|
||||
defaultValues: {
|
||||
text: 'Hello',
|
||||
selectBox: 'item2',
|
||||
selectBox: 2,
|
||||
datePicker: new Date(),
|
||||
timePicker: new Date(),
|
||||
checkbox: true,
|
||||
|
@ -73,9 +73,10 @@ export const ExampleForm = () => {
|
|||
component="SELECT"
|
||||
name="selectBox"
|
||||
label="SelectBox"
|
||||
getLabel={({ name }) => name}
|
||||
data={[
|
||||
{ value: 'item1', name: 'Item 1' },
|
||||
{ value: 'item2', name: 'Item 2' },
|
||||
{ id: 1, name: 'Item 1' },
|
||||
{ id: 2, name: 'Item 2' },
|
||||
]}
|
||||
/>
|
||||
</GridCol>
|
||||
|
|
Loading…
Add table
Reference in a new issue