/** * This is a level above CSX * - It wraps up the CSX primitives into components */ import * as csx from './csx'; import { vendorPrefixed } from './csx'; import * as typestyle from 'typestyle'; import * as React from "react"; /** Creates a copy of an object without the mentioned keys */ function _objectWithoutProperties(obj: any, keys: string[]) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } declare global { interface Function { displayName?: string; } } /******** * * Primitives * ********/ /** * For that time you just need a visual vertical seperation */ export const SmallVerticalSpace = (props: { space?: number }) => { return
; } SmallVerticalSpace.displayName = "SmallVerticalSpace"; /** * For that time you just need a visual horizontal seperation */ export const SmallHorizontalSpace = (props: { space?: number }) => { return
; } SmallVerticalSpace.displayName = "SmallHorizontalSpace"; interface PrimitiveProps extends React.HTMLProps { }; namespace ClassNames { export const content = typestyle.style(vendorPrefixed.content); export const flex = typestyle.style(vendorPrefixed.pass, vendorPrefixed.flex); export const flexScrollY = typestyle.style(vendorPrefixed.pass, vendorPrefixed.flex, vendorPrefixed.vertical, { overflowY: 'auto' }); export const pass = typestyle.style(vendorPrefixed.pass); export const contentVertical = typestyle.style(vendorPrefixed.content, vendorPrefixed.vertical); export const contentVerticalCentered = typestyle.style(vendorPrefixed.content, vendorPrefixed.vertical, vendorPrefixed.center); export const contentHorizontal = typestyle.style(vendorPrefixed.content, vendorPrefixed.horizontal); export const contentHorizontalCentered = typestyle.style(vendorPrefixed.content, vendorPrefixed.horizontal, vendorPrefixed.center); export const flexVertical = typestyle.style(vendorPrefixed.flex, vendorPrefixed.vertical, { maxWidth: '100%' /*normalizing browser bugs*/ }); export const flexHorizontal = typestyle.style(vendorPrefixed.flex, vendorPrefixed.horizontal); } /** * Generally prefer an inline block (as that will wrap). * Use this for critical `content` driven *vertical* height * * Takes as much space as it needs, no more, no less */ export const Content = (props: PrimitiveProps) => { const className = ClassNames.content + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; Content.displayName = "Content"; /** * Takes as much space as it needs, no more, no less */ export const InlineBlock = (props: PrimitiveProps) => { const style = csx.extend({ display: 'inline-block' }, props.style || {}); return (
{props.children}
); }; InlineBlock.displayName = "InlineBlock"; /** * Takes up all the parent space, no more, no less */ export const Flex = (props: PrimitiveProps) => { const className = ClassNames.flex + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; Flex.displayName = "Flex"; /** * Takes up all the parent space, no more, no less and scrolls the children in Y if needed */ export const FlexScrollY = (props: PrimitiveProps) => { const className = ClassNames.flexScrollY + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; FlexScrollY.displayName = "FlexScrollY"; /** * When you need a general purpose container. Use this instead of a `div` */ export const Pass = (props: PrimitiveProps) => { const className = ClassNames.pass + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; Pass.displayName = "Pass"; /** * Provides a Vertical Container. For the parent it behaves like content. */ export const ContentVertical = (props: PrimitiveProps) => { const className = ClassNames.contentVertical + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; ContentVertical.displayName = "ContentVertical"; /** * Quite commonly need horizontally centered text */ export const ContentVerticalCentered = (props: PrimitiveProps) => { const className = ClassNames.contentVerticalCentered + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); } ContentVerticalCentered.displayName = "ContentVerticalCentered"; /** * Provides a Horizontal Container. For the parent it behaves like content. */ export const ContentHorizontal = (props: PrimitiveProps) => { const className = ClassNames.contentHorizontal + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; ContentHorizontal.displayName = "ContentHorizontal"; /** * Provides a Horizontal Container and centers its children in the cross dimension */ export const ContentHorizontalCentered = (props: PrimitiveProps) => { const className = ClassNames.contentHorizontalCentered + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; ContentHorizontalCentered.displayName = "ContentHorizontalCentered"; /** * Provides a Vertical Container. For the parent it behaves like flex. */ export const FlexVertical = (props: PrimitiveProps) => { const className = ClassNames.flexVertical + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; FlexVertical.displayName = "FlexVertical"; /** * Provides a Horizontal Container. For the parent it behaves like flex. */ export const FlexHorizontal = (props: PrimitiveProps) => { const className = ClassNames.flexHorizontal + (props.className ? ` ${props.className}` : ''); return (
{props.children}
); }; FlexHorizontal.displayName = "FlexHorizontal"; /******** * * Grid System * ********/ interface PaddedProps extends PrimitiveProps { padding: number | string; } /** * Lays out the children horizontally with * - ThisComponent: gets the overall Height (by max) of the children * - Children: get the Width : equally distributed from the parent Width * - Children: get the Height : sized by content * - ThisComponent: Puts a horizontal padding between each item */ export const ContentHorizontalFlexPadded = (props: PaddedProps) => { const {padding} = props; const otherProps = _objectWithoutProperties(props, ['padding', 'children']); const children = React.Children.toArray(props.children).filter(c => !!c); const last = children.length - 1; const itemPadding = (index: number) => { if (index == last) { return csx.Box.padding(0); } else { return csx.Box.padding(0, padding, 0, 0); } } return ( { children.map((child, i) => {child}) } ); } ContentHorizontalFlexPadded.displayName = "ContentHorizontalFlexPadded"; /** * Lays out the children horizontally with * - Parent: gets to chose the Width * - ThisComponent: gets the overall Height (by max) of the children * - Children: get the Width : equally distributed from the parent Width * - Children: get the Height : sized by content * - ThisComponent: Puts a horizontal padding between each item */ export const FlexHorizontalFlexPadded = (props: PaddedProps) => { const {padding} = props; const otherProps = _objectWithoutProperties(props, ['padding', 'children']); const children = React.Children.toArray(props.children).filter(c => !!c); const last = children.length - 1; const itemPadding = (index: number) => { if (index == last) { return csx.Box.padding(0); } else { return csx.Box.padding(0, padding, 0, 0); } } return ( { children.map((child, i) => {child}) } ); } FlexHorizontalFlexPadded.displayName = "FlexHorizontalFlexPadded"; /** * Lays out the children horizontally with * - Parent: gets to chose the Width * - ThisComponent: gets the overall Height (by max) of the children * - Children: get the Width : equally distributed from the parent Width * - Children: get the Height : sized by content * - ThisComponent: Puts a horizontal padding between each item */ export const ContentHorizontalContentPadded = (props: PaddedProps) => { const {padding} = props; const otherProps = _objectWithoutProperties(props, ['padding', 'children']); const children = React.Children.toArray(props.children).filter(c => !!c); const last = children.length - 1; const itemPadding = (index: number) => { if (index == last) { return csx.Box.padding(0); } else { return csx.Box.padding(0, padding, 0, 0); } } return ( { children.map((child, i) => {child}) } ); } ContentHorizontalContentPadded.displayName = "ContentHorizontalContentPadded"; /** * Lays out the children vertically with * - Parent: gets to chose the Width * - ThisComponent: gets the Height : (by sum) of the children * - Children: get the Width : parent * - Children: get the Height : sized by content * - ThisComponent: Puts a vertical padding between each item */ export const ContentVerticalContentPadded = (props: PaddedProps) => { const {padding} = props; const otherProps = _objectWithoutProperties(props, ['padding', 'children']); const children = React.Children.toArray(props.children).filter(c => !!c); const last = children.length - 1; const itemPadding = (index: number) => { if (index == last) { return csx.Box.padding(0); } else { return csx.Box.padding(0, 0, padding, 0); } } return ( { children.map((child, i) => {child}) } ); } ContentVerticalContentPadded.displayName = "ContentVerticalContentPadded"; interface GridMarginedProps extends PrimitiveProps { margin: number | string; } /** * Lays out the children vertically with * - Parent: gets to chose the overall Width * - ThisComponent: gets the Height : (by sum) of the children * - Children: get the Width : sized by content * - Children: get the Height : sized by content * - ThisComponent: Puts a margin between each item. * - ThisComponent: Puts a negative margin on itself to offset the margins of the children (prevents them from leaking out) */ export const GridMargined = (props: GridMarginedProps) => { const {margin} = props; const otherProps = _objectWithoutProperties(props, ['margin', 'children']); const marginPx = `${margin}px`; const style = csx.extend(csx.wrap, { marginTop: '-' + marginPx, marginLeft: '-' + marginPx }, props.style || {}); const children = React.Children.toArray(props.children).filter(c => !!c); return ( { children.map((child, i) => {child}) } ); } GridMargined.displayName = "GridMargined";