From edae8f89e1b297e4d754b5d71b228bd92be8b723 Mon Sep 17 00:00:00 2001 From: Nicolas Torion Date: Fri, 18 Oct 2024 15:34:51 +0200 Subject: [PATCH] Added Slider component --- example/app/components/Slider.tsx | 34 ++++++++ example/app/items.ts | 6 ++ example/package.json | 1 + example/pnpm-lock.yaml | 7 ++ package.json | 1 + pnpm-lock.yaml | 7 ++ src/components/index.ts | 2 + src/components/slider/slider.component.tsx | 92 ++++++++++++++++++++++ src/components/slider/slider.style.tsx | 53 +++++++++++++ src/components/slider/slider.type.tsx | 31 ++++++++ src/theme/type.ts | 4 +- 11 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 example/app/components/Slider.tsx create mode 100644 src/components/slider/slider.component.tsx create mode 100644 src/components/slider/slider.style.tsx create mode 100644 src/components/slider/slider.type.tsx diff --git a/example/app/components/Slider.tsx b/example/app/components/Slider.tsx new file mode 100644 index 0000000..e416c05 --- /dev/null +++ b/example/app/components/Slider.tsx @@ -0,0 +1,34 @@ +import React, { useState } from 'react'; +import { SafeAreaView } from 'react-native'; +import { Slider, Text } from 'react-native-ficus-ui'; +import ExampleSection from '@/src/ExampleSection'; + +const SliderComponent = () => { + const [value, setValue] = useState(0.2); + + return ( + + + Slider + + + + + + + + + + + Slider value : {Math.round(value * 100) / 100} + + + + + + + + ); +}; + +export default SliderComponent; diff --git a/example/app/items.ts b/example/app/items.ts index 463567c..a36904e 100644 --- a/example/app/items.ts +++ b/example/app/items.ts @@ -28,6 +28,7 @@ import ScrollBoxComponent from './components/ScrollBox'; import BadgeComponent from './components/Badge'; import AvatarComponent from './components/Avatar'; import PinInputComponent from './components/PinInput'; +import SliderComponent from './components/Slider'; type ExampleComponentType = { onScreenName: string; @@ -161,4 +162,9 @@ export const components: ExampleComponentType[] = [ onScreenName: 'Modal', component: ModalComponent, }, + { + navigationPath: 'Slider', + onScreenName: 'Slider', + component: SliderComponent, + }, ]; diff --git a/example/package.json b/example/package.json index bcc3097..2d8368a 100644 --- a/example/package.json +++ b/example/package.json @@ -51,6 +51,7 @@ "@shopify/flash-list": "1.5.0", "color": "4.2.3", "deepmerge": "4.2.2", + "@react-native-community/slider": "4.5.4", "react-native-animatable": "1.3.3", "react-native-modal": "13.0.1", "react-native-toast-message": "2.1.6", diff --git a/example/pnpm-lock.yaml b/example/pnpm-lock.yaml index f71f595..ac4490b 100644 --- a/example/pnpm-lock.yaml +++ b/example/pnpm-lock.yaml @@ -8,6 +8,9 @@ dependencies: '@expo/vector-icons': specifier: ^14.0.2 version: 14.0.2 + '@react-native-community/slider': + specifier: 4.5.4 + version: 4.5.4 '@react-navigation/native': specifier: ^6.0.2 version: 6.1.18(react-native@0.74.5)(react@18.2.0) @@ -2625,6 +2628,10 @@ packages: - utf-8-validate dev: false + /@react-native-community/slider@4.5.4: + resolution: {integrity: sha512-TFhwnrp0LTFG90yat8mqEOBLLMJylpnchO5F0KusH8dI0VzViIVIXOzhnx0mUVqLvRwRPbqBB0tvhxd739UhmA==} + dev: false + /@react-native/assets-registry@0.74.87: resolution: {integrity: sha512-1XmRhqQchN+pXPKEKYdpJlwESxVomJOxtEnIkbo7GAlaN2sym84fHEGDXAjLilih5GVPpcpSmFzTy8jx3LtaFg==} engines: {node: '>=18'} diff --git a/package.json b/package.json index 208cf1b..95130a7 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "registry": "https://registry.npmjs.org/" }, "dependencies": { + "@react-native-community/slider": "4.5.4", "@shopify/flash-list": "1.5.0", "color": "4.2.3", "deepmerge": "4.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e21464..80f72fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ overrides: '@types/react': 18.2.14 dependencies: + '@react-native-community/slider': + specifier: 4.5.4 + version: 4.5.4 '@shopify/flash-list': specifier: 1.5.0 version: 1.5.0(@babel/runtime@7.25.4)(react-native@0.72.1)(react@18.2.0) @@ -2452,6 +2455,10 @@ packages: resolution: {integrity: sha512-+zDZ20NUnSWghj7Ku5aFphMzuM9JulqCW+aPXT6IfIXFbb8tzYTTOSeRFOtuekJ99ibW2fUCSsjuKNlwDIbHFg==} dev: true + /@react-native-community/slider@4.5.4: + resolution: {integrity: sha512-TFhwnrp0LTFG90yat8mqEOBLLMJylpnchO5F0KusH8dI0VzViIVIXOzhnx0mUVqLvRwRPbqBB0tvhxd739UhmA==} + dev: false + /@react-native/assets-registry@0.72.0: resolution: {integrity: sha512-Im93xRJuHHxb1wniGhBMsxLwcfzdYreSZVQGDoMJgkd6+Iky61LInGEHnQCTN0fKNYF1Dvcofb4uMmE1RQHXHQ==} diff --git a/src/components/index.ts b/src/components/index.ts index dc72af5..73198ac 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -68,3 +68,5 @@ export { RadioProps, RadioGroupProps } from './radio/radio.type'; export { RadioGroup } from './radio/group.component'; export { Modal } from './modal/modal.component'; export { ModalProps } from './modal/modal.type'; +export { Slider } from './slider/slider.component'; +export { SliderProps } from './slider/slider.type'; diff --git a/src/components/slider/slider.component.tsx b/src/components/slider/slider.component.tsx new file mode 100644 index 0000000..37ca1f5 --- /dev/null +++ b/src/components/slider/slider.component.tsx @@ -0,0 +1,92 @@ +import * as React from 'react'; +import RNSlider from '@react-native-community/slider'; + +import { getStyle } from './slider.style'; +import type { SliderProps } from './slider.type'; +import { useTheme } from '../../theme/theme.hook'; +import { useDefaultProps } from '../../utilities/useDefaultProps'; +import { handleResponsiveProps } from '../../types'; +import { getThemeColor } from '../../theme/theme.service'; + +const Slider: React.FunctionComponent = (incomingProps) => { + const { theme, windowWidth } = useTheme(); + const props = useDefaultProps( + 'Slider', + handleResponsiveProps(incomingProps, theme, windowWidth), + { + flexDirection: 'column', + flexWrap: 'nowrap', + min: 0, + max: 1, + filledTrackColor: 'gray.200', + colorScheme: 'blue', + } + ); + + const { + bg, + h, + w, + m, + mt, + mr, + mb, + ml, + ms, + p, + pr, + pt, + pb, + pl, + minH, + minW, + maxW, + maxH, + position, + style, + flexDirection, + direction, + children, + bgImg, + bgMode, + alignItems, + align, + justifyContent, + justify, + flexWrap, + wrap, + flexGrow, + grow, + flexBasis, + basis, + flexShrink, + shrink, + opacity, + top, + left, + right, + bottom, + zIndex, + min, + max, + colorScheme, + filledTrackColor, + defaultValue, + ...rest + } = props; + const computedStyle = getStyle(theme, props); + + return ( + + ); +}; + +export { Slider }; diff --git a/src/components/slider/slider.style.tsx b/src/components/slider/slider.style.tsx new file mode 100644 index 0000000..412bafb --- /dev/null +++ b/src/components/slider/slider.style.tsx @@ -0,0 +1,53 @@ +import { StyleSheet } from 'react-native'; + +import { + createPositionStyle, + createSpacingStyles, + getThemeColor, +} from '../../theme/theme.service'; +import type { SliderProps } from './slider.type'; +import type { ThemeType } from '../../theme/type'; + +/** + * computed style + * + * @param theme + * @param props + */ +export const getStyle = (theme: ThemeType, props: SliderProps) => { + const computedStyle: any = {}; + + computedStyle.slider = { + flexDirection: props.direction ? props.direction : props.flexDirection, + flexWrap: props.wrap ? props.wrap : props.flexWrap, + alignItems: props.align ? props.align : props.alignItems, + justifyContent: props.justify ? props.justify : props.justifyContent, + flexBasis: props.basis ? props.basis : props.flexBasis, + flexGrow: props.grow ? props.grow : props.flexGrow, + flexShrink: props.shrink ? props.shrink : props.flexShrink, + height: props.h, + width: props.w, + minWidth: props.minW, + minHeight: props.minH, + alignSelf: props.alignSelf, + maxWidth: props.maxW, + maxHeight: props.maxH, + opacity: props.opacity, + zIndex: props.zIndex, + backgroundColor: getThemeColor(theme.colors, props.bg as string), + flex: props.flex, + ...createPositionStyle(props), + ...createSpacingStyles(props, theme.spacing), + }; + + // merging custom style props to computed style + if (props.style) { + computedStyle.slider = { + ...computedStyle.slider, + // @ts-ignore + ...props.style, + }; + } + + return StyleSheet.create(computedStyle); +}; diff --git a/src/components/slider/slider.type.tsx b/src/components/slider/slider.type.tsx new file mode 100644 index 0000000..e798afe --- /dev/null +++ b/src/components/slider/slider.type.tsx @@ -0,0 +1,31 @@ +import type { ViewProps as RNViewProps } from 'react-native'; +import type { SliderProps as RNSliderProps } from '@react-native-community/slider'; + +import type { + SpacingPropsType, + DimensionPropsType, + BackgroundPropsType, + FlexPropsType, + PositionPropsType, + ZIndexPropsType, + OpacityPropsType, + VariantPropsType, +} from '../../types'; + +export interface SliderProps + extends RNViewProps, + RNSliderProps, + SpacingPropsType, + DimensionPropsType, + BackgroundPropsType, + FlexPropsType, + PositionPropsType, + ZIndexPropsType, + OpacityPropsType, + VariantPropsType { + min?: number; + max?: number; + defaultValue?: number; + filledTrackColor?: string; + colorScheme?: string; +} diff --git a/src/theme/type.ts b/src/theme/type.ts index f3ce7b6..4a29e92 100644 --- a/src/theme/type.ts +++ b/src/theme/type.ts @@ -31,8 +31,9 @@ import type { ModalProps } from 'components/modal/modal.type'; import { ToastProps } from 'react-native-toast-message'; import type { DividerProps } from 'components/divider/divider.type'; import { BadgeProps } from 'components/badge/badge.type'; -import { AvatarProps } from 'components'; +import { SliderProps } from 'components/slider/slider.type'; import { + AvatarProps, AvatarBadgeProps, AvatarGroupProps, } from 'components/avatar/avatar.type'; @@ -89,6 +90,7 @@ export interface ThemeType { RadioGroup?: VariantType; Modal?: VariantType; Divider?: VariantType; + Slider?: VariantType; }; fontFamily?: {