UNPKG

@teamsnap/teamsnap-ui

Version:

a CSS component library for TeamSnap

226 lines (225 loc) 10.8 kB
"use strict"; /** * @name Combobox * * @description * A common combobox component that will render the appropriate styles. This calls the shared components InputControl * with all the appropriate options. See the teamsnap patterns library for more information. * https://teamsnap-ui-patterns.netlify.com/patterns/components/checkbox.html * * @example * <Combobox * name="birthdate" * buttonLabel="Birthdate" * searchLabel="Search for a year" * items={["2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013"]} /> * */ var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __spreadArray = (this && this.__spreadArray) || function (to, from) { for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) to[j] = from[i]; return to; }; Object.defineProperty(exports, "__esModule", { value: true }); var React = __importStar(require("react")); var PropTypes = __importStar(require("prop-types")); var lodash_1 = require("lodash"); var helpers_1 = require("../../utils/helpers"); var Panel_1 = require("../Panel"); var PanelFooter_1 = require("../PanelFooter"); var PanelBody_1 = require("../PanelBody"); var PanelRow_1 = require("../PanelRow"); var Button_1 = require("../Button"); var Checkbox_1 = require("../Checkbox"); var Field_1 = require("../Field"); var Icon_1 = require("../Icon"); var propTypes = { name: PropTypes.string.isRequired, buttonLabel: PropTypes.string, searchLabel: PropTypes.node, items: PropTypes.arrayOf(PropTypes.shape({ value: PropTypes.string, label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), subtext: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), })), selected: PropTypes.arrayOf(PropTypes.any), onChange: PropTypes.func, className: PropTypes.string, mods: PropTypes.string, style: PropTypes.object, testId: PropTypes.string, otherProps: PropTypes.object, disabled: PropTypes.bool, }; var ComboBox = function (_a) { var name = _a.name, buttonLabel = _a.buttonLabel, style = _a.style, testId = _a.testId, otherProps = _a.otherProps, disabled = _a.disabled, className = _a.className, selected = _a.selected, mods = _a.mods, items = _a.items, onChange = _a.onChange; var _b = React.useState(false), flyoutVisible = _b[0], toggleFlyout = _b[1]; var _c = React.useState(''), comboLabel = _c[0], setComboLabel = _c[1]; var _d = React.useState(false), hasFilters = _d[0], setHasFilters = _d[1]; var _e = React.useState(''), searchParam = _e[0], setSearchParam = _e[1]; var _f = React.useState([]), filterList = _f[0], setFilterList = _f[1]; var _g = React.useState([]), uncheckedfilterList = _g[0], setUncheckedFilterList = _g[1]; var _h = React.useState([]), selectedFilters = _h[0], setSelectedFilters = _h[1]; var shouldShowSearchBar = items.length > 6; var filteredItems = searchParam ? uncheckedfilterList.filter(function (item) { return item.label.toLowerCase().includes(searchParam.toLowerCase()); }) : uncheckedfilterList; var createLabel = function (comboboxItems) { return comboboxItems .reduce(function (prev, current) { return __spreadArray(__spreadArray([], prev), [items.find(function (item) { return item.value === current.value; }).label]); }, []) .join(', '); }; var sortFilters = function () { var checked = []; var unchecked = []; items.forEach(function (item) { if (selectedFilters.includes(item.value)) { checked.push(item); } else { unchecked.push(item); } }); setComboLabel(checked.length > 0 ? createLabel(checked) : buttonLabel); setFilterList(checked); setUncheckedFilterList(unchecked); if (selectedFilters.length > 0) { setHasFilters(true); } }; var clearFilters = function () { setSelectedFilters([]); setHasFilters(false); onChange([]); setSearchParam(''); setComboLabel(buttonLabel); }; var applyFilters = function () { if (!lodash_1.isEqual(selected, selectedFilters)) { if (selectedFilters.length > 0) { setComboLabel(createLabel(filterList)); setHasFilters(true); onChange(selectedFilters); } else { clearFilters(); } } sortFilters(); }; var filtersFromPropsAreDifferent = function (fromProps, currentFilters) { return ((fromProps === null || fromProps === void 0 ? void 0 : fromProps.length) !== (currentFilters || []).length || fromProps.some(function (item) { return !(currentFilters || []).includes(item); })); }; // Run this when the props change React.useEffect(function () { if (filtersFromPropsAreDifferent(selected, selectedFilters)) { setSelectedFilters(selected); applyFilters(); } }, [selected]); React.useEffect(function () { sortFilters(); }, []); // Set up handler when flyoutVisibility changes React.useEffect(function () { var handleBodyClick = function (e) { var isTargetingPopup = e.target.closest("#Combobox-" + name) != null; if (!isTargetingPopup) { toggleFlyout(false); } }; document.body.addEventListener('click', handleBodyClick, { capture: true }); return function () { document.body.removeEventListener('click', handleBodyClick); }; }, []); React.useEffect(function () { if (!flyoutVisible) { applyFilters(); } }, [flyoutVisible]); var buildCheckbox = function (filter, idx) { return (React.createElement(Checkbox_1.Checkbox, { key: name + "-" + idx, mods: "" + (idx === items.length - 1 ? 'u-padBottomNone' : ''), name: filter.value, label: filter.subtext ? (React.createElement(React.Fragment, null, filter.label, " ", React.createElement("span", { style: { color: '#7a7a7a' } }, "(", filter.subtext, ")"))) : (filter.label), inputProps: { checked: selectedFilters.includes(filter.value), value: filter.value, onChange: function () { if (selectedFilters.includes(filter.value)) { setSelectedFilters(selectedFilters.filter(function (selectedFilter) { return selectedFilter !== filter.value; })); } else { setSelectedFilters(__spreadArray(__spreadArray([], selectedFilters), [filter.value])); } }, } })); }; return (React.createElement("div", __assign({ id: "Combobox-" + name, className: helpers_1.getClassName(className, mods), style: style, "data-testid": testId }, otherProps), React.createElement("button", { type: "submit", className: "Combobox-toggle " + (hasFilters ? 'Combobox-toggle--active' : ''), name: name, id: name, "data-testid": "comboboxButton", disabled: disabled, title: comboLabel !== null && comboLabel !== void 0 ? comboLabel : '', onClick: function () { return toggleFlyout(!flyoutVisible); } }, comboLabel !== null && comboLabel !== void 0 ? comboLabel : buttonLabel), flyoutVisible && (React.createElement(Panel_1.Panel, { mods: "Combobox-checkboxContainer", "data-testid": "flyout" }, React.createElement(PanelBody_1.PanelBody, { mods: "Combobox-checkboxes" }, shouldShowSearchBar && (React.createElement(PanelRow_1.PanelRow, { mods: "Grid-cell u-flexAuto u-padBottomMd" }, React.createElement(Field_1.Field, { type: "input", formFieldProps: { inputProps: { value: searchParam, onChange: function (e) { return setSearchParam(e.target.value); }, }, placeholder: "Search for a " + buttonLabel, leftIcon: React.createElement(Icon_1.Icon, { className: "Icon", name: "search" }), }, name: "Sample" }))), (filterList === null || filterList === void 0 ? void 0 : filterList.length) > 0 && (React.createElement(PanelRow_1.PanelRow, { mods: "Grid-cell u-flexAuto u-padBottomSm" }, filterList.map(function (item, idx) { return buildCheckbox(item, idx); }))), (filteredItems === null || filteredItems === void 0 ? void 0 : filteredItems.length) > 0 && (React.createElement(PanelRow_1.PanelRow, null, filteredItems.map(function (item, idx) { return buildCheckbox(item, idx); })))), React.createElement(PanelFooter_1.PanelFooter, { mods: "u-padEndsSm u-padSidesMd" }, React.createElement(Button_1.Button, { onClick: function () { clearFilters(); toggleFlyout(false); }, mods: "u-spaceRightMd u-colorNeutral7", type: "link" }, "Clear"), React.createElement(Button_1.Button, { onClick: function () { return toggleFlyout(false); }, type: "link" }, "Done")))))); }; ComboBox.propTypes = propTypes; ComboBox.defaultProps = { mods: null, style: {}, testId: null, className: 'Combobox', otherProps: {}, selected: [], }; exports.default = ComboBox;