Skip to content

Commit

Permalink
Flex typing fixes and improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Madumo committed Oct 2, 2024
1 parent 8443478 commit 1ab1b12
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 158 deletions.
50 changes: 0 additions & 50 deletions template/src/components/kit/card/Card.tsx

This file was deleted.

1 change: 0 additions & 1 deletion template/src/components/kit/card/index.ts

This file was deleted.

173 changes: 85 additions & 88 deletions template/src/components/kit/flex/Flex.tsx
Original file line number Diff line number Diff line change
@@ -1,108 +1,105 @@
import { ForwardedRef, forwardRef } from 'react';
import {
FlexStyle,
StyleProp,
StyleSheet,
View,
ViewStyle,
} from 'react-native';
import { Padding, PolymorphicComponentProps } from '../shared/types';
import { getPaddingStyle } from '../shared/utils';
import { GapContext, useGap } from './GapContext';
import {
ComponentWithViewStyle,
Padding,
PolymorphicComponentProps,
Radius,
} from '../shared/types';
import { getPaddingStyle, getRadiusStyle } from '../shared/utils';
import { FlexGap } from './types';
import { getFlexDirection, getGapStyle } from './utils';

export type FlexProps<C extends React.ElementType> = PolymorphicComponentProps<
C,
{
row?: boolean;
reverse?: boolean;
gap?: FlexGap;
padding?: Padding;
align?: FlexStyle['alignItems'];
alignSelf?: FlexStyle['alignSelf'];
justify?: FlexStyle['justifyContent'];
grow?: number | boolean;
shrink?: number | boolean;
basis?: FlexStyle['flexBasis'];
wrap?: boolean;
absolute?: boolean;
zIndex?: ViewStyle['zIndex'];
top?: ViewStyle['top'];
left?: ViewStyle['left'];
bottom?: ViewStyle['bottom'];
right?: ViewStyle['right'];
width?: ViewStyle['width'];
height?: ViewStyle['height'];
fill?: boolean;
}
>;

export type FlexComponent = <C extends React.ElementType = typeof View>(
props: FlexProps<C>
) => React.ReactElement | null;
export type FlexProps<C extends ComponentWithViewStyle = typeof View> =
PolymorphicComponentProps<
C,
{
row?: boolean;
reverse?: boolean;
gap?: FlexGap;
padding?: Padding;
align?: FlexStyle['alignItems'];
alignSelf?: FlexStyle['alignSelf'];
justify?: FlexStyle['justifyContent'];
grow?: number | boolean;
shrink?: number | boolean;
basis?: FlexStyle['flexBasis'];
wrap?: boolean;
absolute?: boolean;
zIndex?: number;
top?: FlexStyle['top'];
left?: FlexStyle['left'];
bottom?: FlexStyle['bottom'];
right?: FlexStyle['right'];
width?: FlexStyle['width'];
height?: FlexStyle['height'];
fill?: boolean;
radius?: Radius;
background?: ViewStyle['backgroundColor'];
style?: StyleProp<ViewStyle>;
}
>;

export const Flex = forwardRef(
<C extends React.ElementType = typeof View>(
export const Flex = <C extends ComponentWithViewStyle = typeof View>({
as,
row = false,
reverse = false,
gap,
padding,
align = 'stretch',
alignSelf = 'auto',
justify = 'flex-start',
grow = 0,
shrink = 0,
basis = 'auto',
wrap = false,
absolute = false,
zIndex,
top,
left,
bottom,
right,
width,
height,
fill = false,
radius,
background,
style,
forwardedRef,
...props
}: FlexProps<C>) => {
const Comp = as || View;
const finalStyle: StyleProp<ViewStyle> = [
getPaddingStyle(padding),
getGapStyle(gap),
getRadiusStyle(radius),
{
as,
row = false,
reverse = false,
gap,
padding,
align = 'stretch',
alignSelf = 'auto',
justify = 'flex-start',
grow = 0,
shrink = 0,
basis = 'auto',
wrap = false,
absolute = false,
flexGrow: Number(grow),
flexShrink: Number(shrink),
flexBasis: basis,
alignItems: align,
alignSelf,
justifyContent: justify,
flexDirection: getFlexDirection(row, reverse),
flexWrap: wrap ? 'wrap' : 'nowrap',
position: absolute ? 'absolute' : 'relative',
zIndex,
top,
left,
bottom,
right,
width,
height,
fill = false,
style,
...props
}: FlexProps<C>,
ref?: ForwardedRef<C>
) => {
const Comp = as || View;
const inheritedGap = useGap();
const finalGap = typeof gap === 'number' ? gap : inheritedGap;
const finalStyle: StyleProp<ViewStyle> = [
getPaddingStyle(padding),
getGapStyle(finalGap),
{
flexGrow: Number(grow),
flexShrink: Number(shrink),
flexBasis: basis,
alignItems: align,
alignSelf,
justifyContent: justify,
flexDirection: getFlexDirection(row, reverse),
flexWrap: wrap ? 'wrap' : 'nowrap',
position: absolute ? 'absolute' : 'relative',
zIndex,
top,
left,
bottom,
right,
width,
height,
},
fill ? StyleSheet.absoluteFill : null,
style,
];
backgroundColor: background,
},
fill ? StyleSheet.absoluteFill : null,
style,
];

return (
<GapContext.Provider value={finalGap}>
<Comp ref={ref} style={finalStyle} {...props} />
</GapContext.Provider>
);
}
);
return <Comp ref={forwardedRef} style={finalStyle} {...props} />;
};
8 changes: 0 additions & 8 deletions template/src/components/kit/flex/GapContext.tsx

