Мультиселект не работает при использовании светокопии. js - PullRequest
0 голосов
/ 19 апреля 2020

Я пытаюсь реализовать несколько выбранных пользовательских компонентов с использованием компонентов в стиле реакции. Это не работает, я просмотрел документацию, и это было настолько интуитивно понятно. Я попробовал приведенный ниже код. Любая помощь будет оценена. Заранее спасибо.

MultiSelect.jsx

import React, { Component } from "react";
import { Button, MenuItem, Intent } from "@blueprintjs/core";
import { MultiSelect as BpMulti } from "@blueprintjs/select";
import StyledMultiSelect from "./MultiSelect.styles";
import { filmSelectProps } from "./options";

const INTENTS = [
  Intent.NONE,
  Intent.PRIMARY,
  Intent.SUCCESS,
  Intent.DANGER,
  Intent.WARNING
];

export default class MultiSelect extends Component {
  state = {
    films: []
  };

  getSelectedFilmIndex(film) {
    return this.state.films.indexOf(film);
  }

  isFilmSelected(film) {
    return this.getSelectedFilmIndex(film) !== -1;
  }

  handleFilmSelect = film => {
    if (!this.isFilmSelected(film)) {
      this.selectFilm(film);
    } else {
      this.deselectFilm(this.getSelectedFilmIndex(film));
    }
  };

  selectFilm(film) {
    this.setState({ films: [...this.state.films, film] });
  }
  deselectFilm(index) {
    this.setState({
      films: this.state.films.filter((_film, i) => i !== index)
    });
  }

  handleClear = () => this.setState({ films: [] });

  renderFilm = (film, { modifiers, handleClick }) => {
    if (!modifiers.matchesPredicate) {
      return null;
    }
    return (
      <MenuItem
        active={modifiers.active}
        icon={this.isFilmSelected(film) ? "tick" : "blank"}
        key={film.rank}
        label={film.year.toString()}
        onClick={handleClick}
        text={`${film.rank}. ${film.title}`}
        shouldDismissPopover={false}
      />
    );
  };

  handleTagRemove = (_tag, index) => {
    this.deselectFilm(index);
  };

  render() {
    const { films, ...rest } = this.state;

    const getTagProps = (_value, index) => ({
      intent: this.state.intent ? INTENTS[index % INTENTS.length] : Intent.NONE,
      minimal: false
    });

    const initialContent = this.state.hasInitialContent ? (
      <MenuItem
        disabled={true}
        text={`${filmSelectProps.items.length} items loaded.`}
      />
    ) : (
      // explicit undefined (not null) for default behavior (show full list)
      undefined
    );
    const clearButton =
      films.length > 0 ? (
        <Button icon="cross" minimal={true} onClick={this.handleClear} />
      ) : (
        <Button icon="caret-down" minimal={true} />
      );

    return (
      <StyledMultiSelect
        {...filmSelectProps}
        {...rest}
        initialContent={initialContent}
        itemRenderer={this.renderFilm}
        noResults={<MenuItem disabled={true} text="No results." />}
        onItemSelect={this.handleFilmSelect}
        popoverProps={{ minimal: false }}
        tagRenderer={film => film.title}
        tagInputProps={{
          tagProps: getTagProps,
          onRemove: this.handleTagRemove,
          rightElement: clearButton
        }}
        selectedItems={this.state.films}
      >
        {/* children become the popover target; render value here */}
        <Button
          text={filmSelectProps.items[0].title}
          rightIcon="double-caret-vertical"
        />
      </StyledMultiSelect>
    );
  }
}

MultiSelect.styles.jsx

import { Classes } from "@blueprintjs/core";
import styled from "styled-components";
import { MultiSelect as BpMulti } from "@blueprintjs/select";

const blue = "#038ace";
const darkerBlue = "#0086cc";

const MultiSelect = styled(BpMulti)`
  &&& {
    background-color: ${blue};
    border-radius: 10px;
    color: white;
    box-shadow: none;
    height: 50px;
    & .${Classes.INPUT} {
      border-radius: 10px;
      background-color: ${blue};
      height: 50px;
      display: flex;
      flex: 1;
      justify-content: center;
      align-items: center;
    }
    & .${Classes.INPUT_GHOST} {
      color: white;
      &::placeholder {
        color: white;
      }
    }
    & .${Classes.BUTTON} {
      display: flex;
    }
    & .${Classes.TAG} {
      background-color: white;
      color: black;
    }
    & .${Classes.ICON} {
      color: white;
    }
  }
`;

export default MultiSelect;

. js

import { MenuItem } from "@blueprintjs/core";
import { ItemPredicate, ItemRenderer } from "@blueprintjs/select";
import * as React from "react";

/** Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top */
export const TOP_100_FILMS = [
  { title: "The Shawshank Redemption", year: 1994 },
  { title: "The Godfather", year: 1972 },
  { title: "The Godfather: Part II", year: 1974 },
  { title: "The Dark Knight", year: 2008 },
  { title: "12 Angry Men", year: 1957 },
  { title: "Schindler's List", year: 1993 },
  { title: "Pulp Fiction", year: 1994 },
  { title: "The Lord of the Rings: The Return of the King", year: 2003 },
  { title: "The Good, the Bad and the Ugly", year: 1966 },
  { title: "Fight Club", year: 1999 },
  { title: "The Lord of the Rings: The Fellowship of the Ring", year: 2001 },
  { title: "Star Wars: Episode V - The Empire Strikes Back", year: 1980 },
  { title: "Forrest Gump", year: 1994 },
  { title: "Inception", year: 2010 },
  { title: "The Lord of the Rings: The Two Towers", year: 2002 }
].map((m, index) => ({ ...m, rank: index + 1 }));

export const renderFilm = (film, { handleClick, modifiers, query }) => {
  if (!modifiers.matchesPredicate) {
    return null;
  }
  const text = `${film.rank}. ${film.title}`;
  return (
    <MenuItem
      active={modifiers.active}
      label={film.year.toString()}
      key={film.rank}
      onClick={handleClick}
      text={highlightText(text, query)}
    />
  );
};

export const filterFilm = (query, film) => {
  return (
    `${film.rank}. ${film.title.toLowerCase()} ${film.year}`.indexOf(
      query.toLowerCase()
    ) >= 0
  );
};

function highlightText(text, query) {
  let lastIndex = 0;
  const words = query
    .split(/\s+/)
    .filter(word => word.length > 0)
    .map(escapeRegExpChars);
  if (words.length === 0) {
    return [text];
  }
  const regexp = new RegExp(words.join("|"), "gi");
  const tokens = [];
  while (true) {
    const match = regexp.exec(text);
    if (!match) {
      break;
    }
    const length = match[0].length;
    const before = text.slice(lastIndex, regexp.lastIndex - length);
    if (before.length > 0) {
      tokens.push(before);
    }
    lastIndex = regexp.lastIndex;
    tokens.push(<strong key={lastIndex}>{match[0]}</strong>);
  }
  const rest = text.slice(lastIndex);
  if (rest.length > 0) {
    tokens.push(rest);
  }
  return tokens;
}

function escapeRegExpChars(text) {
  return text.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

export const filmSelectProps = {
  itemPredicate: filterFilm,
  itemRenderer: renderFilm,
  items: TOP_100_FILMS
};

предварительный просмотр живого кода

...