diff --git a/src/lsg/patterns/space/demo.tsx b/src/lsg/patterns/space/demo.tsx new file mode 100644 index 000000000..8bc88a19f --- /dev/null +++ b/src/lsg/patterns/space/demo.tsx @@ -0,0 +1,123 @@ +import { Color, colors } from '../colors'; +import Space, { Size } from './index'; +import * as React from 'react'; +import styled from 'styled-components'; + +const blue: Color = new Color({displayName: 'Demo Blue', rgb: [91, 177, 255]}); +const green: Color = new Color({displayName: 'Demo Green', rgb: [91, 255, 151]}); +const violet: Color = new Color({displayName: 'Demo Violet', rgb: [181, 91, 255]}); + +const DemoTileSpace = styled(Space)` + display: flex; + flex-wrap: wrap; +`; + +const DemoRowSpace = styled(Space)` + display: flex; + align-content: stretch; + flex-wrap: wrap; + justify-content: space-between; +`; + +const InsetSpace = styled(Space)` + background-color: ${blue.toString()}; + width: 250px; + height: 250px; +`; + +const StackSpace = styled(Space)` + background-color: ${green.toString()}; +`; + +const InlineSpace = styled(Space)` + background-color: ${violet.toString()}; +`; + +const Content = styled.div` + background-color: ${colors.white.toString()}; + width: 100%; + height: 100%; + text-align: center; + line-height: 2em; +`; + +const SpaceDemo: React.StatelessComponent = (): JSX.Element => ( +
+ Inset + + + {Size[Size.XS]} + + + {Size[Size.XS]} + + + {Size[Size.S]} + + + {Size[Size.L]} + + + {Size[Size.L]} + + + {Size[Size.XL]} + + + {Size[Size.XXL]} + + + + Inline + + + {Size[Size.XS]} + + + {Size[Size.XS]} + + + {Size[Size.S]} + + + {Size[Size.L]} + + + {Size[Size.L]} + + + {Size[Size.XL]} + + + {Size[Size.XXL]} + + + + Stack + + + {Size[Size.XS]} + + + {Size[Size.XS]} + + + {Size[Size.S]} + + + {Size[Size.L]} + + + {Size[Size.L]} + + + {Size[Size.XL]} + + + {Size[Size.XXL]} + + +
+); + +export default SpaceDemo; diff --git a/src/lsg/patterns/space/index.tsx b/src/lsg/patterns/space/index.tsx new file mode 100644 index 000000000..54c1b2e7d --- /dev/null +++ b/src/lsg/patterns/space/index.tsx @@ -0,0 +1,115 @@ +import * as React from 'react'; +import styled from 'styled-components'; + +export interface SpaceProps { + className?: string; + inside?: boolean; + size?: Size | Size[]; + sizeBottom?: Size; + sizeLeft?: Size; + sizeRight?: Size; + sizeTop?: Size; +} + +export interface StyledSpaceProps { + inside: boolean; + // Redefine `size` as `spaceSize` property for styled components to avoid collision + // with `size` property on `React.HTMLAttributes` interface. + spaceSize: Size[]; +} + +export enum Size { + // Explicity set enum values to indicate that they will be used later on as + // array indicies. + None = 0, + XS = 6, + S = 12, + M = 15, + L = 18, + XL = 24, + XXL = 32 +} + +export enum PageInset { + // Defines global page gutter used in header and footer components + XS = 24, + S = 42, + M = 60, + L = 78, + XL = 96 +} + +/** + * Calculates the actual value for the given size and breakpoint, based on the + * given growth mapping. + * @param size The size used for calculation. + */ +export function getSpace(size: Size): number { + if (undefined !== size) { + return size; + } + return 0; +} + +function expand(source: T[] | T): T[] { + const values: T[] = Array.isArray(source) ? source : [source]; + + switch (values.length) { + case 1: // [a] => [a, a, a, a] + return [values[0], values[0], values[0], values[0]]; + case 2: // [a, b] => [a, b, a, b] + return [...values, ...values]; + case 3: // [a, b, c] => [a, b, c, b] + return [...values, values[1]]; + case 4: // [a, b, c, d] => [a, b, c, d] + default: + return values.slice(0, 4); + } +} + +function merge(shorthand: T | T[], top?: T, right?: T, bottom?: T, left?: T): T[] { + const expanded = expand(shorthand); + + return [ + top === undefined ? expanded[0] : top, + right === undefined ? expanded[1] : right, + bottom === undefined ? expanded[2] : bottom, + left === undefined ? expanded[3] : left + ]; +} + +function calculate(property: string, space: Size[]): string { + const values = space.map((value, index) => `${getSpace(value)}px`); + + const result = `${property}: ${values.join(' ')};`; + + return result; +} + +const StyledSpace = styled.div` + ${(props: StyledSpaceProps) => + calculate(props.inside + ? 'padding' + : 'margin' + , props.spaceSize + ) + } +`; + +const Space: React.StatelessComponent = props => { + const size = merge( + props.size || 0, + props.sizeTop, + props.sizeRight, + props.sizeBottom, + props.sizeLeft + ); + + return ( + + {props.children} + + ); +}; + +export default Space; diff --git a/src/lsg/patterns/space/pattern.json b/src/lsg/patterns/space/pattern.json new file mode 100644 index 000000000..0c41d7f15 --- /dev/null +++ b/src/lsg/patterns/space/pattern.json @@ -0,0 +1,7 @@ +{ + "name": "space", + "displayName": "Space", + "flag": "alpha", + "version": "1.0.0", + "tags": ["space"] +}