This file was deleted.

1 change: 0 additions & 1 deletion template/src/components/kit/flex/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './Flex';
export * from './GapContext';
export * from './types';
export * from './utils';
1 change: 0 additions & 1 deletion template/src/components/kit/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './activity-indicator';
export * from './bottom-sheet';
export * from './button';
export * from './card';
export * from './date-time';
export * from './flex';
export * from './icon';
Expand Down
31 changes: 25 additions & 6 deletions template/src/components/kit/shared/types.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,47 @@
import { StyleProp, ViewStyle } from 'react-native';

export type Padding =
| number
| [vertical: number, horizontal: number]
| [top: number, horizontal: number, bottom: number]
| [top: number, right: number, bottom: number, left: number];

export type Radius =
| number
| [topLeftAndBottomRight: number, topRightAndBottomLeft: number]
| [topLeft: number, topRightAndBottomLeft: number, bottomRight: number]
| [
topLeft: number,
topRight: number,
bottomRight: number,
bottomLeft: number
];

export type Size = number | [number, number];

export type AsProp<C extends React.ElementType> = {
as?: C;
};

export type ForwardedRefProp<C extends React.ElementType> = {
forwardedRef?: PolymorphicRef<C>;
};

export type PropsToOmit<C extends React.ElementType, P> = keyof (AsProp<C> & P);

export type PolymorphicComponentProps<
C extends React.ElementType,
Props = {}
C extends ComponentWithViewStyle<Props>,
Props extends { style?: Style } = {},
Style extends StyleProp<ViewStyle> = StyleProp<ViewStyle>
> = Props &
AsProp<C> &
ForwardedRefProp<C> &
Omit<React.ComponentPropsWithoutRef<C>, PropsToOmit<C, Props>>;

export type PolymorphicComponentPropsWithRef<
C extends React.ElementType,
Props = {}
> = PolymorphicComponentProps<C, Props> & { ref?: PolymorphicRef<C> };
export type ComponentWithViewStyle<
Props extends { style?: Style } = {},
Style extends StyleProp<ViewStyle> = StyleProp<ViewStyle>
> = React.JSXElementConstructor<Props>;

export type PolymorphicRef<C extends React.ElementType> =
React.ComponentPropsWithRef<C>['ref'];
40 changes: 39 additions & 1 deletion template/src/components/kit/shared/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ViewStyle } from 'react-native';
import { Padding, Size } from './types';
import { Padding, Radius, Size } from './types';

export function getPaddingStyle(padding?: Padding): ViewStyle | null {
if (padding === undefined) {
Expand All @@ -24,6 +24,44 @@ export function getPaddingStyle(padding?: Padding): ViewStyle | null {
return { paddingTop, paddingRight, paddingBottom, paddingLeft };
}

export function getRadiusStyle(radius?: Radius): ViewStyle | null {
if (radius === undefined) {
return null;
}

if (typeof radius === 'number') {
return { borderRadius: radius };
}

if (radius.length === 2) {
const [topLeftAndBottomRight, topRightAndBottomLeft] = radius;
return {
borderTopLeftRadius: topLeftAndBottomRight,
borderTopRightRadius: topRightAndBottomLeft,
borderBottomRightRadius: topLeftAndBottomRight,
borderBottomLeftRadius: topRightAndBottomLeft,
};
}

if (radius.length === 3) {
const [topLeft, topRightAndBottomLeft, bottomRight] = radius;
return {
borderTopLeftRadius: topLeft,
borderTopRightRadius: topRightAndBottomLeft,
borderBottomRightRadius: bottomRight,
borderBottomLeftRadius: topRightAndBottomLeft,
};
}

const [topLeft, topRight, bottomRight, bottomLeft] = radius;
return {
borderTopLeftRadius: topLeft,
borderTopRightRadius: topRight,
borderBottomRightRadius: bottomRight,
borderBottomLeftRadius: bottomLeft,
};
}

export function getSizeStyle(
size?: Size
): Pick<ViewStyle, 'width' | 'height'> | null {
Expand Down
Loading

0 comments on commit 1ab1b12

Please sign in to comment.