# All files / layouts/Fields Fields.js

0% Statements 0/56
0% Branches 0/12
0% Functions 0/8
0% Lines 0/23

    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

     import React from 'react';
    import PropTypes from 'prop-types';
    import FieldRowContainer from './styles/FieldRowContainer';
    import FieldRow from './styles/FieldRow';
    import Field from './Field';

    class Fields extends React.Component {
      static Field = Field;

      static propTypes = {
        /**
         * The number of columns to divide the fieldset into when rendering. Fields can span multiple columns if provided
         * with a columnSpan prop. Fields which overflow the column limit will be added to new rows. If a Field's
         * columnSpan is too large to fit in the current row, it will be wrapped to the next one.
         */
        columns: PropTypes.number,
        /**
         * A component prop to override the component used to render the outer container which renders field rows.
         * Defaults to FieldRowContainer.
         */
        RowContainer: PropTypes.func,
        /**
         * A component prop to override the component which is injected to wrap Field elements into discrete rows.
         * Row receives the same `columns` prop provided to this component. Defaults to FieldRow.
         */
        Row: PropTypes.func,
      };

      static defaultProps = {
        RowContainer: FieldRowContainer,
        Row: FieldRow,
        columns: 2,
      };

      partitionFields = () => {
        const { columns, children, Row } = this.props;
        const childArray = React.Children.toArray(children);

        const rows = childArray.reduce(
          (rows, child) => {
            const childColumnSpan = child.props.columnSpan || 1;

            if (childColumnSpan > columns) {
              throw new Error(
                `A Field has a columnSpan of ${childColumnSpan}, but the containing Fields only has ${columns} columns`,
              );
            }

            const currentRow = rows[rows.length - 1];
            if (currentRow.columnWidth + childColumnSpan <= columns) {
              // add to current row
              return [
                ...rows.slice(0, rows.length - 1),
                {
                  children: [
                    ...currentRow.children,
                    {
                      column: currentRow.columnWidth,
                      element: child,
                    },
                  ],
                  columnWidth: currentRow.columnWidth + childColumnSpan,
                },
              ];
            } else {
              // create new row
              return [
                ...rows,
                {
                  children: [{ column: 0, element: child }],
                  columnWidth: childColumnSpan,
                },
              ];
            }
          },
          [{ children: [], columnWidth: 0 }],
        );

        return rows.map((row, rowIdx) => (
          <Row key={rowIdx} columns={columns}>
            {row.children.map(({ element, column }) =>
              React.cloneElement(element, { column }),
            )}
          </Row>
        ));
      };

      render() {
        const { RowContainer } = this.props;

        return <RowContainer>{this.partitionFields()}</RowContainer>;
      }
    }

    export default Fields;