# All files / layouts/Fields/styles FieldRow.js

0% Statements 0/41
0% Branches 0/14
0% Functions 0/15
0% Lines 0/27

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100

     import React from 'react';
    import themeGet from 'extensions/themeGet';
    import styled from 'styled-components';

    const AREA = {
      LABEL: 'label',
      CONTENT: 'content',
      HELP_TEXT: 'helpText',
    };

    const copyArea = (input, times) =>
      new Array(times)
        .fill(input)
        .map((text, index) => `${text}${index}`)
        .join(' ');

    // Returns true if at least one child uses a label
    const hasLabel = children =>
      React.Children.toArray(children).some(
        child =>
          child.props.label &&
          (typeof child.props.label !== 'string' || child.props.label.length > 0),
      );

    // Returns true if at least one child uses help text
    const hasHelpText = children =>
      React.Children.toArray(children).some(
        child =>
          child.props.helpText &&
          (typeof child.props.helpText !== 'string' ||
            child.props.helpText.length > 0),
      );

    /*
     * We calculate whether we need the label and help text rows based on
     * whether any children need them. This helps deal with the gridGap,
     * as it will still be present if a grid area gets a size of zero.
     */
    const includeArea = (area, children) => {
      if (area === AREA.LABEL) {
        return hasLabel(children);
      }
      if (area === AREA.HELP_TEXT) {
        return hasHelpText(children);
      }
      return true;
    };

    const calcGridAreas = children =>
      [AREA.LABEL, AREA.CONTENT, AREA.HELP_TEXT].filter(area =>
        includeArea(area, children),
      );

    const calcGridTemplateAreas = (children, columns) =>
      calcGridAreas(children)
        .map(area => `"${copyArea(area, columns)}"`)
        .join('\n');

    const calcGridTemplateRows = children =>
      calcGridAreas(children)
        .map(() => 'auto')
        .join(' ');

    const FieldRowDiv = styled.div`
      @supports (display: grid) {
        display: grid;
        /* defines spacing between rows and columns */
        grid-gap: var(--spacing-small) var(--spacing-large);
      }

      display: flex;
    `;

    const FieldRow = ({ children, columns, theme }) => {
      return (
        <FieldRowDiv
          style={{
            // each row has 3 sub-rows: label, content, helpText.
            // there's a named area for each column.
            gridTemplateAreas: calcGridTemplateAreas(children, columns),
            // each column has an equal size. To make fields larger than
            // adjacent fields, use the columnSpan prop on Field to span
            // multiple columns. This keeps all field sizes directly proportional
            gridTemplateColumns: `repeat(${columns}, 1fr)`,
            // label and helpText rows expand or contract as needed.
            // content row has a minimum size of 53px, and can expand as needed.
            gridTemplateRows: calcGridTemplateRows(children),
          }}
        >
          {children}
        </FieldRowDiv>
      );
    };

    FieldRow.defaultProps = {
      columnCount: 2,
    };

    export default FieldRow;