<commit_before>import React, { Component, Fragment, ReactElement } from 'react';
import memoize from 'memoizerific';

import { Combo, Consumer, API } from '@storybook/api';
import { Global, Theme } from '@storybook/theming';

import { Icons, IconButton, WithTooltip, TooltipLinkList } from '@storybook/components';

import { PARAM_KEY, EVENTS } from '../constants';
import { ColorIcon } from '../components/ColorIcon';

interface Item {
  id: string;
  title: string;
  onClick: () => void;
  value: string;
  right?: ReactElement;
}

interface Input {
  name: string;
  value: string;
  default?: boolean;
}

const iframeId = 'storybook-preview-iframe';

const createBackgroundSelectorItem = memoize(1000)(
  (
    id: string,
    name: string,
    value: string,
    hasSwatch: boolean,
    change: (arg: { selected: string; name: string }) => void
  ): Item => ({
    id: id || name,
    title: name,
    onClick: () => {
      change({ selected: value, name });
    },
    value,
    right: hasSwatch ? <ColorIcon background={value} /> : undefined,
  })
);

const getSelectedBackgroundColor = (list: Input[], currentSelectedValue: string): string => {
  if (!list.length) {
    return 'transparent';
  }

  if (currentSelectedValue === 'transparent') {
    return currentSelectedValue;
  }

  if (list.find(i => i.value === currentSelectedValue)) {
    return currentSelectedValue;
  }

  if (list.find(i => i.default)) {
    return list.find(i => i.default).value;
  }

  return 'transparent';
};

const mapper = ({ api, state }: Combo): { items: Input[]; selected: string | null } => {
  const story = state.storiesHash[state.storyId];
  const list = story ? api.getParameters(story.id, PARAM_KEY) : [];
  const selected = state.addons[PARAM_KEY] || null;

  return { items: list || [], selected };
};

const getDisplayedItems = memoize(10)(
  (
    list: Input[],
    selected: string | null,
    change: (arg: { selected: string; name: string }) => void
  ) => {
    let availableBackgroundSelectorItems: Item[] = [];

    if (selected !== 'transparent') {
      availableBackgroundSelectorItems.push(
        createBackgroundSelectorItem('reset', 'Clear background', 'transparent', null, change)
      );
    }

    if (list.length) {
      availableBackgroundSelectorItems = [
        ...availableBackgroundSelectorItems,
        ...list.map(({ name, value }) =>
          createBackgroundSelectorItem(null, name, value, true, change)
        ),
      ];
    }

    return availableBackgroundSelectorItems;
  }
);

interface GlobalState {
  name: string | undefined;
  selected: string | undefined;
}

interface Props {
  api: API;
}

export class BackgroundSelector extends Component<Props> {
  change = ({ selected, name }: GlobalState) => {
    const { api } = this.props;
    if (typeof selected === 'string') {
      api.setAddonState<string>(PARAM_KEY, selected);
    }
    api.emit(EVENTS.UPDATE, { selected, name });
  };

