├── demo
├── dist
│ ├── CNAME
│ └── index.html
├── .babelrc
├── src
│ ├── app.css
│ ├── crumb-route.jsx
│ ├── index.jsx
│ ├── locations.jsx
│ ├── events.jsx
│ ├── friends.jsx
│ └── app.jsx
├── webpack.dev.js
├── webpack.prod.js
├── package.json
└── README.md
├── .gitignore
├── .travis.yml
├── src
├── index.js
├── style.css
├── store.js
├── breadcrumb.jsx
└── breadcrumbs.jsx
├── .babelrc
├── bin
└── authors
├── .eslintrc
├── LICENSE
├── webpack.config.js
├── package.json
├── AUTHORS
├── CHANGELOG.md
├── README.md
└── dist
└── react-breadcrumbs.min.js
/demo/dist/CNAME:
--------------------------------------------------------------------------------
1 | breadcrumbs.surge.sh
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea
3 | npm-debug.log
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "node"
4 | - "8"
5 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export Breadcrumb from './breadcrumb.jsx'
2 | export Breadcrumbs from './breadcrumbs.jsx'
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "env", { "modules": false } ],
4 | "stage-0",
5 | "react"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/demo/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "env", { "modules": false } ],
4 | "stage-0",
5 | "react"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/demo/src/app.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Titillium+Web');
2 |
3 | body {
4 | font-size: 16px;
5 | margin: 0;
6 | font-family: 'Titillium Web', sans-serif;
7 | }
8 |
9 | .demo__main {
10 | max-width: 1280px;
11 | margin: 0 auto;
12 | padding: 0 1.5em;
13 | }
--------------------------------------------------------------------------------
/bin/authors:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | # Generate an AUTHORS file based on the output of git shortlog. It uses ABC
4 | # order, strips out leading spaces and numbers, then filters out specific
5 | # authors.
6 |
7 | git shortlog -se \
8 | | perl -spe 's/^\s+\d+\s+//' \
9 | | sed -e '/^CommitSyncScript.*$/d' \
10 | > AUTHORS
11 |
12 |
--------------------------------------------------------------------------------
/demo/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | React Breadcrumbs Demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "eslint:recommended",
4 | "plugin:react/recommended"
5 | ],
6 | "plugins": [
7 | "react"
8 | ],
9 | "parser": "babel-eslint",
10 | "parserOptions": {
11 | "ecmaVersion": 6,
12 | "sourceType": "module",
13 | "ecmaFeatures": {
14 | "jsx": true
15 | }
16 | },
17 | "env": {
18 | "browser": false,
19 | "node": true,
20 | "es6": true
21 | },
22 | "rules": {
23 | "semi": [ 2, "never" ]
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/demo/src/crumb-route.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react';
3 | import { Route } from 'react-router-dom';
4 |
5 | // Import Components
6 | import { Breadcrumb } from '../../src/index.js';
7 |
8 | // Create and export the component
9 | export default ({
10 | component: Component,
11 | includeSearch = false,
12 | render,
13 | ...props
14 | }) => (
15 | (
16 |
21 | { Component ? : render(routeProps) }
22 |
23 | )} />
24 | )
--------------------------------------------------------------------------------
/demo/src/index.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import { BrowserRouter } from 'react-router-dom';
5 |
6 | // Import Components
7 | import App from './app.jsx';
8 | import CrumbRoute from './crumb-route.jsx';
9 |
10 | // Define element and render method
11 | let element = document.getElementById('app'),
12 | render = Root => {
13 | ReactDOM.render((
14 |
15 |
16 |
17 | ), element);
18 | }
19 |
20 | // Initial render
21 | render(App)
22 |
23 | // Subsequent HMR renders
24 | if ( module.hot ) {
25 | module.hot.accept('./app.jsx', () => {
26 | render(App)
27 | })
28 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License (ISC)
2 |
3 | Copyright (c) 2015, Sven Anders Robbestad
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
6 |
7 | 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.
8 |
--------------------------------------------------------------------------------
/src/style.css:
--------------------------------------------------------------------------------
1 | .breadcrumbs {
2 | background: #dedede;
3 | }
4 |
5 | .breadcrumbs__inner {
6 | display: flex;
7 | height: 2em;
8 | max-width: 1280px;
9 | margin: 0 auto;
10 | padding: 0 1.5em;
11 | align-items: center;
12 | }
13 |
14 | .breadcrumbs__crumb {
15 | margin-right: 1em;
16 | text-transform: uppercase;
17 | text-decoration: none;
18 | color: #3498db;
19 | vertical-align: middle;
20 | transition: color 250ms;
21 | }
22 |
23 | .breadcrumbs__crumb:hover {
24 | color: #2980b9;
25 | }
26 |
27 | .breadcrumbs__crumb--active {
28 | pointer-events: none;
29 | color: #666;
30 | }
31 |
32 | .breadcrumbs__separator {
33 | margin-right: 1em;
34 | color: #e67e22;
35 | pointer-events: none;
36 | }
37 |
38 | .breadcrumbs--hidden {
39 | display: none;
40 | }
41 |
--------------------------------------------------------------------------------
/demo/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | module.exports = {
5 | devtool: 'source-map',
6 | entry: './src/index.jsx',
7 | module: {
8 | loaders: [
9 | {
10 | test: /\.jsx?$/,
11 | use: 'babel-loader',
12 | exclude: /node_modules/
13 | },
14 | {
15 | test: /\.css/,
16 | use: [
17 | 'style-loader',
18 | 'css-loader'
19 | ]
20 | }
21 | ]
22 | },
23 | plugins: [
24 | new webpack.HotModuleReplacementPlugin()
25 | ],
26 | output: {
27 | path: path.resolve(__dirname, 'dist'),
28 | filename: 'bundle.js'
29 | },
30 | devServer: {
31 | port: 3030,
32 | hot: true,
33 | inline: true,
34 | compress: true,
35 | historyApiFallback: true,
36 | contentBase: 'dist/'
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/demo/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | module.exports = {
5 | entry: './src/index.jsx',
6 | module: {
7 | loaders: [
8 | {
9 | test: /\.jsx?$/,
10 | use: 'babel-loader',
11 | exclude: /node_modules/
12 | },
13 | {
14 | test: /\.css/,
15 | use: [
16 | 'style-loader',
17 | 'css-loader'
18 | ]
19 | }
20 | ]
21 | },
22 | plugins: [
23 | new webpack.DefinePlugin({
24 | 'process.env': { NODE_ENV: '"production"' }
25 | }),
26 | new webpack.optimize.UglifyJsPlugin({
27 | compressor: {
28 | screw_ie8: true,
29 | drop_console: true,
30 | warnings: false
31 | }
32 | })
33 | ],
34 | output: {
35 | path: path.resolve(__dirname, 'dist'),
36 | filename: 'bundle.js'
37 | }
38 | }
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import { createStore } from 'redux'
3 |
4 | // Create the reducer
5 | let crumbs = (state = [], action) => {
6 | switch (action.type) {
7 | case 'ADD_CRUMB':
8 | return [
9 | ...state,
10 | action.payload
11 | ]
12 |
13 | case 'UPDATE_CRUMB':
14 | return state.map(crumb => {
15 | return crumb.id === action.payload.id ? action.payload : crumb
16 | })
17 |
18 | case 'REMOVE_CRUMB':
19 | return state.filter(crumb => {
20 | return crumb.id !== action.payload.id
21 | })
22 |
23 | default:
24 | return state
25 | }
26 | }
27 |
28 | // Create the store
29 | let store = createStore(crumbs)
30 |
31 | // Export store and Dispatch method
32 | export default store
33 | export var Dispatch = store.dispatch
34 |
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-breadcrumbs-demo",
3 | "version": "0.1.0",
4 | "description": "A small demo of the react-breadcrumbs package.",
5 | "main": "n/a",
6 | "scripts": {
7 | "start": "webpack-dev-server --config webpack.dev.js",
8 | "build": "webpack --config webpack.prod.js"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/svenanders/react-breadcrumbs.git"
13 | },
14 | "keywords": [
15 | "react-breadcrumbs",
16 | "demo"
17 | ],
18 | "author": "Greg Venech",
19 | "license": "ISC",
20 | "bugs": {
21 | "url": "https://github.com/svenanders/react-breadcrumbs/issues"
22 | },
23 | "homepage": "https://github.com/svenanders/react-breadcrumbs#readme",
24 | "devDependencies": {
25 | "babel-preset-env": "^1.6.1",
26 | "babel-preset-stage-0": "^6.24.1",
27 | "css-loader": "^0.28.7",
28 | "style-loader": "^0.18.2",
29 | "webpack": "^3.5.6",
30 | "webpack-dev-server": "^2.8.1"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/demo/src/locations.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react'
3 | import { Switch, NavLink } from 'react-router-dom'
4 |
5 | // Import Components
6 | import CrumbRoute from './crumb-route.jsx'
7 |
8 | // Define a small event page
9 | const Location = props => (
10 |
11 |
{ props.name }
12 |
More information about { props.name }...
13 |
14 | )
15 |
16 | // Create and export the component
17 | export default ({
18 | location,
19 | match,
20 | ...props
21 | }) => (
22 |
23 |
Locations
24 |
Some locations...
25 |
26 | Mexico
27 | China
28 |
29 |
30 |
31 | } />
32 | } />
33 |
34 |
35 | )
--------------------------------------------------------------------------------
/demo/src/events.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react'
3 | import { Switch, NavLink } from 'react-router-dom'
4 |
5 | // Import Components
6 | import CrumbRoute from './crumb-route.jsx'
7 |
8 | // Define a small event page
9 | const Event = props => (
10 |
11 |
{ props.name }
12 |
More information about the { props.name }...
13 |
14 | )
15 |
16 | // Create and export the component
17 | export default ({
18 | location,
19 | match,
20 | ...props
21 | }) => (
22 |
23 |
Upcoming Events
24 |
These events are coming up soon...
25 |
26 | Dance
27 | Cookout
28 |
29 |
30 |
31 | } />
32 | } />
33 |
34 |
35 | )
--------------------------------------------------------------------------------
/demo/README.md:
--------------------------------------------------------------------------------
1 | # React Breadcrumbs Demo
2 |
3 | This simple demo includes a variety of routes and very basic content to
4 | demonstrate clearly how `react-breadcrumbs` can easily be integrated into
5 | your application. It is compiled via `webpack` and the following scripts
6 | are available:
7 |
8 | - `npm start`: Start a local `webpack-dev-server` to test the site.
9 | - `npm run build`: Build a production version of the demo.
10 |
11 | Note that making an "enhanced route" component is only one method of using
12 | the `` component. It can also be used directly for throughout
13 | the application, dynamically at the top-level using the `hidden` prop, or
14 | in a variety of other ways.
15 |
16 | See the [`/src`][1] directory for all code. The `/dist` directory is auto
17 | generated and should not be edited.
18 |
19 |
20 | ## TODOs
21 |
22 | Note that we kept the site extremely simple intentionally. Obviously it
23 | would be better to dynamically create routes and links using data.
24 |
25 | We should also create a `webpack.common.js` file and use `webpack-merge`
26 | to dedupe the configurations. I think we could also simplify management
27 | of the HTML file either via the `HTMLWebpackPlugin` or the `CopyWebpackPlugin`
28 | so everything in `/dist` is truly auto-generated.
29 |
30 |
31 | [1]: https://github.com/svenanders/react-breadcrumbs/tree/master/demo/src
--------------------------------------------------------------------------------
/demo/src/friends.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react'
3 | import { Switch, NavLink } from 'react-router-dom'
4 |
5 | // Import Components
6 | import CrumbRoute from './crumb-route.jsx'
7 |
8 | // Define a small friend page
9 | const Friend = props => (
10 |
11 |
{ props.name }
12 |
More information about { props.name }...
13 |
14 | )
15 |
16 | // Create and export the component
17 | export default ({
18 | location,
19 | match,
20 | ...props
21 | }) => (
22 |
23 |
Your Friends
24 |
Here are your friends...
25 |
26 | Alice
27 | Frank
28 | Jane
29 | Matt
30 |
31 |
32 |
33 | } />
34 | } />
35 | } />
36 | } />
37 |
38 |
39 | )
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const path = require('path');
3 |
4 | module.exports = {
5 | devtool: 'source-map',
6 | entry: './src/index.js',
7 | module: {
8 | loaders: [
9 | {
10 | test: /\.jsx?$/,
11 | exclude: /node_modules/,
12 | use: [
13 | 'babel-loader',
14 | 'eslint-loader'
15 | ]
16 | }
17 | ]
18 | },
19 | plugins: [
20 | new webpack.DefinePlugin({
21 | 'process.env': { NODE_ENV: '"production"' }
22 | }),
23 | new webpack.optimize.UglifyJsPlugin({
24 | sourceMap: true,
25 | compressor: {
26 | screw_ie8: true,
27 | drop_console: true,
28 | warnings: false
29 | }
30 | })
31 | ],
32 | externals: {
33 | react: {
34 | root: 'React',
35 | commonjs2: 'react',
36 | commonjs: 'react',
37 | amd: 'react'
38 | },
39 | 'prop-types': {
40 | root: 'PropTypes',
41 | commonjs2: 'prop-types',
42 | commonjs: 'prop-types',
43 | amd: 'prop-types'
44 | },
45 | 'react-router-dom': {
46 | root: 'ReactRouterDOM',
47 | commonjs2: 'react-router-dom',
48 | commonjs: 'react-router-dom',
49 | amd: 'react-router-dom'
50 | }
51 | },
52 | output: {
53 | path: path.resolve(__dirname, 'dist'),
54 | filename: 'react-breadcrumbs.min.js',
55 | library: 'react-breadcrumbs',
56 | libraryTarget: 'umd'
57 | }
58 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-breadcrumbs",
3 | "version": "2.1.7",
4 | "description": "Automatic breadcrumbs for react-router",
5 | "author": "Sven Anders Robbestad ",
6 | "homepage": "https://github.com/svenanders/react-breadcrumbs",
7 | "license": "ISC",
8 | "main": "dist/react-breadcrumbs.min.js",
9 | "scripts": {
10 | "build": "webpack",
11 | "release": "standard-version"
12 | },
13 | "npmFileMap": [
14 | {
15 | "basePath": "/dist/",
16 | "files": [
17 | "*.js"
18 | ]
19 | }
20 | ],
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/svenanders/react-breadcrumbs.git"
24 | },
25 | "bugs": {
26 | "url": "https://github.com/svenanders/react-breadcrumbs/issues"
27 | },
28 | "keywords": [
29 | "react-component",
30 | "breadcrumbs",
31 | "react",
32 | "trail"
33 | ],
34 | "peerDependencies": {
35 | "react": "^15.0.0 || ^16.0.0",
36 | "react-router-dom": "^4.0.0 || ^5.0.0",
37 | "prop-types": "^15.5.7"
38 | },
39 | "devDependencies": {
40 | "babel-core": "^6.26.3",
41 | "babel-eslint": "^8.0.0",
42 | "babel-loader": "^7.1.2",
43 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
44 | "babel-preset-env": "^1.7.0",
45 | "babel-preset-react": "^6.5.0",
46 | "babel-preset-stage-0": "^6.24.1",
47 | "eslint": "^3.17.0",
48 | "eslint-loader": "^1.9.0",
49 | "eslint-plugin-react": "^7.3.0",
50 | "prop-types": "^15.5.8",
51 | "react": "^15.3.2",
52 | "react-dom": "^15.5.4",
53 | "react-router-dom": "^4.1.1",
54 | "standard-version": "^6.0.1",
55 | "webpack": "^3.5.6"
56 | },
57 | "dependencies": {
58 | "lodash.isequal": "^4.5.0",
59 | "redux": "^3.6.0",
60 | "uuid": "^3.0.1"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/breadcrumb.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react'
3 | import PropTypes from 'prop-types'
4 | import UUID from 'uuid'
5 | import IsEqual from 'lodash.isequal'
6 |
7 | // Import Utilities
8 | import { Dispatch } from './store'
9 |
10 | // Create and export the component
11 | export default class Breadcrumb extends React.Component {
12 | static propTypes = {
13 | data: PropTypes.object.isRequired,
14 | hidden: PropTypes.bool,
15 | children: PropTypes.element
16 | }
17 |
18 | static defaultProps = {
19 | hidden: false,
20 | children: null
21 | }
22 |
23 | state = {
24 | id: UUID.v4()
25 | }
26 |
27 | render() {
28 | return this.props.children
29 | }
30 |
31 | componentDidMount() {
32 | let { data, hidden } = this.props
33 |
34 | if ( !hidden ) this._dispatch('ADD_CRUMB', data)
35 | }
36 |
37 | componentWillReceiveProps(nextProps) {
38 | let { data, hidden } = nextProps
39 |
40 | // Update the crumb if its data has changed
41 | if ( !IsEqual(data, this.props.data) ) {
42 | this._dispatch('UPDATE_CRUMB', data)
43 | }
44 |
45 | // Remove/add crumb based on `hidden` prop
46 | if ( hidden && !this.props.hidden ) {
47 | this._dispatch('REMOVE_CRUMB', data)
48 |
49 | } else if ( !hidden && this.props.hidden ) {
50 | this._dispatch('ADD_CRUMB', data)
51 | }
52 | }
53 |
54 | componentWillUnmount() {
55 | this._dispatch(
56 | 'REMOVE_CRUMB',
57 | this.props.data
58 | )
59 | }
60 |
61 | /**
62 | * Dispatch the given `action`
63 | *
64 | * @param {string} action - A valid action name accepted by the store
65 | * @param {object} data - The breadcrumb data to pass
66 | */
67 | _dispatch(action, data) {
68 | let { id } = this.state
69 |
70 | Dispatch({
71 | type: action,
72 | payload: { id, ...data }
73 | })
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Alasdair
2 | Andrew Sullivan
3 | BALEHOK
4 | Benjamin Flesch
5 | Dany Ellement
6 | Derek Yau
7 | Dmitry Erman
8 | Erik Anderson
9 | FoxxMD
10 | Greg Venech
11 | Guilherme Caminha
12 | Jack Allan
13 | Jack Coulter
14 | Jeremy Greer
15 | Jonas Matser
16 | Joshua
17 | Konstantin Alekseev
18 | Lance Batson
19 | Lee Siong Chan
20 | Loris Guignard
21 | Luca Fabbri
22 | Mateusz Nowotyński
23 | Mateusz Zatorski
24 | Michael Tsyganov
25 | Noah Hall
26 | Pavel Vanecek
27 | Rahav lussato
28 | Ricardo Filipe Gonçalves Ribeiro
29 | Ricardo Ribeiro
30 | Ricky Miller
31 | Sharon Rolel
32 | Steve Fuller
33 | Sven A Robbestad
34 | Sven Anders Robbestad
35 | Sven Anders Robbestad
36 | Sven Anders Robbestad
37 | TheClark
38 | Thomas Wilson
39 | Tom Panier
40 | Varun Arora
41 | Vincent
42 | bakatrouble
43 | clodal
44 | dignifiedquire
45 |
--------------------------------------------------------------------------------
/demo/src/app.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react';
3 | import { Switch, NavLink, Route } from 'react-router-dom';
4 |
5 | // Import Components
6 | import { Breadcrumbs } from '../../src/index.js';
7 | import CrumbRoute from './crumb-route.jsx'
8 | import Friends from './friends.jsx'
9 | import Events from './events.jsx'
10 | import Locations from './locations.jsx'
11 |
12 | // Load Styling
13 | import '../../src/style.css';
14 | import './app.css';
15 |
16 | // Create and export the component
17 | export default class App extends React.Component {
18 | /**
19 | * Handle breadcrumb render
20 | * @param {[{}]} crumbs
21 | * @return {[{}]}
22 | */
23 | handleCrumbs = (crumbs) => {
24 | // Remove first crumb
25 | return crumbs.filter((c, i) => i !== 0)
26 | }
27 | render() {
28 | return (
29 |
30 |
31 |
32 | Breadcrumbs Demo
33 | Use the links below to jump around the site and watch the breadcrumbs update...
34 |
35 | Friends
36 | Events
37 | Locations
38 |
39 |
40 |
41 |
42 | Home content... } />
43 |
44 |
45 |
46 | Page not found... } />
47 |
48 |
49 |
50 |
51 | )
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ### [2.1.7](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.6...v2.1.7) (2019-06-14)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * allow usage with latest react-router version ([d4258e9](https://github.com/svenanders/react-breadcrumbs/commit/d4258e9))
11 |
12 |
13 |
14 |
15 | ## [2.1.6](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.5...v2.1.6) (2018-07-05)
16 |
17 |
18 |
19 |
20 | ## [2.1.5](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.4...v2.1.5) (2018-01-18)
21 |
22 |
23 |
24 |
25 | ## [2.1.4](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.3...v2.1.4) (2018-01-11)
26 |
27 |
28 |
29 |
30 | ## [2.1.3](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.2...v2.1.3) (2018-01-04)
31 |
32 |
33 | ### Bug Fixes
34 |
35 | * **breadcrumb:** allow no children to be passed ([2122618](https://github.com/svenanders/react-breadcrumbs/commit/2122618))
36 | * **demo:** update crumb-route ([0a0bd31](https://github.com/svenanders/react-breadcrumbs/commit/0a0bd31))
37 | * **deps:** allow the latest version of react ([0815c17](https://github.com/svenanders/react-breadcrumbs/commit/0815c17))
38 |
39 |
40 |
41 |
42 | ## [2.1.2](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.1...v2.1.2) (2017-10-24)
43 |
44 |
45 | ### Bug Fixes
46 |
47 | * fix “Cannot read property 'Component' of undefined” issue ([275ded1](https://github.com/svenanders/react-breadcrumbs/commit/275ded1))
48 |
49 |
50 |
51 |
52 | ## [2.1.1](https://github.com/svenanders/react-breadcrumbs/compare/v2.1.0...v2.1.1) (2017-10-19)
53 |
54 |
55 |
56 |
57 | # [2.1.0](https://github.com/svenanders/react-breadcrumbs/compare/v1.6.6...v2.1.0) (2017-10-14)
58 |
59 |
60 | ### Features
61 |
62 | * rewrite library to be compatible with react-router v4 ([0637464](https://github.com/svenanders/react-breadcrumbs/commit/0637464))
63 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Breadcrumbs
2 |
3 | [React][1] component use to generate a breadcrumb trail (compatible with
4 | [React Router][2]).
5 |
6 | ## Installation
7 |
8 | ```sh
9 | npm install --save react-breadcrumbs
10 | ```
11 |
12 | Note: this version is only compatible with React-Router v4 and up. If you
13 | need a version that is compatible with React-Router v3 and below, use
14 | ```
15 | npm install --save react-breadcrumbs@1.6.x
16 | ```
17 |
18 | ## Demo
19 |
20 | The `/demo` directory provide one example of how this
21 | package can be used. See the [`/demo`][3] for the code powering the small
22 | site.
23 |
24 | ## Usage
25 |
26 | This package exposes two components, a `` component to wrap
27 | the entire application and a `` component to use throughout
28 | the different sections (e.g. ``s) within the application.
29 |
30 | ### Breadcrumbs
31 |
32 | The top-level `` component accepts the following `props`:
33 |
34 | - `className` (string): A class name for the outer wrapper element.
35 | - `hidden` (bool): Hide the inner breadcrumbs wrapper.
36 | - `setCrumbs` (func): A `function(crumbs: [Object]): [Object]` which will be called before crumbs are rendered.
37 | - `wrapper` (func|class): A react component to use for the inner wrapper.
38 |
39 | ### Breadcrumb
40 |
41 | - `data` (object): An extended [location descriptor][5]. See below...
42 | - `hidden` (bool): Hide an individual breadcrumb (rarely needed).
43 |
44 | The `data` object allows any valid [location descriptor][5] key (e.g.
45 | `pathname` or `search`) as well as a `title` prop:
46 |
47 | ``` js
48 | {
49 | title: 'Home', // Any valid `PropTypes.node`
50 | pathname: '/',
51 | // ... any other location descriptor values
52 | }
53 | ```
54 |
55 | The fact that the `title` can be any valid `PropTypes.node` allows for a huge
56 | amount of customization. The following values are all valid:
57 |
58 | ``` jsx
59 | title: 'Home'
60 | title: Home
61 | title:
62 | ```
63 |
64 | ### Authors
65 |
66 | This project would not have been where it is today without massive contributions from
67 | a whole lot of people ([`AUTHORS`][6]). Suport for React Router v4 support was written
68 | entirely by ([`@skipjack`][7]).
69 |
70 | [1]: https://facebook.github.io/react
71 | [2]: https://github.com/rackt/react-router
72 | [3]: https://github.com/svenanders/react-breadcrumbs/tree/master/demo
73 | [4]: http://breadcrumbs.surge.sh/index.html
74 | [5]: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/location.md
75 | [6]: https://github.com/svenanders/react-breadcrumbs/tree/master/AUTHORS
76 | [7]: https://github.com/skipjack
77 |
--------------------------------------------------------------------------------
/src/breadcrumbs.jsx:
--------------------------------------------------------------------------------
1 | // Import External Dependencies
2 | import React from 'react'
3 | import PropTypes from 'prop-types'
4 |
5 | // TODO: Use imitation and allow it to be passed as a prop
6 | import { NavLink } from 'react-router-dom'
7 |
8 | // Import Utilities
9 | import Store from './store'
10 |
11 | // Specify BEM block name
12 | const block = 'breadcrumbs'
13 |
14 | // Create and export the component
15 | export default class Breadcrumbs extends React.Component {
16 | static propTypes = {
17 | className: PropTypes.string,
18 | hidden: PropTypes.bool,
19 | separator: PropTypes.node,
20 | setCrumbs: PropTypes.func,
21 | wrapper: PropTypes.oneOfType([
22 | PropTypes.func,
23 | PropTypes.instanceOf(
24 | React.Component
25 | )
26 | ]),
27 | children: PropTypes.oneOfType([
28 | PropTypes.node,
29 | PropTypes.arrayOf(
30 | PropTypes.node
31 | )
32 | ])
33 | }
34 |
35 | static defaultProps = {
36 | className: '',
37 | hidden: false,
38 | separator: '>',
39 | setCrumbs: undefined,
40 | wrapper: props => (
41 |
42 | { props.children }
43 |
44 | )
45 | }
46 |
47 | _unsubscribe = null
48 |
49 | render() {
50 | let { className, hidden, wrapper: Wrapper, setCrumbs } = this.props,
51 | hiddenMod = hidden ? `${block}--hidden` : '',
52 | crumbs = Store.getState()
53 |
54 | crumbs = crumbs.sort((a, b) => {
55 | return a.pathname.length - b.pathname.length
56 | })
57 |
58 | if (setCrumbs) crumbs = setCrumbs(crumbs)
59 |
60 | return (
61 |
62 |
63 |
64 | {
65 | crumbs.map((crumb, i) => (
66 |
67 |
76 | { crumb.title }
77 |
78 |
79 | { i < crumbs.length - 1 ? (
80 |
81 | { this.props.separator }
82 |
83 | ) : null }
84 |
85 | ))
86 | }
87 |
88 |
89 |
90 | { this.props.children }
91 |
92 | )
93 | }
94 |
95 | componentWillMount() {
96 | this._unsubscribe = Store.subscribe(() => {
97 | this.forceUpdate()
98 | })
99 | }
100 |
101 | componentWillUnmount() {
102 | this._unsubscribe()
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/dist/react-breadcrumbs.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("react"),require("prop-types"),require("react-router-dom")):"function"==typeof define&&define.amd?define(["react","prop-types","react-router-dom"],e):"object"==typeof exports?exports["react-breadcrumbs"]=e(require("react"),require("prop-types"),require("react-router-dom")):t["react-breadcrumbs"]=e(t.React,t.PropTypes,t.ReactRouterDOM)}(this,function(t,e,r){return function(t){function e(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var r={};return e.m=t,e.c=r,e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=12)}([function(t,e){var r;r=function(){return this}();try{r=r||Function("return this")()||(0,eval)("this")}catch(t){"object"==typeof window&&(r=window)}t.exports=r},function(e,r){e.exports=t},function(t,r){t.exports=e},function(t,e,r){(function(e){var r,n=e.crypto||e.msCrypto;if(n&&n.getRandomValues){var o=new Uint8Array(16);r=function(){return n.getRandomValues(o),o}}if(!r){var i=new Array(16);r=function(){for(var t,e=0;e<16;e++)0==(3&e)&&(t=4294967296*Math.random()),i[e]=t>>>((3&e)<<3)&255;return i}}t.exports=r}).call(e,r(0))},function(t,e){function r(t,e){var r=e||0,o=n;return o[t[r++]]+o[t[r++]]+o[t[r++]]+o[t[r++]]+"-"+o[t[r++]]+o[t[r++]]+"-"+o[t[r++]]+o[t[r++]]+"-"+o[t[r++]]+o[t[r++]]+"-"+o[t[r++]]+o[t[r++]]+o[t[r++]]+o[t[r++]]+o[t[r++]]+o[t[r++]]}for(var n=[],o=0;o<256;++o)n[o]=(o+256).toString(16).substr(1);t.exports=r},function(t,e){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,e,r){"use strict";function n(t){if(Array.isArray(t)){for(var e=0,r=Array(t.length);e0&&void 0!==arguments[0]?arguments[0]:[],e=arguments[1];switch(e.type){case"ADD_CRUMB":return[].concat(n(t),[e.payload]);case"UPDATE_CRUMB":return t.map(function(t){return t.id===e.payload.id?e.payload:t});case"REMOVE_CRUMB":return t.filter(function(t){return t.id!==e.payload.id});default:return t}},a=Object(o.a)(i);e.b=a;var c=a.dispatch},function(t,e,r){"use strict";function n(t,e,r){function i(){y===v&&(y=v.slice())}function u(){return b}function s(t){if("function"!=typeof t)throw new Error("Expected listener to be a function.");var e=!0;return i(),y.push(t),function(){if(e){e=!1,i();var r=y.indexOf(t);y.splice(r,1)}}}function f(t){if(!Object(o.a)(t))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if(void 0===t.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(_)throw new Error("Reducers may not dispatch actions.");try{_=!0,b=h(b,t)}finally{_=!1}for(var e=v=y,r=0;rs)&&void 0===t.nsecs&&(p=0),p>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");s=l,f=p,u=a,l+=122192928e5;var h=(1e4*(268435455&l)+p)%4294967296;o[n++]=h>>>24&255,o[n++]=h>>>16&255,o[n++]=h>>>8&255,o[n++]=255&h;var b=l/4294967296*1e4&268435455;o[n++]=b>>>8&255,o[n++]=255&b,o[n++]=b>>>24&15|16,o[n++]=b>>>16&255,o[n++]=a>>>8|128,o[n++]=255&a;for(var v=t.node||c,y=0;y<6;++y)o[n+y]=v[y];return e||i(o)}var o=r(3),i=r(4),a=o(),c=[1|a[0],a[1],a[2],a[3],a[4],a[5]],u=16383&(a[6]<<8|a[7]),s=0,f=0;t.exports=n},function(t,e,r){function n(t,e,r){var n=e&&r||0;"string"==typeof t&&(e="binary"==t?new Array(16):null,t=null),t=t||{};var a=t.random||(t.rng||o)();if(a[6]=15&a[6]|64,a[8]=63&a[8]|128,e)for(var c=0;c<16;++c)e[n+c]=a[c];return e||i(a)}var o=r(3),i=r(4);t.exports=n},function(t,e,r){(function(t,r){function n(t,e){for(var r=-1,n=null==t?0:t.length,o=0,i=[];++r-1}function w(t,e){var r=this.__data__,n=I(r,t);return n<0?(++this.size,r.push([t,e])):r[n][1]=e,this}function O(t){var e=-1,r=null==t?0:t.length;for(this.clear();++es))return!1;var l=a.get(t);if(l&&a.get(e))return l==e;var p=-1,d=!0,h=r&mt?new M:void 0;for(a.set(t,e),a.set(e,t);++p-1&&t%1==0&&t-1&&t%1==0&&t<=gt}function pt(t){var e=typeof t;return null!=t&&("object"==e||"function"==e)}function dt(t){return null!=t&&"object"==typeof t}function ht(t){return ut(t)?D(t):H(t)}function bt(){return[]}function vt(){return!1}var yt=200,_t="__lodash_hash_undefined__",jt=1,mt=2,gt=9007199254740991,wt="[object Arguments]",Ot="[object Array]",Et="[object AsyncFunction]",xt="[object Boolean]",At="[object Date]",Pt="[object Error]",kt="[object Function]",Mt="[object GeneratorFunction]",Rt="[object Map]",zt="[object Number]",Tt="[object Null]",St="[object Object]",Ut="[object Proxy]",Ct="[object RegExp]",Nt="[object Set]",Bt="[object String]",Dt="[object Symbol]",It="[object Undefined]",qt="[object ArrayBuffer]",Ft="[object DataView]",Wt=/[\\^$.*+?()[\]{}|]/g,Vt=/^\[object .+?Constructor\]$/,$t=/^(?:0|[1-9]\d*)$/,Lt={};Lt["[object Float32Array]"]=Lt["[object Float64Array]"]=Lt["[object Int8Array]"]=Lt["[object Int16Array]"]=Lt["[object Int32Array]"]=Lt["[object Uint8Array]"]=Lt["[object Uint8ClampedArray]"]=Lt["[object Uint16Array]"]=Lt["[object Uint32Array]"]=!0,Lt[wt]=Lt[Ot]=Lt[qt]=Lt[xt]=Lt[Ft]=Lt[At]=Lt[Pt]=Lt[kt]=Lt[Rt]=Lt[zt]=Lt[St]=Lt[Ct]=Lt[Nt]=Lt[Bt]=Lt["[object WeakMap]"]=!1;var Gt="object"==typeof t&&t&&t.Object===Object&&t,Ht="object"==typeof self&&self&&self.Object===Object&&self,Jt=Gt||Ht||Function("return this")(),Kt="object"==typeof e&&e&&!e.nodeType&&e,Qt=Kt&&"object"==typeof r&&r&&!r.nodeType&&r,Xt=Qt&&Qt.exports===Kt,Yt=Xt&&Gt.process,Zt=function(){try{return Yt&&Yt.binding&&Yt.binding("util")}catch(t){}}(),te=Zt&&Zt.isTypedArray,ee=Array.prototype,re=Function.prototype,ne=Object.prototype,oe=Jt["__core-js_shared__"],ie=re.toString,ae=ne.hasOwnProperty,ce=function(){var t=/[^.]+$/.exec(oe&&oe.keys&&oe.keys.IE_PROTO||"");return t?"Symbol(src)_1."+t:""}(),ue=ne.toString,se=RegExp("^"+ie.call(ae).replace(Wt,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),fe=Xt?Jt.Buffer:void 0,le=Jt.Symbol,pe=Jt.Uint8Array,de=ne.propertyIsEnumerable,he=ee.splice,be=le?le.toStringTag:void 0,ve=Object.getOwnPropertySymbols,ye=fe?fe.isBuffer:void 0,_e=function(t,e){return function(r){return t(e(r))}}(Object.keys,Object),je=Z(Jt,"DataView"),me=Z(Jt,"Map"),ge=Z(Jt,"Promise"),we=Z(Jt,"Set"),Oe=Z(Jt,"WeakMap"),Ee=Z(Object,"create"),xe=at(je),Ae=at(me),Pe=at(ge),ke=at(we),Me=at(Oe),Re=le?le.prototype:void 0,ze=Re?Re.valueOf:void 0;l.prototype.clear=p,l.prototype.delete=d,l.prototype.get=h,l.prototype.has=b,l.prototype.set=v,y.prototype.clear=_,y.prototype.delete=j,y.prototype.get=m,y.prototype.has=g,y.prototype.set=w,O.prototype.clear=E,O.prototype.delete=x,O.prototype.get=A,O.prototype.has=P,O.prototype.set=k,M.prototype.add=M.prototype.push=R,M.prototype.has=z,T.prototype.clear=S,T.prototype.delete=U,T.prototype.get=C,T.prototype.has=N,T.prototype.set=B;var Te=ve?function(t){return null==t?[]:(t=Object(t),n(ve(t),function(e){return de.call(t,e)}))}:bt,Se=F;(je&&Se(new je(new ArrayBuffer(1)))!=Ft||me&&Se(new me)!=Rt||ge&&"[object Promise]"!=Se(ge.resolve())||we&&Se(new we)!=Nt||Oe&&"[object WeakMap]"!=Se(new Oe))&&(Se=function(t){var e=F(t),r=e==St?t.constructor:void 0,n=r?at(r):"";if(n)switch(n){case xe:return Ft;case Ae:return Rt;case Pe:return"[object Promise]";case ke:return Nt;case Me:return"[object WeakMap]"}return e});var Ue=W(function(){return arguments}())?W:function(t){return dt(t)&&ae.call(t,"callee")&&!de.call(t,"callee")},Ce=Array.isArray,Ne=ye||vt,Be=te?function(t){return function(e){return t(e)}}(te):G;r.exports=st}).call(e,r(0),r(5)(t))},function(t,e,r){"use strict";var n=r(7);r(30),r(31),r(32),r(11),r(10);r.d(e,"a",function(){return n.b})},function(t,e,r){"use strict";function n(t){return null==t?void 0===t?u:c:s&&s in Object(t)?Object(i.a)(t):Object(a.a)(t)}var o=r(9),i=r(22),a=r(23),c="[object Null]",u="[object Undefined]",s=o.a?o.a.toStringTag:void 0;e.a=n},function(t,e,r){"use strict";var n=r(21),o="object"==typeof self&&self&&self.Object===Object&&self,i=n.a||o||Function("return this")();e.a=i},function(t,e,r){"use strict";(function(t){var r="object"==typeof t&&t&&t.Object===Object&&t;e.a=r}).call(e,r(0))},function(t,e,r){"use strict";function n(t){var e=a.call(t,u),r=t[u];try{t[u]=void 0;var n=!0}catch(t){}var o=c.call(t);return n&&(e?t[u]=r:delete t[u]),o}var o=r(9),i=Object.prototype,a=i.hasOwnProperty,c=i.toString,u=o.a?o.a.toStringTag:void 0;e.a=n},function(t,e,r){"use strict";function n(t){return i.call(t)}var o=Object.prototype,i=o.toString;e.a=n},function(t,e,r){"use strict";var n=r(25),o=Object(n.a)(Object.getPrototypeOf,Object);e.a=o},function(t,e,r){"use strict";function n(t,e){return function(r){return t(e(r))}}e.a=n},function(t,e,r){"use strict";function n(t){return null!=t&&"object"==typeof t}e.a=n},function(t,e,r){t.exports=r(28)},function(t,e,r){"use strict";(function(t,n){Object.defineProperty(e,"__esModule",{value:!0});var o,i=r(29),a=function(t){return t&&t.__esModule?t:{default:t}}(i);o="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==t?t:n;var c=(0,a.default)(o);e.default=c}).call(e,r(0),r(5)(t))},function(t,e,r){"use strict";function n(t){var e,r=t.Symbol;return"function"==typeof r?r.observable?e=r.observable:(e=r("observable"),r.observable=e):e="@@observable",e}Object.defineProperty(e,"__esModule",{value:!0}),e.default=n},function(t,e,r){"use strict";r(7),r(8),r(10)},function(t,e,r){"use strict"},function(t,e,r){"use strict";r(11),Object.assign},function(t,e,r){"use strict";function n(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}var a=r(1),c=r.n(a),u=r(2),s=r.n(u),f=r(34),l=(r.n(f),r(6)),p=function(){function t(t,e){for(var r=0;r",setCrumbs:void 0,wrapper:function(t){return c.a.createElement("nav",t,t.children)}},e.a=h},function(t,e){t.exports=r}])});
2 | //# sourceMappingURL=react-breadcrumbs.min.js.map
--------------------------------------------------------------------------------