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

This commit is contained in:
Roman Jaroš 2024-06-16 20:39:40 +00:00
parent 451adb4942
commit fbbdc3825c
6 changed files with 51 additions and 23 deletions

View file

@ -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>
);

View file

@ -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,

View file

@ -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'];

View file

@ -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>
);

View file

@ -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) {

View file

@ -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>