import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { styled } from '@storybook/theming';
import { Link } from '@storybook/router';
import { SyntaxHighlighter } from '@storybook/components';

import { createElement } from 'react-syntax-highlighter';
import { EVENT_ID } from './events';

const StyledStoryLink = styled(Link)(({ theme }) => ({
  display: 'block',
  textDecoration: 'none',
  borderRadius: theme.appBorderRadius,

  '&:hover': {
    background: theme.background.hoverable,
  },
}));

const SelectedStoryHighlight = styled.div(({ theme }) => ({
  background: theme.background.hoverable,
  borderRadius: theme.appBorderRadius,
}));

const StyledSyntaxHighlighter = styled(SyntaxHighlighter)(({ theme }) => ({
  fontSize: theme.typography.size.s2 - 1,
}));

const areLocationsEqual = (a, b) =>
  a.startLoc.line === b.startLoc.line &&
  a.startLoc.col === b.startLoc.col &&
  a.endLoc.line === b.endLoc.line &&
  a.endLoc.col === b.endLoc.col;

const getLocationKeys = locationsMap =>
  locationsMap
    ? Array.from(Object.keys(locationsMap)).sort(
        (key1, key2) => locationsMap[key1].startLoc.line - locationsMap[key2].startLoc.line
      )
    : [];

export default class StoryPanel extends Component {
  state = { source: 'loading source...' };

  componentDidMount() {
    this.mounted = true;
    const { api } = this.props;

    api.on(EVENT_ID, this.listener);
  }

  componentDidUpdate() {
    if (this.selectedStoryRef) {
      this.selectedStoryRef.scrollIntoView();
    }
  }

  componentWillUnmount() {
    const { api } = this.props;

    api.off(EVENT_ID, this.listener);
  }

  setSelectedStoryRef = ref => {
    this.selectedStoryRef = ref;
  };

  listener = ({ source, currentLocation, locationsMap }) => {
    const locationsKeys = getLocationKeys(locationsMap);

    this.setState({
      source,
      currentLocation,
      locationsMap,
      locationsKeys,
    });
  };

  createPart = (rows, stylesheet, useInlineStyles) =>
    rows.map((node, i) =>
      createElement({
        node,
        stylesheet,
        useInlineStyles,
        key: `code-segement${i}`,
      })
    );

  createStoryPart = (rows, stylesheet, useInlineStyles, location, id) => {
    const { currentLocation } = this.state;
    const first = location.startLoc.line - 1;
    const last = location.endLoc.line;

    const storyRows = rows.slice(first, last);
    const story = this.createPart(storyRows, stylesheet, useInlineStyles);
    const storyKey = `${first}-${last}`;

    if (location && currentLocation && areLocationsEqual(location, currentLocation)) {
      return (
        <SelectedStoryHighlight key={storyKey} ref={this.setSelectedStoryRef}>
          {story}
        </SelectedStoryHighlight>
      );
    }

    return (
      <StyledStoryLink to={`/story/${id}`} key={storyKey}>
        {story}
      </StyledStoryLink>
    );
  };

  createParts = (rows, stylesheet, useInlineStyles) => {
    const { locationsMap, locationsKeys } = this.state;

    const parts = [];
    let lastRow = 0;

    locationsKeys.forEach(key => {
      const location = locationsMap[key];
      const first = location.startLoc.line - 1;
      const last = location.endLoc.line;

      const start = this.createPart(rows.slice(lastRow, first), stylesheet, useInlineStyles);
      const storyPart = this.createStoryPart(rows, stylesheet, useInlineStyles, location, key);

      parts.push(start);
      parts.push(storyPart);

      lastRow = last;
    });

    const lastPart = this.createPart(rows.slice(lastRow), stylesheet, useInlineStyles);

    parts.push(lastPart);

    return parts;
  };

  lineRenderer = ({ rows, stylesheet, useInlineStyles }) => {
    const { locationsMap, locationsKeys } = this.state;

    // because of the usage of lineRenderer, all lines will be wrapped in a span
    // these spans will recieve all classes on them for some reason
    // which makes colours casecade incorrectly
    // this removed that list of classnames
    const myrows = rows.map(({ properties, ...rest }) => ({
      ...rest,
      properties: { className: [] },
    }));

    if (!locationsMap || !locationsKeys.length) {
      return this.createPart(myrows, stylesheet, useInlineStyles);
    }

    const parts = this.createParts(myrows, stylesheet, useInlineStyles);

    return <span>{parts}</span>;
  };

  render() {
    const { active } = this.props;
    const { source } = this.state;

    return active ? (
      <StyledSyntaxHighlighter
        language="jsx"
        showLineNumbers="true"
        renderer={this.lineRenderer}
        format={false}
        copyable={false}
        padded
      >
        {source}
      </StyledSyntaxHighlighter>
    ) : null;
  }
}

StoryPanel.propTypes = {
  active: PropTypes.bool.isRequired,
  api: PropTypes.shape({
    selectStory: PropTypes.func.isRequired,
    emit: PropTypes.func,
    on: PropTypes.func,
    off: PropTypes.func,
  }).isRequired,
};

@@ -453,16 +453,36 @@
 rRadius,
+%0A  color: 'inherit',
 %0A%0A  '&:h

Add color inherit to StyledStoryLink (#6876)