Skip to content

Commit

Permalink
Inline useSpaceStyle implementation into Space component
Browse files Browse the repository at this point in the history
  • Loading branch information
samholmes committed May 27, 2024
1 parent 5f8edf0 commit 3ee59b8
Showing 1 changed file with 90 additions and 10 deletions.
100 changes: 90 additions & 10 deletions src/components/layout/Space.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,100 @@
import * as React from 'react'
import { View } from 'react-native'
import { useMemo } from 'react'
import { View, ViewStyle } from 'react-native'

import { SpaceProps, useSpaceStyle } from '../../hooks/useSpaceStyle'
import { MarginRemProps, MarginRemStyle, useMarginRemStyle } from '../../hooks/useMarginRemStyle'

interface OwnProps {
export interface SpaceProps extends MarginRemProps {
// Single-sided:
/** Align children to the top */
alignBottom?: boolean
/** Align children to the top */
alignLeft?: boolean
/** Align children to the right */
alignRight?: boolean
/** Align children to the top */
alignTop?: boolean

// Multiple-sided:
/** Aligns children to the center */
alignCenter?: boolean
/** Aligns children to the center horizontally */
alignHorizontal?: boolean
/** Aligns children to the center vertically */
alignVertical?: boolean

// Children:
children?: React.ReactNode

/**
* The `expand` space prop tells a component to expand its size within its
* parent component.
*
* This is particularly useful when you want to use the space props to
* align the component.
*/
expand?: boolean

/**
* Changes the orientation of child component layout from column
* (top-to-bottom) to row (left-to-right).
*
* The `row` prop is an additional, non-space props useful managing the
* stacking direction of child components. By default, child components stack
* vertically (column-based), from top to bottom. If `row={true}`, then
* child components stack horizontally (row-based).
*
* The `row` prop does not affect the alignment or rem props (i.e. vertical
* is always vertical regardless of the value set for the `row` prop).
*/
row?: boolean
}
type Props = OwnProps & SpaceProps

/**
* Numbers are rem units, and boolean means to fill up assigned space; this
* allows for centering and alignment (see useSpaceStyle hook for details).
*/
export const Space = React.memo((props: Props) => {
type SpaceStyle = Pick<ViewStyle, 'flex' | 'flexDirection' | 'alignItems' | 'justifyContent'> & MarginRemStyle

export const Space = React.memo((props: SpaceProps) => {
const { children } = props
const spaceStyle = useSpaceStyle(props)
const { aroundRem, horizontalRem, verticalRem, topRem, bottomRem, leftRem, rightRem, expand = false, row = false } = props
const { alignBottom, alignLeft, alignRight, alignTop, alignCenter, alignHorizontal, alignVertical } = props

const topFill = boolify(alignBottom, alignVertical, alignCenter)
const bottomFill = boolify(alignTop, alignVertical, alignCenter)
const leftFill = boolify(alignRight, alignHorizontal, alignCenter)
const rightFill = boolify(alignLeft, alignHorizontal, alignCenter)

// Margins:
const marginRemStyle = useMarginRemStyle({ bottomRem, leftRem, rightRem, topRem, aroundRem, horizontalRem, verticalRem })

// Direction:
const flexDirection = row ? 'row' : 'column'

// Alignment:
const horizontalAlignment = leftFill && rightFill ? 'center' : rightFill ? 'flex-start' : leftFill ? 'flex-end' : undefined
const verticalAlignment = topFill && bottomFill ? 'center' : bottomFill ? 'flex-start' : topFill ? 'flex-end' : undefined
const alignItems = row ? verticalAlignment : horizontalAlignment
const justifyContent = row ? horizontalAlignment ?? (expand ? 'space-between' : undefined) : verticalAlignment

// Flex:
const alignSelf = expand ? 'stretch' : undefined
const flexGrow = expand ? 1 : undefined

const spaceStyle: SpaceStyle = useMemo(
() => ({
alignSelf,
alignItems,
flexGrow,
flexDirection,
justifyContent,
...marginRemStyle
}),
[alignItems, alignSelf, flexDirection, flexGrow, justifyContent, marginRemStyle]
)

return <View style={spaceStyle}>{children}</View>
})

const boolify = (...things: Array<boolean | undefined>): boolean => {
return things.some(thing => {
return typeof thing === 'boolean' && thing
})
}

0 comments on commit 3ee59b8

Please sign in to comment.