import PropTypes from 'prop-types';
import { prependContext } from "../../../utils/tracking/index.js";
import customizable from "../../../utils/css/customizable.js";
import getColor from "../../../utils/colors/getColor.js";
import getShadowClasses from "../../../utils/css/getShadowClasses.js";
import { useResponsiveValues } from "../../../hooks/breakpoint/index.js";
import getPaddingClasses from "../../../utils/css/getPaddingClasses.js";
import CustomPropTypes from "../../../utils/prop-types/index.js";
import cx from "../../../utils/css/cx.js";
import { useSideDrawerState } from "../../../hooks/ui/index.js";
import CloseButton from './CloseButton';
import classes from './styles.module.scss';
import useFocusDrawer from './useFocusDrawer';
const cls = cx.merge(classes);

/**
 * Renders a hidden side drawer that will slide into view with a trigger. A scrim obscures the rest
 * of the content on the page.
 *
 * The component comes in two parts:
 * - `SideDrawer`: The actual drawer itself, which will render its children inside
 * - `Hooks/useSideDrawerState`: A hook that allows you to access the drawer's state,
 *    as well as `close`, `open` and `toggle` functions. You can use this to handle
 *    the trigger on a button outside of the drawer
 */
const SideDrawer = function SideDrawer(props) {
  const {
    children,
    CloseButton: CloseButtonFromProps,
    tracking,
    bg,
    shadow,
    dialogName,
    closeButtonName,
    padding
  } = props;
  const drawer = useSideDrawerState();
  const [drawerRef, closeButtonRef] = useFocusDrawer(drawer);
  const trackingOpts = {
    context: `${prependContext({
      prefix: tracking?.context,
      context: 'SideDrawer'
    })}`
  };
  const shadowClasses = getShadowClasses(shadow);
  const paddingValue = useResponsiveValues(padding);
  const pads = getPaddingClasses(paddingValue);
  return <div className={cls('container', `${drawer.state}`, customizable('SideDrawer'))}>
      <div className={cls(customizable('SideDrawer__scrim'), 'scrim')} />

      <div ref={drawerRef} className={cls('drawer', customizable('SideDrawer__drawer'), {
      defaultPadding: !padding
    }, shadowClasses, pads)} role="dialog" aria-modal="true" title={dialogName} style={{
      background: getColor(bg)
    }}>
        <div className={cls(customizable('SideDrawer__content'), 'content')}>
          <div className={cls(customizable('SideDrawer__controls'), 'controls')}>
            <CloseButton drawer={drawer} tracking={trackingOpts} ref={closeButtonRef} name={closeButtonName} CustomCloseButton={CloseButtonFromProps} />
          </div>
          <div className={cls(customizable('SideDrawer__inner'), 'inner')}>
            {children}
          </div>
        </div>
      </div>
    </div>;
};
SideDrawer.defaultProps = {
  tracking: undefined,
  CloseButton: undefined,
  children: undefined,
  bg: 'white',
  shadow: '200',
  padding: '8',
  closeButtonName: 'Close'
};
SideDrawer.propTypes = {
  /**
   * Children to render inside the container.
   */
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
  /**
   * A color to use for the background of the drawer. Each color value can
   * be either the name of a color provided by this library (e.g., `altblack-80`)
   * or a valid CSS color (e.g., `red`, `#f04444`).
   * Note that if no color is specified the background will be white.
   */
  bg: PropTypes.string,
  /**
   * A custom close button
   */
  CloseButton: PropTypes.func,
  /**
   * A name for the drawer that will be announced by screenreaders. This should be
   * a short name that lets the user know what to expect inside of the drawer.
   */
  dialogName: PropTypes.string.isRequired,
  /**
   * A name for the button that cloess that drawer that will be announced by screenreaders.
   * This should be a short description of what this button will do.
   */
  closeButtonName: PropTypes.string,
  /**
   * The padding of the drawer container. Padding can be specified as one spacing value
   * that gets used on all sides, separate `x` and `y` values, or completely
   * separate `trbl` values. The values correspond to levels of our spacing
   * scale (e.g., `"4"` corresponds to `$spacing-4`). If you don't specify any
   * padding some default padding is applied, but if you specify any padding at
   * all the default padding is removed.
   *
   * Padding can also be specified as a responsive value. See our guide
   * on our standard styling props for more details.
   */
  padding: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    x: PropTypes.string,
    y: PropTypes.string
  }), PropTypes.shape({
    t: PropTypes.string,
    r: PropTypes.string,
    b: PropTypes.string,
    l: PropTypes.string
  })])),
  /**
   * Sets the elevation level of the drawer. See the section on elevation
   * for guidance on which level to choose.
   * Note that if no level is specified the elevation will be '200'
   */
  shadow: PropTypes.oneOf(['000', '100', '200', '300', '400']),
  /**
   * Tracking configuration
   */
  tracking: PropTypes.shape({
    context: PropTypes.string
  })
};
export default SideDrawer;