@teamsnap/teamsnap-ui
Version:
a CSS component library for TeamSnap
226 lines (225 loc) • 10.8 kB
JavaScript
;
/**
* @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;