Remove DatePicker and Selectbox modal components
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
11cb5d65db
commit
2763fb6ab2
25 changed files with 10318 additions and 7977 deletions
|
@ -42,6 +42,7 @@
|
|||
"react-native-svg": "15.1.0",
|
||||
"react-native-web": "0.19.12",
|
||||
"scroll-into-view-if-needed": "3.0.10",
|
||||
"lucide-react-native": "^0.379.0",
|
||||
"tiny-invariant": "1.3.3",
|
||||
"values.js": "^2.1.1",
|
||||
"wouter": "2.12.1",
|
||||
|
@ -88,7 +89,6 @@
|
|||
"esprima": "4.0.1",
|
||||
"http-server": "14.1.1",
|
||||
"jest": "29.7.0",
|
||||
"lucide-react-native": "^0.379.0",
|
||||
"nightwatch": "3.3.5",
|
||||
"postcss-cli": "11.0.0",
|
||||
"postcss-loader": "8.1.0",
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
"@emotion/styled": "^11.11.5",
|
||||
"clsx": "2.1.0",
|
||||
"date-fns": "3.3.1",
|
||||
"lucide-react-native": "^0.379.0",
|
||||
"ramda": "0.29.1",
|
||||
"scroll-into-view-if-needed": "3.1.0",
|
||||
"react-native-reanimated": "3.7.0",
|
||||
|
|
|
@ -193,7 +193,7 @@ export function Calendar({
|
|||
}, [workDate, type, View, layout, onClick]);
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
<Grid style={{ gap: 6 }}>
|
||||
{!isNilOrEmpty(title) && (
|
||||
<GridRow>
|
||||
<GridCol>
|
||||
|
@ -237,5 +237,6 @@ const CalendarWeekContainer = styled(GridRow)(() => {
|
|||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
};
|
||||
});
|
||||
|
|
|
@ -85,10 +85,10 @@ const CalendarDateContainer = styled.View<{
|
|||
}>(({ theme, type, isSelected, isToday, isOtherMonth }) => {
|
||||
return {
|
||||
borderRadius: theme.spacing.sm,
|
||||
backgroundColor: theme.palette.base.main,
|
||||
margin: 1,
|
||||
|
||||
...(isToday && {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
}),
|
||||
...(isOtherMonth &&
|
||||
type !== 'months' && {
|
||||
|
@ -114,7 +114,6 @@ const CalendarDateText = styled.Text<{
|
|||
|
||||
...(isToday && {
|
||||
color: theme.palette.primary.light,
|
||||
fontWeight: 'bold',
|
||||
}),
|
||||
...(isOtherMonth &&
|
||||
type !== 'months' && {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { format, format as formatFn, parse } from 'date-fns';
|
||||
import { CalendarFoldIcon } from 'lucide-react-native';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { useModal } from '@procyon/components/Modal/context';
|
||||
import { Calendar } from '@procyon/components/Calendar';
|
||||
import { InputElementType } from '@procyon/types/form';
|
||||
import { IMask, Masked } from '@procyon/utils/imask';
|
||||
|
||||
import { TextField } from '../TextField';
|
||||
import { DatePickerModal } from './DatePickerModal';
|
||||
import { TextField } from './TextField';
|
||||
|
||||
export const DEFAULT_DATE_FORMAT = 'dd.MM.yyyy';
|
||||
|
||||
|
@ -33,35 +33,16 @@ export const DatePicker: React.FC<DatePickerProps> = ({
|
|||
return undefined;
|
||||
};
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const [value, setValue] = useState<string | undefined>(formatValue(others.value));
|
||||
|
||||
const [openModal, closeModal] = useModal(name, {
|
||||
style: { container: { width: 400 } },
|
||||
});
|
||||
const [toggle, setToggle] = useState<boolean>(false);
|
||||
|
||||
const handleDateClick = (value: Date): void => {
|
||||
const handleDateClick = (value: Date) => {
|
||||
onChange?.(value);
|
||||
setValue(formatValue(value));
|
||||
};
|
||||
|
||||
const modalComponent = useCallback(
|
||||
(props) => (
|
||||
<DatePickerModal
|
||||
format={dateFormat}
|
||||
name={name}
|
||||
value={others.value}
|
||||
closeModal={closeModal}
|
||||
onChange={handleDateClick}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
[format, name, others.value],
|
||||
);
|
||||
|
||||
const handleOpenModal = (): void => {
|
||||
openModal({
|
||||
Component: modalComponent,
|
||||
});
|
||||
setToggle(false);
|
||||
};
|
||||
|
||||
const mask =
|
||||
|
@ -96,13 +77,14 @@ export const DatePicker: React.FC<DatePickerProps> = ({
|
|||
});
|
||||
|
||||
return (
|
||||
<View style={{ position: 'relative' }}>
|
||||
<TextField
|
||||
name={name}
|
||||
label={label}
|
||||
placeholder={dateFormat}
|
||||
LeftIcon={(props) => (
|
||||
<View style={{ cursor: 'pointer' } as any}>
|
||||
<CalendarFoldIcon onClick={handleOpenModal} {...props} />
|
||||
<CalendarFoldIcon onClick={() => setToggle(!toggle)} {...props} />
|
||||
</View>
|
||||
)}
|
||||
{...others}
|
||||
|
@ -115,5 +97,27 @@ export const DatePicker: React.FC<DatePickerProps> = ({
|
|||
setValue(value ?? undefined);
|
||||
}}
|
||||
/>
|
||||
{toggle && (
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
position: 'absolute',
|
||||
top: 65,
|
||||
margin: theme.spacing.sm,
|
||||
marginHorizontal: 0,
|
||||
padding: theme.spacing.md,
|
||||
borderColor: theme.palette.primary.main,
|
||||
borderWidth: 1,
|
||||
borderRadius: theme.rounded.md,
|
||||
},
|
||||
]}>
|
||||
<Calendar
|
||||
onClick={handleDateClick}
|
||||
value={others.value}
|
||||
selected={others.value}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
import React, { FC, useCallback } from 'react';
|
||||
|
||||
import { Calendar } from '../Calendar';
|
||||
import { ModalId } from '../Modal/context';
|
||||
|
||||
export type DatePickerModalProps = {
|
||||
closeModal: () => void;
|
||||
format: ModalId;
|
||||
name: ModalId;
|
||||
onChange: (value: Date) => void;
|
||||
value: Date | undefined;
|
||||
};
|
||||
|
||||
export const DatePickerModal: FC<DatePickerModalProps> = (props) => {
|
||||
const { onChange, closeModal, value } = props;
|
||||
|
||||
const setActiveOption = useCallback(
|
||||
(value: Date) => {
|
||||
onChange?.(value);
|
||||
closeModal();
|
||||
},
|
||||
[onChange, closeModal],
|
||||
);
|
||||
|
||||
return (
|
||||
<Calendar selected={value ?? undefined} value={value} onClick={setActiveOption} />
|
||||
);
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
export { DatePicker, DatePickerProps } from './DatePicker';
|
|
@ -47,8 +47,6 @@ const GridColContainer = styled.View<{
|
|||
const br = mQ(theme);
|
||||
|
||||
return {
|
||||
padding: 2,
|
||||
|
||||
...br.xs({
|
||||
flex: (100 / getSize('xs', gridCols)) * getSize('xs', cols),
|
||||
}),
|
||||
|
|
|
@ -36,7 +36,7 @@ export const ListItem: FC<ListItemProps> = ({
|
|||
|
||||
const handleClick = debounceAfter(() => {
|
||||
onClick?.(value, children);
|
||||
}, 200);
|
||||
}, 100);
|
||||
|
||||
const rippleColor = useMemo(() => {
|
||||
const val = new Values(theme.palette[color!].main);
|
||||
|
@ -59,7 +59,14 @@ export const ListItem: FC<ListItemProps> = ({
|
|||
style={[style?.container]}
|
||||
onPress={handleClick}
|
||||
ref={rippleAnimationRef}>
|
||||
<RippleEffect ref={rippleAnimationRef} color={rippleColor}>
|
||||
<RippleEffect
|
||||
ref={rippleAnimationRef}
|
||||
color={rippleColor}
|
||||
style={{
|
||||
container: {
|
||||
padding: theme.spacing.md,
|
||||
},
|
||||
}}>
|
||||
{typeof children === 'string' ? (
|
||||
<ListItemView>
|
||||
<ListItemText color={color} size={size}>
|
||||
|
@ -67,7 +74,7 @@ export const ListItem: FC<ListItemProps> = ({
|
|||
</ListItemText>
|
||||
</ListItemView>
|
||||
) : (
|
||||
<ListItemView>{children}</ListItemView>
|
||||
children
|
||||
)}
|
||||
</RippleEffect>
|
||||
</ListItemContainer>
|
||||
|
@ -82,6 +89,7 @@ const ListItemContainer = styled.Pressable<{
|
|||
return {
|
||||
borderBottomWidth: 1,
|
||||
borderColor: theme.palette.primary.light,
|
||||
backgroundColor: theme.palette.base.light,
|
||||
|
||||
...(selected && {
|
||||
backgroundColor: theme.palette[color!].light,
|
||||
|
@ -92,9 +100,11 @@ const ListItemContainer = styled.Pressable<{
|
|||
};
|
||||
});
|
||||
|
||||
const ListItemView = styled.View(({ theme }) => {
|
||||
export const ListItemView = styled.View(() => {
|
||||
return {
|
||||
padding: theme.spacing.md,
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ import styled from '@emotion/native';
|
|||
import { View } from 'react-native';
|
||||
|
||||
import { Label } from '@procyon/components/Label';
|
||||
import { RadioItem } from '@procyon/components/RadioButton/RadioItem';
|
||||
import { RadioItem } from '@procyon/components/RadioItem';
|
||||
import { InputElementType } from '@procyon/types/form';
|
||||
|
||||
import { FieldMessage } from '../FieldMessage';
|
||||
import { FieldMessage } from './FieldMessage';
|
||||
|
||||
export type RadioButtonProps = Omit<
|
||||
{
|
|
@ -1,2 +0,0 @@
|
|||
export { RadioButton, RadioButtonProps } from './RadioButton';
|
||||
export { RadioItem, RadioItemProps } from './RadioItem';
|
|
@ -3,7 +3,7 @@ import styled from '@emotion/native';
|
|||
import { useTheme } from '@emotion/react';
|
||||
import { CircleCheckIcon, CircleIcon } from 'lucide-react-native';
|
||||
|
||||
import { RadioButtonProps } from '@procyon/components/RadioButton/RadioButton';
|
||||
import { RadioButtonProps } from '@procyon/components/RadioButton';
|
||||
|
||||
export type RadioItemProps = {
|
||||
children: string;
|
122
packages/components/src/Selectbox.tsx
Normal file
122
packages/components/src/Selectbox.tsx
Normal file
|
@ -0,0 +1,122 @@
|
|||
import React, {
|
||||
Children,
|
||||
FC,
|
||||
isValidElement,
|
||||
ReactNode,
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import styled from '@emotion/native';
|
||||
import { ChevronDownIcon } from 'lucide-react-native';
|
||||
import { Platform, Pressable, View } from 'react-native';
|
||||
|
||||
import { List, ListProps } from '@procyon/components/List';
|
||||
import { ListItem } from '@procyon/components/ListItem';
|
||||
import { InputElementType } from '@procyon/types/form';
|
||||
|
||||
import { TextField, TextFieldProps } from './TextField';
|
||||
|
||||
export type SelectboxProps = Omit<
|
||||
InputElementType<string> & {
|
||||
children: ReactNode;
|
||||
clearable?: boolean;
|
||||
onChange?: (value: string) => void;
|
||||
style?: {
|
||||
input?: TextFieldProps['style'];
|
||||
list?: ListProps['style'];
|
||||
};
|
||||
},
|
||||
'onFocus' | 'onClick' | 'onBlur'
|
||||
>;
|
||||
|
||||
const findPreSelectedItems = (children: ReactNode, initValue: string): ReactNode => {
|
||||
return Children.map(Children.toArray(children), (child: ReactNode) => {
|
||||
const elementChild = child as ReactNode;
|
||||
if (isValidElement(elementChild)) {
|
||||
if (elementChild.type === ListItem && elementChild.props.value === initValue) {
|
||||
return elementChild.props.children;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
export const Selectbox: FC<SelectboxProps> = (props) => {
|
||||
const { value, onChange, label, children, message, ...others } = props;
|
||||
|
||||
const [toggle, setToggle] = useState<boolean>(false);
|
||||
const [renderValue, setRenderValue] = useState<ReactNode>(null);
|
||||
|
||||
const handleClick = (value: string, renderValue: ReactNode) => {
|
||||
setRenderValue(renderValue);
|
||||
onChange?.(value);
|
||||
setToggle(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setRenderValue(findPreSelectedItems(children, value));
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={{ position: 'relative' }}>
|
||||
<TextField
|
||||
{...others}
|
||||
style={{
|
||||
...(props.style?.input ?? {}),
|
||||
input: [],
|
||||
}}
|
||||
label={label}
|
||||
Input={(props) =>
|
||||
typeof renderValue === 'string' ? (
|
||||
<FieldText {...props} style={[props.style?.input]}>
|
||||
{renderValue}
|
||||
</FieldText>
|
||||
) : (
|
||||
renderValue ?? <View />
|
||||
)
|
||||
}
|
||||
message={message}
|
||||
onClick={() => setToggle(!toggle)}
|
||||
RightIcon={(props) => (
|
||||
<Pressable
|
||||
onPressIn={() => setToggle(!toggle)}
|
||||
style={[Platform.OS === 'web' && { cursor: 'pointer' }]}>
|
||||
<ChevronDownIcon {...props} />
|
||||
</Pressable>
|
||||
)}
|
||||
/>
|
||||
{toggle && (
|
||||
<List
|
||||
{...others}
|
||||
selected={value}
|
||||
onClick={handleClick}
|
||||
style={{
|
||||
container: [
|
||||
{
|
||||
position: 'absolute',
|
||||
top: 65,
|
||||
width: '100%',
|
||||
marginHorizontal: 0,
|
||||
},
|
||||
props.style?.list?.container,
|
||||
],
|
||||
}}>
|
||||
{children}
|
||||
</List>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const FieldText = styled.Text<{
|
||||
size: SelectboxProps['size'];
|
||||
}>(({ theme, size }) => {
|
||||
return {
|
||||
...(Platform.OS === 'web' && { cursor: 'pointer' }),
|
||||
color: theme.palette.text.main,
|
||||
fontFamily: theme.fontFamily,
|
||||
fontSize: theme.fontSize[size!],
|
||||
};
|
||||
});
|
|
@ -1,120 +0,0 @@
|
|||
import React, { Children, FC, isValidElement, ReactNode, useEffect } from 'react';
|
||||
import { mergeDeepRight } from 'ramda';
|
||||
import styled from '@emotion/native';
|
||||
import { PointerIcon } from 'lucide-react-native';
|
||||
import { Pressable, View } from 'react-native';
|
||||
|
||||
import { ListItem } from '@procyon/components/ListItem';
|
||||
import { Modal, useModal } from '@procyon/components/Modal/context';
|
||||
import { SelectboxProvider, useSelectbox } from '@procyon/components/Selectbox/context';
|
||||
import { InputElementType } from '@procyon/types/form';
|
||||
|
||||
import { TextField, TextFieldProps } from '../TextField';
|
||||
import { SelectboxModal, SelectboxModalProps } from './SelectboxModal';
|
||||
|
||||
export type SelectboxProps = Omit<
|
||||
InputElementType<string> & {
|
||||
children: ReactNode;
|
||||
clearable?: boolean;
|
||||
onChange?: (value: string) => void;
|
||||
style?: {
|
||||
input?: TextFieldProps['style'];
|
||||
list?: SelectboxModalProps['style'];
|
||||
modal?: Modal<any>['style'];
|
||||
};
|
||||
},
|
||||
'onFocus' | 'onClick' | 'onBlur'
|
||||
>;
|
||||
|
||||
const findPreSelectedItems = (children: ReactNode, initValue: string): ReactNode => {
|
||||
return Children.map(Children.toArray(children), (child: ReactNode) => {
|
||||
const elementChild = child as ReactNode;
|
||||
if (isValidElement(elementChild)) {
|
||||
if (elementChild.type === ListItem && elementChild.props.value === initValue) {
|
||||
return elementChild.props.children;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
const SelectboxComponent: FC<SelectboxProps> = (props) => {
|
||||
const { value, onChange, name, label, children, message, ...others } = props;
|
||||
|
||||
const { renderValue, setRenderValue } = useSelectbox();
|
||||
|
||||
const handleClick = (value: string, renderValue: ReactNode) => {
|
||||
setRenderValue(renderValue);
|
||||
onChange?.(value);
|
||||
};
|
||||
|
||||
const handleOptionRemove = () => {
|
||||
onChange?.(undefined);
|
||||
};
|
||||
|
||||
const [openModal, closeModal] = useModal(name, {
|
||||
style: mergeDeepRight({ container: { maxWidth: 300 } }, props.style?.modal ?? {}),
|
||||
Component: (modalProps: object) => (
|
||||
<SelectboxModal
|
||||
name={name!}
|
||||
closeModal={closeModal}
|
||||
onChange={handleClick}
|
||||
onRemove={handleOptionRemove}
|
||||
style={props.style?.list}
|
||||
clearable={props.clearable}
|
||||
value={value}
|
||||
{...modalProps}>
|
||||
{children}
|
||||
</SelectboxModal>
|
||||
),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setRenderValue(findPreSelectedItems(children, value));
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<TextField
|
||||
{...others}
|
||||
style={{
|
||||
...props.style,
|
||||
input: [],
|
||||
}}
|
||||
label={label}
|
||||
Input={(props) => (
|
||||
<FieldText {...props} style={[props.style?.input]}>
|
||||
{renderValue ?? <View />}
|
||||
</FieldText>
|
||||
)}
|
||||
message={message}
|
||||
onClick={() => openModal()}
|
||||
RightIcon={(props) => (
|
||||
<Pressable
|
||||
onPress={() => openModal()}
|
||||
style={[{ cursor: 'pointer' } as any]}
|
||||
{...props}>
|
||||
<PointerIcon />
|
||||
</Pressable>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const Selectbox: FC<SelectboxProps> = ({ children, ...props }) => (
|
||||
<SelectboxProvider>
|
||||
<SelectboxComponent {...props}>{children}</SelectboxComponent>
|
||||
</SelectboxProvider>
|
||||
);
|
||||
|
||||
const FieldText = styled.Text<{
|
||||
size: SelectboxProps['size'];
|
||||
}>(({ theme, size }) => {
|
||||
return {
|
||||
cursor: 'pointer' as any,
|
||||
color: theme.palette.text.main,
|
||||
fontFamily: theme.fontFamily,
|
||||
fontSize: theme.fontSize[size!],
|
||||
};
|
||||
});
|
|
@ -1,66 +0,0 @@
|
|||
import React, { FC, ReactNode } from 'react';
|
||||
import { mergeDeepRight } from 'ramda';
|
||||
import { TrashIcon } from 'lucide-react-native';
|
||||
|
||||
import { List, ListProps } from '@procyon/components/List';
|
||||
|
||||
import { Button } from '../Button';
|
||||
import { ModalId } from '../Modal/context';
|
||||
|
||||
export type SelectboxModalProps = {
|
||||
children: ReactNode;
|
||||
clearable?: boolean;
|
||||
closeModal: () => void;
|
||||
name: ModalId;
|
||||
onChange: (value: string, renderValue: ReactNode) => void;
|
||||
onRemove: () => void;
|
||||
style?: {
|
||||
container: NonNullable<ListProps['style']>['container'];
|
||||
};
|
||||
value?: string;
|
||||
};
|
||||
|
||||
export const SelectboxModal: FC<SelectboxModalProps> = ({
|
||||
onChange,
|
||||
onRemove,
|
||||
closeModal,
|
||||
style,
|
||||
clearable,
|
||||
value,
|
||||
children,
|
||||
...others
|
||||
}) => {
|
||||
const handleChange = (value: string, renderValue: ReactNode) => {
|
||||
onChange(value, renderValue);
|
||||
closeModal();
|
||||
};
|
||||
|
||||
const removeActiveOption = (): void => {
|
||||
onRemove();
|
||||
closeModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<List
|
||||
{...others}
|
||||
selected={value}
|
||||
onClick={handleChange}
|
||||
style={mergeDeepRight(
|
||||
{
|
||||
container: {
|
||||
maxHeight: 250,
|
||||
},
|
||||
},
|
||||
style ?? {},
|
||||
)}>
|
||||
{children}
|
||||
</List>
|
||||
{clearable && (
|
||||
<Button size="sm" color="negative" onClick={removeActiveOption} variant="text">
|
||||
<TrashIcon fontSize={20} />
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,34 +0,0 @@
|
|||
import React, {
|
||||
createContext,
|
||||
Dispatch,
|
||||
FC,
|
||||
ReactNode,
|
||||
SetStateAction,
|
||||
useContext,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
export type SelectboxContext = {
|
||||
renderValue: ReactNode | null;
|
||||
setRenderValue: Dispatch<SetStateAction<ReactNode | null>>;
|
||||
};
|
||||
|
||||
const SelectboxContext = createContext<SelectboxContext>({} as any);
|
||||
|
||||
export type SelectboxProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const SelectboxProvider: FC<SelectboxProviderProps> = ({ children, ...props }) => {
|
||||
const [renderValue, setRenderValue] = useState(null);
|
||||
|
||||
return (
|
||||
<SelectboxContext.Provider value={{ renderValue, setRenderValue, ...props }}>
|
||||
{children}
|
||||
</SelectboxContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useSelectbox = () => {
|
||||
return useContext(SelectboxContext);
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
export { Selectbox, SelectboxProps } from './Selectbox';
|
|
@ -1,11 +1,10 @@
|
|||
import React, { FC, useState } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import styled from '@emotion/native';
|
||||
import { Theme, useTheme } from '@emotion/react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import {
|
||||
InputModeOptions,
|
||||
Pressable,
|
||||
StyleProp,
|
||||
Text,
|
||||
TextInputFocusEventData,
|
||||
TextStyle,
|
||||
View,
|
||||
|
@ -73,8 +72,6 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
loading,
|
||||
} = props;
|
||||
|
||||
const [focused, setFocused] = useState(false);
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
const applyMask = (val: typeof props.value) => {
|
||||
|
@ -93,12 +90,10 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
|
||||
const handleFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
||||
onFocus?.(e.nativeEvent.text, e);
|
||||
setFocused(true);
|
||||
};
|
||||
|
||||
const handleBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>): void => {
|
||||
onBlur?.(e.nativeEvent.text, e);
|
||||
setFocused(false);
|
||||
};
|
||||
|
||||
const handleChange = (e: NativeSyntheticEvent<TextInputChangeEventData>): void => {
|
||||
|
@ -115,17 +110,17 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
{label}
|
||||
</Label>
|
||||
<Skeleton active={loading || false} layout={[{ key: '1', height: 40 }]}>
|
||||
<TextFieldWrapper color={color} disabled={disabled} focused={focused}>
|
||||
<TextFieldWrapper color={color} disabled={disabled}>
|
||||
{LeftIcon && (
|
||||
<TextFieldIconContainer style={[style?.icon]}>
|
||||
<LeftIcon style={[textFieldIcon({ icon: true, color, size, theme })]} />
|
||||
<TextFieldIconContainer>
|
||||
<LeftIcon style={[style?.icon]} color={theme.palette[color!].main} />
|
||||
</TextFieldIconContainer>
|
||||
)}
|
||||
{leftText && (
|
||||
<TextFieldIconContainer>
|
||||
<Text style={[textFieldIcon({ icon: false, color, size, theme })]}>
|
||||
<TextFieldText color={color} size={size}>
|
||||
{leftText}
|
||||
</Text>
|
||||
</TextFieldText>
|
||||
</TextFieldIconContainer>
|
||||
)}
|
||||
<Pressable
|
||||
|
@ -159,15 +154,15 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
/>
|
||||
</Pressable>
|
||||
{RightIcon && (
|
||||
<TextFieldIconContainer style={[style?.icon]}>
|
||||
<RightIcon style={[textFieldIcon({ icon: true, color, size, theme })]} />
|
||||
<TextFieldIconContainer>
|
||||
<RightIcon style={[style?.icon]} color={theme.palette[color!].main} />
|
||||
</TextFieldIconContainer>
|
||||
)}
|
||||
{rightText && (
|
||||
<TextFieldIconContainer>
|
||||
<Text style={[textFieldIcon({ icon: false, color, size, theme })]}>
|
||||
<TextFieldText color={color} size={size}>
|
||||
{rightText}
|
||||
</Text>
|
||||
</TextFieldText>
|
||||
</TextFieldIconContainer>
|
||||
)}
|
||||
</TextFieldWrapper>
|
||||
|
@ -180,8 +175,7 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
const TextFieldWrapper = styled.View<{
|
||||
color: TextFieldProps['color'];
|
||||
disabled: boolean;
|
||||
focused: boolean;
|
||||
}>(({ theme, color, focused, disabled }) => {
|
||||
}>(({ theme, color, disabled }) => {
|
||||
return {
|
||||
height: 40,
|
||||
display: 'flex',
|
||||
|
@ -190,11 +184,11 @@ const TextFieldWrapper = styled.View<{
|
|||
borderRadius: theme.rounded.sm - 1,
|
||||
paddingHorizontal: theme.spacing.lg,
|
||||
borderWidth: 2,
|
||||
borderColor: new Values(theme.palette[color!].main).tint(80).rgbString(),
|
||||
borderColor: new Values(theme.palette[color!].main).tint(30).rgbString(),
|
||||
backgroundColor: new Values(theme.palette[color!].light).tint(50).rgbString(),
|
||||
|
||||
...(focused && {
|
||||
borderColor: new Values(theme.palette[color!].main).tint(30).rgbString(),
|
||||
...(color === 'primary' && {
|
||||
backgroundColor: theme.palette.base.light,
|
||||
}),
|
||||
|
||||
...(disabled && {
|
||||
|
@ -225,18 +219,13 @@ const TextFieldIconContainer = styled.View(() => {
|
|||
};
|
||||
});
|
||||
|
||||
const textFieldIcon = ({
|
||||
icon,
|
||||
theme,
|
||||
color,
|
||||
size,
|
||||
}: {
|
||||
const TextFieldText = styled.Text<{
|
||||
color: TextFieldProps['color'];
|
||||
icon: boolean;
|
||||
size: TextFieldProps['size'];
|
||||
theme: Theme;
|
||||
}) => ({
|
||||
}>(({ theme, color, size }) => {
|
||||
return {
|
||||
color: theme.palette[color!].main,
|
||||
fontSize: theme.fontSize[size!] + (icon ? 4 : 0),
|
||||
fontSize: theme.fontSize[size!],
|
||||
fontFamily: theme.fontFamily,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -12,7 +12,13 @@ export const Typography: FC<TypographyProps> = ({ children, size = 'h5' }) => {
|
|||
|
||||
const TypographyText = styled.Text<{
|
||||
size: TypographyProps['size'];
|
||||
}>(({ size, theme }) => {
|
||||
}>(
|
||||
({ theme }) => {
|
||||
return {
|
||||
fontFamily: theme.fontFamily,
|
||||
};
|
||||
},
|
||||
({ size, theme }) => {
|
||||
switch (size) {
|
||||
case 'h1': {
|
||||
return {
|
||||
|
@ -48,4 +54,5 @@ const TypographyText = styled.Text<{
|
|||
return {};
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useController, useFormContext } from 'react-hook-form';
|
|||
|
||||
import { Checkbox } from '@procyon/components/Checkbox';
|
||||
import { DatePicker } from '@procyon/components/DatePicker';
|
||||
import { RadioButton } from '@procyon/components/RadioButton/RadioButton';
|
||||
import { RadioButton } from '@procyon/components/RadioButton';
|
||||
import { Selectbox } from '@procyon/components/Selectbox';
|
||||
import { TextField } from '@procyon/components/TextField';
|
||||
import { TimePicker } from '@procyon/components/TimePicker';
|
||||
|
|
|
@ -2,7 +2,7 @@ import { FieldValues, SubmitErrorHandler, SubmitHandler } from 'react-hook-form'
|
|||
|
||||
import { CheckboxProps } from '@procyon/components/Checkbox';
|
||||
import { DatePickerProps } from '@procyon/components/DatePicker';
|
||||
import { RadioButtonProps } from '@procyon/components/RadioButton/RadioButton';
|
||||
import { RadioButtonProps } from '@procyon/components/RadioButton';
|
||||
import { SelectboxProps } from '@procyon/components/Selectbox';
|
||||
import { TextFieldProps } from '@procyon/components/TextField';
|
||||
import { TimePickerProps } from '@procyon/components/TimePicker';
|
||||
|
|
17610
pnpm-lock.yaml
generated
17610
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,8 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { RadioButton } from '@procyon/components/RadioButton/RadioButton';
|
||||
import { RadioItem } from '@procyon/components/RadioButton/RadioItem';
|
||||
import { RadioButton } from '@procyon/components/RadioButton';
|
||||
import { RadioItem } from '@procyon/components/RadioItem';
|
||||
|
||||
type Story = StoryObj<typeof RadioButton>;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { Text, View } from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
|
||||
import { ListItem, ListItemValue } from '@procyon/components/ListItem';
|
||||
import { ListItem, ListItemText } from '@procyon/components/ListItem';
|
||||
import { ModalProvider } from '@procyon/components/Modal/context';
|
||||
import { Modals } from '@procyon/components/Modal/Modals';
|
||||
import { Selectbox } from '@procyon/components/Selectbox';
|
||||
|
@ -41,26 +41,21 @@ export const Default: Story = {
|
|||
label: 'I am Selectbox',
|
||||
},
|
||||
render: function Component(args) {
|
||||
const [value, setValue] = useState<ListItemValue | undefined>(undefined);
|
||||
const [value, setValue] = useState<string | undefined>(undefined);
|
||||
|
||||
const onValueChange = (item: ListItemValue) => {
|
||||
const onValueChange = (item: string) => {
|
||||
args.onChange?.(item);
|
||||
setValue(item);
|
||||
};
|
||||
|
||||
return (
|
||||
<Selectbox value={value} {...args} onChange={onValueChange}>
|
||||
<ListItem id="item1" value="Item 1">
|
||||
Item 1
|
||||
</ListItem>
|
||||
<ListItem id="item2" value="Item 2" color="negative">
|
||||
<ListItem value="Item 1">Item 1</ListItem>
|
||||
<ListItem value="Item 2" color="negative">
|
||||
Item 2
|
||||
</ListItem>
|
||||
<ListItem id="item3" value="Doplhin">
|
||||
<View>
|
||||
<Text style={{ fontSize: 20 }}>Doplhin</Text>
|
||||
</View>
|
||||
<Text>Is a smart animal</Text>
|
||||
<ListItem value="Doplhin">
|
||||
<ListItemText style={{ fontSize: 20 }}>Doplhin</ListItemText>
|
||||
</ListItem>
|
||||
</Selectbox>
|
||||
);
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { FlagIcon } from 'lucide-react-native';
|
||||
import { View } from 'react-native';
|
||||
import * as yup from 'yup';
|
||||
|
||||
import { Button } from '@procyon/components/Button';
|
||||
import { Grid, GridCol, GridRow } from '@procyon/components/Grid';
|
||||
import { ListItem, ListItemText } from '@procyon/components/ListItem';
|
||||
import { ListItem, ListItemText, ListItemView } from '@procyon/components/ListItem';
|
||||
import { Puzzle } from '@procyon/components/Puzzle';
|
||||
import { RadioItem } from '@procyon/components/RadioButton';
|
||||
import { RadioItem } from '@procyon/components/RadioItem';
|
||||
import { Field, FieldWrapper } from '@procyon/forms/Field';
|
||||
import { Form } from '@procyon/forms/Form';
|
||||
import { useForm } from '@procyon/forms/useForm';
|
||||
|
@ -63,16 +62,10 @@ export const ExampleForm = () => {
|
|||
<Field component="SELECT" name="selectBox" label="SelectBox">
|
||||
<ListItem value="item1">Item 1</ListItem>
|
||||
<ListItem value="item2" color="negative">
|
||||
<View
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
}}>
|
||||
<ListItemView style={{ gap: 6 }}>
|
||||
<FlagIcon color="black" fill="red" strokeWidth={1} />
|
||||
<ListItemText>Item 2</ListItemText>
|
||||
</View>
|
||||
</ListItemView>
|
||||
</ListItem>
|
||||
</Field>
|
||||
<Field component="DATE" name="datePicker" label="DatePicker" />
|
||||
|
|
Loading…
Add table
Reference in a new issue