Created
September 4, 2020 17:15
-
-
Save chaance/7ea95688de8024fb2131b5ab69dace09 to your computer and use it in GitHub Desktop.
Interop flex concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
import omit from 'lodash.omit'; | |
import { cssReset, isUndefined } from '@interop-ui/utils'; | |
import { forwardRef, createStyleObj } from '@interop-ui/react-utils'; | |
/* ------------------------------------------------------------------------------------------------- | |
* Flex | |
* -----------------------------------------------------------------------------------------------*/ | |
const FLEX_NAME = 'Flex'; | |
const FLEX_DEFAULT_TAG = 'div'; | |
const GAP_PROP_NAMES = ['rowGap', 'columnGap', 'gap']; | |
type FlexDOMProps = React.ComponentPropsWithoutRef<typeof FLEX_DEFAULT_TAG>; | |
type FlexOwnProps = { rowGap?: number; columnGap?: number; gap?: number }; | |
type FlexProps = FlexDOMProps & FlexOwnProps; | |
interface FlexStaticProps { | |
Item: typeof FlexItem; | |
} | |
const FlexContext = React.createContext<{ | |
rowGap?: number; | |
columnGap?: number; | |
}>(null as any); | |
const Flex = forwardRef<typeof FLEX_DEFAULT_TAG, FlexProps, FlexStaticProps>(function Flex( | |
props, | |
forwardedRef | |
) { | |
const { as: Comp = FLEX_DEFAULT_TAG, style, children, ...restProps } = props; | |
const flexProps = omit(restProps, GAP_PROP_NAMES); | |
const columnGap = props.gap ?? props.columnGap; | |
const rowGap = props.gap ?? props.rowGap; | |
const hasGap = !isUndefined(rowGap) || !isUndefined(columnGap); | |
const context = React.useMemo(() => ({ columnGap, rowGap }), [columnGap, rowGap]); | |
if (hasGap) { | |
return ( | |
<div style={{ overflow: 'hidden', flexGrow: 1 }}> | |
<Comp | |
{...flexProps} | |
{...interopDataAttrObj('root')} | |
ref={forwardedRef} | |
style={{ | |
...style, | |
marginTop: isUndefined(rowGap) ? undefined : -rowGap, | |
marginLeft: isUndefined(columnGap) ? undefined : -columnGap, | |
}} | |
> | |
<FlexContext.Provider value={context}>{children}</FlexContext.Provider> | |
</Comp> | |
</div> | |
); | |
} | |
return ( | |
<Comp {...flexProps} {...interopDataAttrObj('root')} style={style} ref={forwardedRef}> | |
{children} | |
</Comp> | |
); | |
}); | |
/* ------------------------------------------------------------------------------------------------- | |
* FlexItem | |
* -----------------------------------------------------------------------------------------------*/ | |
const ITEM_NAME = 'Flex.Item'; | |
const ITEM_DEFAULT_TAG = 'div'; | |
type FlexItemDOMProps = React.ComponentPropsWithoutRef<typeof ITEM_DEFAULT_TAG>; | |
type FlexItemOwnProps = { xOffset?: number; yOffset?: number }; | |
type FlexItemProps = FlexItemDOMProps & FlexItemOwnProps; | |
const FlexItem = forwardRef<typeof ITEM_DEFAULT_TAG, FlexItemProps>(function FlexItem( | |
props, | |
forwardedRef | |
) { | |
const { as: Comp = ITEM_DEFAULT_TAG, style, xOffset = 0, yOffset = 0, ...itemProps } = props; | |
const { rowGap, columnGap } = React.useContext(FlexContext) || {}; | |
return ( | |
<Comp | |
{...itemProps} | |
{...interopDataAttrObj('item')} | |
ref={forwardedRef} | |
style={{ | |
...style, | |
marginTop: isUndefined(rowGap) ? undefined : rowGap + yOffset, | |
marginLeft: isUndefined(columnGap) ? undefined : columnGap + xOffset, | |
}} | |
/> | |
); | |
}); | |
Flex.Item = FlexItem; | |
Flex.displayName = FLEX_NAME; | |
Flex.Item.displayName = ITEM_NAME; | |
const [styles, interopDataAttrObj] = createStyleObj(FLEX_NAME, { | |
root: { | |
...cssReset(FLEX_DEFAULT_TAG), | |
display: 'flex', | |
}, | |
item: { | |
...cssReset(ITEM_DEFAULT_TAG), | |
flex: 1, | |
}, | |
}); | |
export { Flex, styles }; | |
export type { FlexProps, FlexItemProps }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as React from 'react'; | |
import { Flex as FlexPrimitive, styles } from './Flex'; | |
export default { title: 'Flex' }; | |
export const Basic = () => ( | |
<Flex> | |
<FlexItem /> | |
<FlexItem /> | |
<FlexItem /> | |
<FlexItem /> | |
<FlexItem /> | |
<FlexItem /> | |
</Flex> | |
); | |
export const InlineStyle = () => ( | |
<FlexInlineStyle> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
</FlexInlineStyle> | |
); | |
export const Gap = () => ( | |
<FlexInlineStyle gap={5}> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
</FlexInlineStyle> | |
); | |
export const RowGap = () => ( | |
<FlexInlineStyle rowGap={5}> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
</FlexInlineStyle> | |
); | |
export const ColumnGap = () => ( | |
<FlexInlineStyle columnGap={5}> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
</FlexInlineStyle> | |
); | |
export const OffsetGap = () => ( | |
<FlexInlineStyle gap={5}> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem xOffset={20} /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem /> | |
<FlexInlineStyleItem yOffset={20} /> | |
<FlexInlineStyleItem /> | |
</FlexInlineStyle> | |
); | |
const Flex = (props: React.ComponentProps<typeof FlexPrimitive>) => ( | |
<FlexPrimitive {...props} style={{ ...styles.root, ...props.style }} /> | |
); | |
const FlexItem = (props: React.ComponentProps<typeof FlexPrimitive.Item>) => ( | |
<FlexPrimitive.Item {...props} style={{ ...styles.item, ...props.style }} /> | |
); | |
const FlexInlineStyle = (props: React.ComponentProps<typeof Flex>) => ( | |
<Flex | |
{...props} | |
style={{ | |
backgroundColor: 'ghostwhite', | |
flexWrap: 'wrap', | |
}} | |
/> | |
); | |
const FlexInlineStyleItem = (props: React.ComponentProps<typeof FlexItem>) => ( | |
<FlexItem | |
{...props} | |
style={{ | |
height: 50, | |
minWidth: 200, | |
borderWidth: 2, | |
borderStyle: 'solid', | |
borderColor: 'gainsboro', | |
}} | |
/> | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment