UNPKG

armstrong-react

Version:

Rocketmakers Armstrong library of React components

195 lines (194 loc) 12.5 kB
"use strict"; var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var React = require("react"); var ReactDOM = require("react-dom"); var _ = require("underscore"); var icon_1 = require('./../display/icon'); var grid_1 = require('./../layout/grid'); var button_1 = require('./../interaction/button'); var DropdownSelect = (function (_super) { __extends(DropdownSelect, _super); function DropdownSelect(props) { _super.call(this, props); this.itemHeight = 52; this.state = { filteredOptions: [], query: "", open: false, selectedValue: props.multiSelect ? [] : null, selectedIndex: 0, remoteSearching: false, offsetIndex: 0 }; } DropdownSelect.prototype.filterRemote = function (query, immediate) { var _this = this; if (this.timer) { window.clearTimeout(this.timer); } this.timer = window.setTimeout(function () { _this.setState({ remoteSearching: true }); _this.props.remoteQuery(query).then(function (filteredOptions) { _this.setState({ filteredOptions: filteredOptions, remoteSearching: false }); }); }, immediate ? 0 : this.props.remoteThrottle); }; DropdownSelect.prototype.filter = function (query) { var _this = this; var q = query.toLowerCase(); if (this.props.remoteQuery) { this.filterRemote(query); } else { if (query.length < this.props.minimumLength) { this.setState({ filteredOptions: this.props.options, query: query }, function () { return _this.constrainIndex(); }); } else { this.setState({ filteredOptions: _.reject(this.props.options, function (o) { return o.name.toLowerCase().indexOf(q) === -1; }), query: query }, function () { return _this.constrainIndex(); }); ; } } }; DropdownSelect.prototype.focusInput = function (e) { var _this = this; if (!this.state.open && !e.target.classList.contains("clear-selected")) { this.setState({ open: true }, function () { ReactDOM.findDOMNode(_this).querySelector("input").focus(); document.addEventListener("click", _this, false); if (_this.props.remoteQueryOnOpen) { _this.filterRemote("", true); } }); } else { } }; DropdownSelect.prototype.handleEvent = function (e) { if (ReactDOM.findDOMNode(this).contains(e.target) || e.target.classList.contains("multi-select-item-part")) { return; } this.setState({ open: false, query: "", filteredOptions: this.props.options || [] }); document.removeEventListener("click", this, false); }; DropdownSelect.prototype.componentWillMount = function () { var selectedValue = this.props.multiSelect ? [] : null; if (this.props.value) { selectedValue = this.props.value; } this.setState({ filteredOptions: this.props.options || [], selectedValue: selectedValue }); }; DropdownSelect.prototype.componentWillReceiveProps = function (newProps) { if (this.props.multiSelect) { var newMultiValue = newProps.value; var oldMultiValue = this.state.selectedValue; if (oldMultiValue.length === 0 || !_.isEqual(newMultiValue.map(function (v) { return v.id; }), oldMultiValue.map(function (v) { return v.id; }))) { this.setState({ selectedValue: newMultiValue }); } } else { var newSingleValue = newProps.value; var oldSingleValue = this.state.selectedValue; if (!oldSingleValue || newSingleValue.id !== oldSingleValue.id) { this.setState({ selectedValue: newSingleValue }); } } }; DropdownSelect.prototype.checkKey = function (e) { var currentIndex = this.state.selectedIndex; if (e.keyCode === 27) { this.setState({ open: false, query: "", filteredOptions: this.props.options || [] }); } if (e.keyCode === 40 && this.state.filteredOptions.length !== 0) { var offsetIndex = Math.min((this.props.visibleItems || 3) - 1, this.state.offsetIndex + 1); var selectedIndex = Math.min(this.state.selectedIndex + 1, this.state.filteredOptions.length - 1); var listElement = ReactDOM.findDOMNode(this).querySelector(".dropdown-select-list"); this.setState({ offsetIndex: offsetIndex }); if (offsetIndex >= 2) { listElement.scrollTop = (selectedIndex - 2) * this.itemHeight; } var selectedItem = this.state.filteredOptions[selectedIndex]; this.setState({ selectedIndex: selectedIndex, query: selectedItem.name }); e.preventDefault(); return false; } if (e.keyCode === 38 && this.state.filteredOptions.length !== 0) { var offsetIndex = Math.max(this.state.offsetIndex - 1, 0); var selectedIndex = Math.max(this.state.selectedIndex - 1, 0); var listElement = ReactDOM.findDOMNode(this).querySelector(".dropdown-select-list"); this.setState({ offsetIndex: offsetIndex }); if (offsetIndex === 0) { listElement.scrollTop = (selectedIndex) * this.itemHeight; } var selectedItem = this.state.filteredOptions[selectedIndex]; this.setState({ selectedIndex: selectedIndex, query: selectedItem.name }); e.preventDefault(); return false; } if (e.keyCode === 13 && this.state.filteredOptions.length !== 0) { var selectedValue = this.state.filteredOptions[this.state.selectedIndex]; this.handleSelection(selectedValue); e.preventDefault(); return false; } this.filter(e.target.value); }; DropdownSelect.prototype.constrainIndex = function () { if (this.state.selectedIndex > this.state.filteredOptions.length - 1) { this.setState({ selectedIndex: Math.max(this.state.filteredOptions.length - 1, 0) }); } }; DropdownSelect.prototype.handleSelection = function (options) { if (this.props.multiSelect) { var newOptions = options; if (!_.isArray(options)) { newOptions = [options]; } var ddOptions = this.state.selectedValue; newOptions.forEach(function (option) { if (ddOptions.length !== 0 && _.some(ddOptions, function (ddo) { return ddo.id === option.id; })) { ddOptions = _.reject(ddOptions, function (ddo) { return ddo.id === option.id; }); } else { ddOptions.push(option); } }); this.setState({ selectedValue: ddOptions }); if (this.props.onSelected) { this.props.onSelected(ddOptions); } ReactDOM.findDOMNode(this).querySelector("input").focus(); } else { var option = options; this.setState({ selectedValue: option, open: false, query: "", filteredOptions: this.props.options || [], offsetIndex: 0 }); if (this.props.onSelected) { this.props.onSelected(option); } document.removeEventListener("click", this, false); } }; DropdownSelect.prototype.buttonClick = function () { if (this.state.filteredOptions.length !== 0) { var selectedValue = this.state.filteredOptions[this.state.selectedIndex]; if (selectedValue) { this.handleSelection(selectedValue); } } }; DropdownSelect.prototype.render = function () { var _this = this; return (React.createElement(grid_1.Grid, {onClick: function (e) { return _this.focusInput(e); }, className: "dropdown-select" + (this.props.className ? " " + this.props.className : '') + (this.props.disabled ? ' disabled' : '') + (this.props.hasGoButton && !this.props.multiSelect ? ' has-go-button' : '') + (this.props.multiSelect && this.state.selectedValue.length !== 0 ? ' has-multiple-options' : '')}, React.createElement(grid_1.Row, null, React.createElement(grid_1.Col, {className: "drop-down-controls"}, (!this.state.open || this.props.multiSelect) && React.createElement(grid_1.Grid, {className: "dropdown-value-display"}, React.createElement(grid_1.Row, null, React.createElement(grid_1.Col, null, this.state.selectedValue && React.createElement("div", {className: "selected-value-wrapper"}, this.props.multiSelect ? this.state.selectedValue.map(function (ddo) { return React.createElement("div", {key: "multi-select-item-" + ddo.id, className: "multi-select-item multi-select-item-part", onClick: function () { return _this.handleSelection(ddo); }}, ddo.name, React.createElement(icon_1.Icon, {className: "multi-select-item-part", icon: icon_1.Icon.Icomoon.cross})); }) : this.state.selectedValue.name), (this.props.multiSelect && this.state.selectedValue.length === 0) && React.createElement("div", {className: "placeholder"}, this.props.placeholder || "start typing to filter results..."), !this.props.multiSelect && this.state.selectedValue === null && React.createElement("div", {className: "placeholder"}, this.props.placeholder || "start typing to filter results...")), !this.props.multiSelect && this.state.selectedValue && this.props.canClear && React.createElement(grid_1.Col, {fixed: true, className: "clear-selected p-right-xsmall", onClick: function () { return _this.setState({ selectedValue: _this.props.multiSelect ? [] : null, open: false, query: "", filteredOptions: _this.props.options || [] }); }}, React.createElement(icon_1.Icon, {icon: icon_1.Icon.Icomoon.cross})), this.props.multiSelect && this.state.selectedValue.length !== 0 && this.props.canClear && React.createElement(grid_1.Col, {fixed: true, className: "clear-selected p-right-xsmall", onClick: function () { return _this.setState({ selectedValue: _this.props.multiSelect ? [] : null, open: false, query: "", filteredOptions: _this.props.options || [] }); }}, React.createElement(icon_1.Icon, {icon: icon_1.Icon.Icomoon.cross})))), this.state.open && React.createElement("div", {className: "dropdown-select-list-wrapper"}, React.createElement("input", {type: "text", value: this.state.query, onKeyUp: function (e) { return _this.checkKey(e); }, onChange: function (e) { return _this.setState({ query: e.target.value }); }, placeholder: this.props.placeholder || "start typing to filter results..."}), this.state.remoteSearching && React.createElement(icon_1.Icon, {className: "spinner fg-info", icon: icon_1.Icon.Icomoon.spinner2}), React.createElement("div", {"data-id": "dropdown-select-list", className: "dropdown-select-list", style: { maxHeight: (this.props.visibleItems || 3) * this.itemHeight + "px" }}, this.state.filteredOptions && this.state.filteredOptions.map(function (o, i) { return React.createElement("div", {"data-index": i, key: "dd-item-" + i, className: "dd-list-item" + (i === _this.state.selectedIndex ? ' selected' : '') + ((_this.props.multiSelect && _.some(_this.state.selectedValue, function (ddo) { return ddo.id === o.id; })) ? ' in-selected-list' : ''), onClick: function () { return _this.handleSelection(o); }}, o.name); }), this.state.filteredOptions.length === 0 && this.state.query && React.createElement("div", {className: "dd-list-item-no-select"}, this.props.noResultsMessage || "No results...")))), this.props.hasGoButton && !this.props.multiSelect && React.createElement(grid_1.Col, {fixed: true}, React.createElement(button_1.Button, {text: this.props.goButtonContent || "Go", className: "bg-positive", onClick: function () { return _this.buttonClick(); }}))))); }; DropdownSelect.defaultProps = { remoteThrottle: 500, minimumLength: 1 }; return DropdownSelect; }(React.Component)); exports.DropdownSelect = DropdownSelect;