Skip to content

Commit

Permalink
Add proportional column component.
Browse files Browse the repository at this point in the history
  • Loading branch information
jameswilddev committed Jul 22, 2024
1 parent 27e01a1 commit 3706c8c
Show file tree
Hide file tree
Showing 8 changed files with 1,164 additions and 2 deletions.
2 changes: 2 additions & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export { createNullableTextInputComponent } from './react-native/components/crea
export { createOfflineTableComponent } from './react-native/components/createOfflineTableComponent'
export { createPaddingComponent } from './react-native/components/createPaddingComponent'
export { createPickerButtonComponent } from './react-native/components/createPickerButtonComponent'
export { createProportionalColumnComponent } from './react-native/components/createProportionalColumnComponent'
export { createProportionalRowComponent } from './react-native/components/createProportionalRowComponent'
export { createRequiredEmailInputComponent } from './react-native/components/createRequiredEmailInputComponent'
export { createRequiredFloatInputComponent } from './react-native/components/createRequiredFloatInputComponent'
Expand Down Expand Up @@ -149,6 +150,7 @@ export type { PreflightResponse } from './react-native/types/PreflightResponse'
export type { PreflightResponseCollection } from './react-native/types/PreflightResponseCollection'
export type { PreflightResponseCollectionItem } from './react-native/types/PreflightResponseCollectionItem'
export type { PreflightResponseSingleton } from './react-native/types/PreflightResponseSingleton'
export type { ProportionalColumnProps } from './react-native/types/ProportionalColumnProps'
export type { ProportionalRowProps } from './react-native/types/ProportionalRowProps'
export type { PushingSyncableStateCollectionItem } from './react-native/types/PushingSyncableStateCollectionItem'
export type { QueryParameter } from './react-native/types/QueryParameter'
Expand Down
139 changes: 139 additions & 0 deletions react-native/components/createProportionalColumnComponent/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import * as React from 'react'
import { StyleSheet, View, type ViewStyle } from 'react-native'
import type { ProportionalColumnProps } from '../../types/ProportionalColumnProps'

const globalStyles = StyleSheet.create({
fillsContainerLeft: {
width: '100%',
height: '100%',
flexDirection: 'column',
alignItems: 'flex-start'
},
fillsContainerCentered: {
width: '100%',
height: '100%',
flexDirection: 'column',
alignItems: 'center'
},
fillsContainerRight: {
width: '100%',
height: '100%',
flexDirection: 'column',
alignItems: 'flex-end'
},
fillsContainerStretched: {
width: '100%',
height: '100%',
flexDirection: 'column',
alignItems: 'stretch'
},
fitsContentLeft: {
height: '100%',
flexDirection: 'column',
alignItems: 'flex-start'
},
fitsContentCentered: {
height: '100%',
flexDirection: 'column',
alignItems: 'center'
},
fitsContentRight: {
height: '100%',
flexDirection: 'column',
alignItems: 'flex-end'
},
fitsContentStretched: {
height: '100%',
flexDirection: 'column',
alignItems: 'stretch'
}
})

/**
* Creates a new React component which fills its container verticall and
* presents a fixed set of rows with proportional height and optional spacing.
* @template T Keys representing the rows within.
* @param spacing The spacing between the rows.
* @param widths The proportional heights of the rows.
* @returns The created React component.
*/
export function createProportionalColumnComponent<T extends readonly never[]> (
spacing: number,
widths: { [TKey in keyof T]: number }
): React.FunctionComponent<ProportionalColumnProps<T>> {
const viewStyles: Array<{ readonly view: ViewStyle }> = []

for (const width of widths) {
viewStyles.push(
StyleSheet.create({
view: {
flexBasis: 0,
flexGrow: width
}
})
)
}

const localStyles = StyleSheet.create({
spacer: {
flexBasis: spacing
}
})

const ProportionalColumn: React.FunctionComponent<ProportionalColumnProps<T>> = ({ width, horizontalAlignment, children }) => {
const intercalatedChildren: Array<null | JSX.Element> = []

let index = 0

for (const view of children) {
if (index > 0 && spacing !== 0) {
intercalatedChildren.push(
<View
key={`separator${index - 1}`}
style={localStyles.spacer}
pointerEvents="none"
/>
)
}

intercalatedChildren.push(
<View
key={String(index)}
pointerEvents="box-none"
style={viewStyles[index]?.view}
>
{view}
</View>
)

index++
}

return (
<View
style={
width === 'fitsContent'
? horizontalAlignment === 'left'
? globalStyles.fitsContentLeft
: horizontalAlignment === 'centered'
? globalStyles.fitsContentCentered
: horizontalAlignment === 'right'
? globalStyles.fitsContentRight
: globalStyles.fitsContentStretched
: horizontalAlignment === 'left'
? globalStyles.fillsContainerLeft
: horizontalAlignment === 'centered'
? globalStyles.fillsContainerCentered
: horizontalAlignment === 'right'
? globalStyles.fillsContainerRight
: globalStyles.fillsContainerStretched
}
pointerEvents="box-none"
>
{intercalatedChildren}
</View>
)
}

return ProportionalColumn
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# `react-native-app-helpers/createProportionalColumnComponent`

Creates a new React component which fills its container vertically and presents
a fixed set of rows with proportional width and optional spacing.

## Usage

```tsx
import { createProportionalColumnComponent } from "react-native-app-helpers";

const ExampleComponent = createProportionalColumnComponent(23, [27, 18, 33, 44]);

const ExampleScreen = () => (
<ExampleComponent width="fitsContent" horizontalAlignment="top">
<Text>
This is 27/122 of the height.
</Text>
<Text>
This is 18/122 of the height.
</Text>
<Text>
This is 33/122 of the height.
</Text>
<Text>
This is 44/122 of the height.
</Text>
</ExampleComponent>
);
```

```tsx
import { createProportionalColumnComponent } from "react-native-app-helpers";

const ExampleComponent = createProportionalColumnComponent(23, [27, 18, 33, 44]);

const ExampleScreen = () => (
<ExampleComponent width="fillsContainer" horizontalAlignment="centered">
<Text>
This is 27/122 of the height.
</Text>
<Text>
This is 18/122 of the height.
</Text>
<Text>
This is 33/122 of the height.
</Text>
<Text>
This is 44/122 of the height.
</Text>
</ExampleComponent>
);
```

```tsx
import { createProportionalColumnComponent } from "react-native-app-helpers";

const ExampleComponent = createProportionalColumnComponent(23, [27, 18, 33, 44]);

const ExampleScreen = () => (
<ExampleComponent width="fillsContainer" horizontalAlignment="bottom">
<Text>
This is 27/122 of the height.
</Text>
<Text>
This is 18/122 of the height.
</Text>
<Text>
This is 33/122 of the height.
</Text>
<Text>
This is 44/122 of the height.
</Text>
</ExampleComponent>
);
```

```tsx
import { createProportionalColumnComponent } from "react-native-app-helpers";

const ExampleComponent = createProportionalColumnComponent(23, [27, 18, 33, 44]);

const ExampleScreen = () => (
<ExampleComponent width="fillsContainer" horizontalAlignment="stretched">
<Text>
This is 27/122 of the height.
</Text>
<Text>
This is 18/122 of the height.
</Text>
<Text>
This is 33/122 of the height.
</Text>
<Text>
This is 44/122 of the height.
</Text>
</ExampleComponent>
);
```
Loading

0 comments on commit 3706c8c

Please sign in to comment.