Я пытаюсь реализовать несколько выбранных пользовательских компонентов с использованием компонентов в стиле реакции. Это не работает, я просмотрел документацию, и это было настолько интуитивно понятно. Я попробовал приведенный ниже код. Любая помощь будет оценена. Заранее спасибо.
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
};
предварительный просмотр живого кода