  render() {
    return (
      <Consumer filter={mapper}>
        {({ items, selected }: ReturnType<typeof mapper>) => {
          const selectedBackgroundColor = getSelectedBackgroundColor(items, selected);

          return items.length ? (
            <Fragment>
              {selectedBackgroundColor ? (
                <Global
                  styles={(theme: Theme) => ({
                    [`#${iframeId}`]: {
                      background:
                        selectedBackgroundColor === 'transparent'
                          ? theme.background.content
                          : selectedBackgroundColor,
                    },
                  })}
                />
              ) : null}
              <WithTooltip
                placement="top"
                trigger="click"
                tooltip={({ onHide }) => (
                  <TooltipLinkList
                    links={getDisplayedItems(items, selectedBackgroundColor, i => {
                      this.change(i);
                      onHide();
                    })}
                  />
                )}
                closeOnClick
              >
                <IconButton<commit_msg>fix(background): use backgroundColor to prevent css collision with grid<commit_after>import React, { Component, Fragment, ReactElement } from 'react';
import memoize from 'memoizerific';

import { Combo, Consumer, API } from '@storybook/api';
import { Global, Theme } from '@storybook/theming';

import { Icons, IconButton, WithTooltip, TooltipLinkList } from '@storybook/components';

import { PARAM_KEY, EVENTS } from '../constants';
import { ColorIcon } from '../components/ColorIcon';

interface Item {
  id: string;
  title: string;
  onClick: () => void;
  value: string;
  right?: ReactElement;
}

interface Input {
  name: string;
  value: string;
  default?: boolean;
}

const iframeId = 'storybook-preview-iframe';

const createBackgroundSelectorItem = memoize(1000)(
  (
    id: string,
    name: string,
    value: string,
    hasSwatch: boolean,
    change: (arg: { selected: string; name: string }) => void
  ): Item => ({
    id: id || name,
    title: name,
    onClick: () => {
      change({ selected: value, name });
    },
    value,
    right: hasSwatch ? <ColorIcon background={value} /> : undefined,
  })
);

const getSelectedBackgroundColor = (list: Input[], currentSelectedValue: string): string => {
  if (!list.length) {
    return 'transparent';
  }

  if (currentSelectedValue === 'transparent') {
    return currentSelectedValue;
  }

  if (list.find(i => i.value === currentSelectedValue)) {
    return currentSelectedValue;
  }

  if (list.find(i => i.default)) {
    return list.find(i => i.default).value;
  }

  return 'transparent';
};

const mapper = ({ api, state }: Combo): { items: Input[]; selected: string | null } => {
  const story = state.storiesHash[state.storyId];
  const list = story ? api.getParameters(story.id, PARAM_KEY) : [];
  const selected = state.addons[PARAM_KEY] || null;

  return { items: list || [], selected };
};

const getDisplayedItems = memoize(10)(
  (
    list: Input[],
    selected: string | null,
    change: (arg: { selected: string; name: string }) => void
  ) => {
    let availableBackgroundSelectorItems: Item[] = [];

    if (selected !== 'transparent') {
      availableBackgroundSelectorItems.push(
        createBackgroundSelectorItem('reset', 'Clear background', 'transparent', null, change)
      );
    }

    if (list.length) {
      availableBackgroundSelectorItems = [
        ...availableBackgroundSelectorItems,
        ...list.map(({ name, value }) =>
          createBackgroundSelectorItem(null, name, value, true, change)
        ),
      ];
    }

    return availableBackgroundSelectorItems;
  }
);

interface GlobalState {
  name: string | undefined;
  selected: string | undefined;
}

interface Props {
  api: API;
}

export class BackgroundSelector extends Component<Props> {
  change = ({ selected, name }: GlobalState) => {
    const { api } = this.props;
    if (typeof selected === 'string') {
      api.setAddonState<string>(PARAM_KEY, selected);
    }
    api.emit(EVENTS.UPDATE, { selected, name });
  };

  render() {
    return (
      <Consumer filter={mapper}>
        {({ items, selected }: ReturnType<typeof mapper>) => {
          const selectedBackgroundColor = getSelectedBackgroundColor(items, selected);

          return items.length ? (
            <Fragment>
              {selectedBackgroundColor ? (
                <Global
                  styles={(theme: Theme) => ({
                    [`#${iframeId}`]: {
                      backgroundColor:
                        selectedBackgroundColor === 'transparent'
                          ? theme.background.content
                          : selectedBackgroundColor,
                    },
                  })}
                />
              ) : null}
              <WithTooltip
                placement="top"
                trigger="click"
                tooltip={({ onHide }) => (
                  <TooltipLinkList
                    links={getDisplayedItems(items, selectedBackgroundColor, i => {
                      this.change(i);
                      onHide();
                    })}
                  />
                )}
                closeOnClick
              >
                <IconButton
{'fraction_non_alphanumeric': 0.1321389924251533, 'fraction_numerical': 0.001442827942767825, 'mean_word_length': 2.265802905378877, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 55, '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': '2556841', 'n_tokens_mistral': 2312, 'n_tokens_neox': 2247, 'n_words': 539}