import { forwardRef } from 'react';
import PropTypes from 'prop-types';
import useResponsiveValues from "../../../hooks/breakpoint/useResponsiveValues/index.js";
import CustomPropTypes from "../../../utils/prop-types/index.js";
import cx from "../../../utils/css/cx.js";
import getMarginClasses from "../../../utils/css/getMarginClasses.js";
import classes from './styles.module.scss';

/**
 * Renders a flex container that sets up the standard grid. This `Grid` is set
 * up to be used as a container for `GridItem` components that dictate their
 * own behavior within the grid. The grid itself is based on a 12 column
 * layout, with 12 equal columns separated by responsive gutters.
 *
 * See the `GridItem` component for documentation on how it can position itself
 * and dictate its behavior within the grid.
 *
 * ```js
 *
 * import { Grid } from '@politico/interactive-style';
 * ```
 */
const Grid = forwardRef((props, ref) => {
  const {
    as: Tag,
    margin,
    relative,
    children
  } = props;
  const marginValue = useResponsiveValues(margin);
  const margins = getMarginClasses(marginValue, {
    defaultSide: 'y',
    sides: ['y', 't', 'b']
  });
  return <Tag ref={ref} className={cx.merge(classes)('root', margins, {
    relative
  })}>
      {children}
    </Tag>;
});
Grid.displayName = 'Grid';
Grid.defaultProps = {
  margin: undefined,
  as: 'div',
  relative: false,
  children: undefined
};
Grid.propTypes = {
  /**
   * Control which kind of tag or component is used to render the Grid
   * container. If you use a custom component it will be passed `className` and
   * `ref` props.
   */
  as: PropTypes.elementType,
  /**
   * The vertical margins of the grid. Margins can be specified as one spacing
   * value that gets used on both top and bottom, an explicit `y` value, or
   * completely separate `tb` values. The values correspond to levels of our
   * spacing scale (e.g., `"4"` corresponds to `$spacing-4`). Note that grids
   * do not support custom horizontal margins.
   */
  margin: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    y: PropTypes.string
  }), PropTypes.shape({
    t: PropTypes.string,
    b: PropTypes.string
  })])),
  /**
   * Whether the grid should specify `position: relative` to allow absolute
   * positioning within it.
   */
  relative: PropTypes.bool,
  /**
   * Any children that should be rendered within the Grid container. Note that
   * these should probably be `GridItem` elements or custom components that
   * render `GridItem` components.
   */
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)])
};
export default Grid;