<commit_before>// @flow

import React from 'react';
import PropTypes from 'prop-types';
import { merge } from 'timm';
import {
  flexContainer,
  flexItem,
  boxWithShadow,
  isDark,
  darken,
} from '../gral/styles';
import { COLORS, FONTS } from '../gral/constants';
import Hoverable from '../wrappers/hoverable';
import type {
  HoverableProps,
  PublicHoverableProps,
} from '../wrappers/hoverable';
/* eslint-disable no-unused-vars */
import type { NotificationType, NotificationPars } from './notificationTypes';
/* eslint-enable no-unused-vars */
import Icon from './icon';

// ==========================================
// Types
// ==========================================
type PublicProps = {
  ...NotificationPars,
  ...PublicHoverableProps,
};
type Props = {
  ...PublicProps,
  ...HoverableProps,
  type: NotificationType,
};

// ==========================================
// Component
// ==========================================
const HoverableNotification = (props: PublicProps) => (
  <Hoverable
    onHoverStart={props.onHoverStart}
    onHoverStop={props.onHoverStop}
    render={hoverableProps => <Notification {...props} {...hoverableProps} />}
  />
);

class Notification extends React.PureComponent<Props> {
  static defaultProps = {
    type: ('info': NotificationType),
  };

  // ==========================================
  render() {
    const { theme } = this.context;
    const icon =
      this.props.icon || (theme === 'mdl' ? 'announcement' : 'exclamation');
    return (
      <div
        className="giu-notification"
        id={this.props.id}
        onMouseEnter={this.props.onHoverStart}
        onMouseLeave={this.props.onHoverStop}
        onClick={this.props.onClick}
        style={style.outer(this.props, this.context.theme)}
      >
        <div style={style.icon}>
          <Icon icon={icon} size="2x" spin={this.props.iconSpin} />
        </div>
        <div style={style.body}>
          <div style={style.title}>{this.props.title}</div>
          <div style={style.msg}>{this.props.msg}</div>
        </div>
      </div>
    );
  }
}

Notification.contextTypes = { theme: PropTypes.any };

// ==========================================
const style = {
  outer: (
    {
      type,
      hovering,
      onClick,
      style: baseStyle,
      noStylePosition,
      noStyleShadow,
    },
    theme
  ) => {
    let bgColor = COLORS.notifs[type] || COLORS.notifs.info;
    if (hovering && onClick) bgColor = darken(bgColor, 10);
    const fgColor = COLORS[isDark(bgColor) ? 'lightText' : 'darkText'];
    let out = flexContainer('row', {
      alignItems: 'center',
      WebkitAlignItems: 'center',
      overflow: 'hidden',
      padding: '7px 13px',
      cursor: onClick ? 'pointer' : undefined,
      backgroundColor: bgColor,
      color: fgColor,
      fontFamily: theme === 'mdl' ? FONTS.mdl : undefined,
    });
    if (!noStyleShadow) out = boxWithShadow(out);
    if (!noStylePosition) {
      out = merge(out, {
        position: 'fixed',
        bottom: 20,
        right: 20,
        maxWidth: 350,
      });
    }
    if (baseStyle) out = merge(out, baseStyle);
    return out;
  },
  icon: flexItem('0 1 auto', {
    paddingRight: 20,
  }),
  body: flexItem('1 1 50px'),
  title: {
    fontWeight: 'bold',
  },
  msg: {
    wordWrap: 'break-word',
    fontWeight: 'normal',
  },
};

// ==========================================
// Public
// ==========================================
export default HoverableNotification;
<commit_msg>Make Notification not depend on Hoverable<commit_after>// @flow

import React from 'react';
import PropTypes from 'prop-types';
import { merge } from 'timm';
import {
  flexContainer,
  flexItem,
  boxWithShadow,
  isDark,
  darken,
} from '../gral/styles';
import { COLORS, FONTS } from '../gral/constants';
import type { NotificationType, NotificationPars } from './notificationTypes';
import Icon from './icon';

// ==========================================
// Declarations
// ==========================================
type Props = {
  ...NotificationPars,
  onHoverStart?: (ev: SyntheticEvent<*>) => any,
  onHoverStop?: (ev: SyntheticEvent<*>) => any,
  type: NotificationType,
};
type State = {
  hovering: boolean,
};

// ==========================================
// Component
// ==========================================
class Notification extends React.PureComponent<Props, State> {
  static defaultProps = {
    type: ('info': NotificationType),
  };
  state = { hovering: false };

  // ==========================================
  render() {
    const { theme } = this.context;
    const icon =
      this.props.icon || (theme === 'mdl' ? 'announcement' : 'exclamation');
    return (
      <div
        className="giu-notification"
        id={this.props.id}
        onMouseEnter={this.onHoverStart}
        onMouseLeave={this.onHoverStop}
        onClick={this.props.onClick}
        style={style.outer(this.props, this.state, this.context.theme)}
      >
        <div style={style.icon}>
          <Icon icon={icon} size="2x" spin={this.props.iconSpin} />
        </div>
        <div style={style.body}>
          <div style={style.title}>{this.props.title}</div>
          <div style={style.msg}>{this.props.msg}</div>
        </div>
      </div>
    );
  }

  // ==========================================
  onHoverStart = (ev: SyntheticEvent<*>) => {
    this.setState({ hovering: true });
    this.props.onHoverStart && this.props.onHoverStart(ev);
  };

  onHoverStop = (ev: SyntheticEvent<*>) => {
    this.setState({ hovering: false });
    this.props.onHoverStop && this.props.onHoverStop(ev);
  };
}

Notification.contextTypes = { theme: PropTypes.any };

// ==========================================
const style = {
  outer: (
    { type, onClick, style: baseStyle, noStylePosition, noStyleShadow },
    { hovering },
    theme
  ) => {
    let bgColor = COLORS.notifs[type] || COLORS.notifs.info;
    if (hovering && onClick) bgColor = darken(bgColor, 10);
    const fgColor = COLORS[isDark(bgColor) ? 'lightText' : 'darkText'];
    let out = flexContainer('row', {
      alignItems: 'center',
      WebkitAlignItems: 'center',
      overflow: 'hidden',
      padding: '7px 13px',
      cursor: onClick ? 'pointer' : undefined,
      backgroundColor: bgColor,
      color: fgColor,
      fontFamily: theme === 'mdl' ? FONTS.mdl : undefined,
    });
    if (!noStyleShadow) out = boxWithShadow(out);
    if (!noStylePosition) {
      out = merge(out, {
        position: 'fixed',
        bottom: 20,
        right: 20,
        maxWidth: 350,
      });
    }
    if (baseStyle) out = merge(out, baseStyle);
    return out;
  },
  icon: flexItem('0 1 auto', { paddingRight: 20 }),
  body: flexItem('1 1 50px'),
  title: { fontWeight: 'bold' },
  msg: {
    wordWrap: 'break-word',
    fontWeight: 'normal',
  },
};

// ==========================================
// Public
// ==========================================
export default Notification;

{'fraction_non_alphanumeric': 0.24555619266055045, 'fraction_numerical': 0.006020642201834863, 'mean_word_length': 3.133293838862559, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1550470', 'n_tokens_mistral': 2184, 'n_tokens_neox': 2103, 'n_words': 442}