UNPKG

react-router-breadcrumbs-hoc

Version:

small, flexible, higher order component for rendering breadcrumbs with react-router 4.x

205 lines (173 loc) 6.21 kB
import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import React, { createElement } from 'react'; import { useLocation, matchPath } from 'react-router-dom'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } var DEFAULT_MATCH_OPTIONS = { exact: true }; var NO_BREADCRUMB = 'NO_BREADCRUMB'; var humanize = function humanize(str) { return str.replace(/^[\s_]+|[\s_]+$/g, '').replace(/[_\s]+/g, ' ').replace(/^[a-z]/, function (m) { return m.toUpperCase(); }); }; var render = function render(_a) { var Breadcrumb = _a.breadcrumb, match = _a.match, location = _a.location, rest = __rest(_a, ["breadcrumb", "match", "location"]); var componentProps = Object.assign({ match: match, location: location, key: match.url }, rest); return Object.assign(Object.assign({}, componentProps), { breadcrumb: typeof Breadcrumb === 'string' ? /*#__PURE__*/createElement('span', { key: componentProps.key }, Breadcrumb) : /*#__PURE__*/React.createElement(Breadcrumb, Object.assign({}, componentProps)) }); }; var getDefaultBreadcrumb = function getDefaultBreadcrumb(_ref) { var currentSection = _ref.currentSection, location = _ref.location, pathSection = _ref.pathSection; var match = matchPath(pathSection, Object.assign(Object.assign({}, DEFAULT_MATCH_OPTIONS), { path: pathSection })) || { url: 'not-found' }; return render({ breadcrumb: humanize(currentSection), match: match, location: location }); }; var getBreadcrumbMatch = function getBreadcrumbMatch(_ref2) { var currentSection = _ref2.currentSection, disableDefaults = _ref2.disableDefaults, excludePaths = _ref2.excludePaths, location = _ref2.location, pathSection = _ref2.pathSection, routes = _ref2.routes; var breadcrumb; var getIsPathExcluded = function getIsPathExcluded(path) { return matchPath(pathSection, { path: path, exact: true, strict: false }); }; if (excludePaths && excludePaths.some(getIsPathExcluded)) { return NO_BREADCRUMB; } routes.some(function (_a) { var userProvidedBreadcrumb = _a.breadcrumb, matchOptions = _a.matchOptions, path = _a.path, rest = __rest(_a, ["breadcrumb", "matchOptions", "path"]); if (!path) { throw new Error('withBreadcrumbs: `path` must be provided in every route object'); } var match = matchPath(pathSection, Object.assign(Object.assign({}, matchOptions || DEFAULT_MATCH_OPTIONS), { path: path })); if (match && userProvidedBreadcrumb === null || !match && matchOptions) { breadcrumb = NO_BREADCRUMB; return true; } if (match) { if (!userProvidedBreadcrumb && disableDefaults) { breadcrumb = NO_BREADCRUMB; return true; } breadcrumb = render(Object.assign({ breadcrumb: userProvidedBreadcrumb || humanize(currentSection), match: match, location: location }, rest)); return true; } return false; }); if (breadcrumb) { return breadcrumb; } if (disableDefaults) { return NO_BREADCRUMB; } return getDefaultBreadcrumb({ pathSection: pathSection, currentSection: pathSection === '/' ? 'Home' : currentSection, location: location }); }; var getBreadcrumbs = function getBreadcrumbs(_ref3) { var routes = _ref3.routes, location = _ref3.location, _ref3$options = _ref3.options, options = _ref3$options === void 0 ? {} : _ref3$options; var matches = []; var pathname = location.pathname; pathname.split('?')[0].split('/').reduce(function (previousSection, currentSection, index) { var pathSection = !currentSection ? '/' : "".concat(previousSection, "/").concat(currentSection); if (pathSection === '/' && index !== 0) { return ''; } var breadcrumb = getBreadcrumbMatch(Object.assign({ currentSection: currentSection, location: location, pathSection: pathSection, routes: routes }, options)); if (breadcrumb !== NO_BREADCRUMB) { matches.push(breadcrumb); } return pathSection === '/' ? '' : pathSection; }, ''); return matches; }; var flattenRoutes = function flattenRoutes(routes) { return routes.reduce(function (arr, route) { if (route.routes) { return arr.concat([route].concat(_toConsumableArray(flattenRoutes(route.routes)))); } return arr.concat(route); }, []); }; var withBreadcrumbs = function withBreadcrumbs(routes, options) { return function (Component) { return function (props) { return /*#__PURE__*/React.createElement(Component, Object.assign(Object.assign({}, props), { breadcrumbs: getBreadcrumbs({ options: options, routes: flattenRoutes(routes || []), location: useLocation() }) })); }; }; }; export default withBreadcrumbs; export { getBreadcrumbs };