piral-breadcrumbs 1.5.3-beta.6894 → 1.5.3-beta.6919
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/esm/Breadcrumbs.js +44 -9
- package/esm/Breadcrumbs.js.map +1 -1
- package/esm/types.d.ts +0 -2
- package/lib/Breadcrumbs.js +44 -9
- package/lib/Breadcrumbs.js.map +1 -1
- package/lib/types.d.ts +0 -2
- package/package.json +5 -7
- package/piral-breadcrumbs.min.js +1 -1
- package/src/Breadcrumbs.test.tsx +7 -47
- package/src/Breadcrumbs.tsx +60 -17
- package/src/types.ts +0 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[](https://piral.io)
|
|
2
2
|
|
|
3
|
-
# [Piral Breadcrumbs](https://piral.io) · [](https://github.com/smapiot/piral/blob/main/LICENSE) [](https://www.npmjs.com/package/piral-breadcrumbs) [](https://jestjs.io) [ · [](https://github.com/smapiot/piral/blob/main/LICENSE) [](https://www.npmjs.com/package/piral-breadcrumbs) [](https://jestjs.io) [](https://discord.gg/kKJ2FZmK8t)
|
|
4
4
|
|
|
5
5
|
This is plugin that only has a peer dependency to `piral-core`. What `piral-breadcrumbs` brings to the table is a set of Pilet API extensions that can be used with `piral` or `piral-core`.
|
|
6
6
|
|
package/esm/Breadcrumbs.js
CHANGED
|
@@ -1,30 +1,65 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useGlobalStateContext } from 'piral-core';
|
|
3
3
|
import { PiralBreadcrumbsContainer, PiralBreadcrumbItem } from './components';
|
|
4
4
|
import { useBreadcrumbs } from './useBreadcrumbs';
|
|
5
|
-
|
|
5
|
+
const getKey = /:(([A-Za-z0-9_]+)\*?)/g;
|
|
6
|
+
function getContent(title, path, params) {
|
|
6
7
|
if (typeof title === 'function') {
|
|
7
|
-
return title({
|
|
8
|
+
return title({ path, params });
|
|
8
9
|
}
|
|
9
10
|
return title;
|
|
10
11
|
}
|
|
12
|
+
function useNavigationPath() {
|
|
13
|
+
const { navigation } = useGlobalStateContext();
|
|
14
|
+
const [path, setPath] = React.useState(navigation.path);
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
return navigation.listen(() => {
|
|
17
|
+
setPath(navigation.path);
|
|
18
|
+
});
|
|
19
|
+
}, []);
|
|
20
|
+
return path;
|
|
21
|
+
}
|
|
22
|
+
function getKeys(template) {
|
|
23
|
+
const keys = [];
|
|
24
|
+
let result;
|
|
25
|
+
while (result = getKey.exec(template)) {
|
|
26
|
+
keys.push(result[2]);
|
|
27
|
+
}
|
|
28
|
+
return keys;
|
|
29
|
+
}
|
|
30
|
+
function getParams(current, path) {
|
|
31
|
+
const params = {};
|
|
32
|
+
if (current) {
|
|
33
|
+
const matcher = current.matcher;
|
|
34
|
+
const data = matcher.exec(path);
|
|
35
|
+
if (data) {
|
|
36
|
+
const keys = getKeys(current.settings.path);
|
|
37
|
+
for (let i = 0; i < keys.length; i++) {
|
|
38
|
+
params[keys[i]] = data[i + 1];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return params;
|
|
43
|
+
}
|
|
44
|
+
function useParams(current, path) {
|
|
45
|
+
return React.useMemo(() => getParams(current, path), [current, path]);
|
|
46
|
+
}
|
|
11
47
|
export const Breadcrumbs = () => {
|
|
12
|
-
const
|
|
13
|
-
const breadcrumbs = useBreadcrumbs(
|
|
48
|
+
const path = useNavigationPath();
|
|
49
|
+
const breadcrumbs = useBreadcrumbs(path);
|
|
14
50
|
const currentIndex = breadcrumbs.length - 1;
|
|
15
|
-
const
|
|
16
|
-
const { params } = useRouteMatch(current?.settings.path ?? '/');
|
|
51
|
+
const params = useParams(breadcrumbs[currentIndex], path);
|
|
17
52
|
const children = breadcrumbs.map(({ settings }, i) => {
|
|
18
53
|
const { title, path, ...props } = settings;
|
|
19
54
|
const key = `bc_${i}_${settings.path}`;
|
|
20
55
|
const current = i === currentIndex;
|
|
21
|
-
const computedPath = path.replace(
|
|
56
|
+
const computedPath = path.replace(getKey, (s, _, id) => {
|
|
22
57
|
if (id in params) {
|
|
23
58
|
return params[id] || '';
|
|
24
59
|
}
|
|
25
60
|
return s;
|
|
26
61
|
});
|
|
27
|
-
return (React.createElement(PiralBreadcrumbItem, { key: key, current: current, path: computedPath, ...props }, getContent(title,
|
|
62
|
+
return (React.createElement(PiralBreadcrumbItem, { key: key, current: current, path: computedPath, ...props }, getContent(title, computedPath, params)));
|
|
28
63
|
});
|
|
29
64
|
return React.createElement(PiralBreadcrumbsContainer, { children: children });
|
|
30
65
|
};
|
package/esm/Breadcrumbs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Breadcrumbs.js","sourceRoot":"","sources":["../src/Breadcrumbs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.js","sourceRoot":"","sources":["../src/Breadcrumbs.tsx"],"names":[],"mappings":"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"}
|
package/esm/types.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from 'react';
|
|
2
2
|
import type { Dict, BaseRegistration, RegistrationDisposer } from 'piral-core';
|
|
3
|
-
import type { Location } from 'history';
|
|
4
3
|
declare module 'piral-core/lib/types/custom' {
|
|
5
4
|
interface PiletCustomApi extends PiletBreadcrumbsApi {
|
|
6
5
|
}
|
|
@@ -54,7 +53,6 @@ export interface BreadcrumbItemProps extends Omit<BreadcrumbSettings, 'title'> {
|
|
|
54
53
|
export interface PiralCustomBreadcrumbSettings {
|
|
55
54
|
}
|
|
56
55
|
export interface BreadcrumbTitleParams {
|
|
57
|
-
location: Location;
|
|
58
56
|
path: string;
|
|
59
57
|
params: Record<string, string>;
|
|
60
58
|
}
|
package/lib/Breadcrumbs.js
CHANGED
|
@@ -2,32 +2,67 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Breadcrumbs = void 0;
|
|
4
4
|
const React = require("react");
|
|
5
|
-
const
|
|
5
|
+
const piral_core_1 = require("piral-core");
|
|
6
6
|
const components_1 = require("./components");
|
|
7
7
|
const useBreadcrumbs_1 = require("./useBreadcrumbs");
|
|
8
|
-
|
|
8
|
+
const getKey = /:(([A-Za-z0-9_]+)\*?)/g;
|
|
9
|
+
function getContent(title, path, params) {
|
|
9
10
|
if (typeof title === 'function') {
|
|
10
|
-
return title({
|
|
11
|
+
return title({ path, params });
|
|
11
12
|
}
|
|
12
13
|
return title;
|
|
13
14
|
}
|
|
15
|
+
function useNavigationPath() {
|
|
16
|
+
const { navigation } = (0, piral_core_1.useGlobalStateContext)();
|
|
17
|
+
const [path, setPath] = React.useState(navigation.path);
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
return navigation.listen(() => {
|
|
20
|
+
setPath(navigation.path);
|
|
21
|
+
});
|
|
22
|
+
}, []);
|
|
23
|
+
return path;
|
|
24
|
+
}
|
|
25
|
+
function getKeys(template) {
|
|
26
|
+
const keys = [];
|
|
27
|
+
let result;
|
|
28
|
+
while (result = getKey.exec(template)) {
|
|
29
|
+
keys.push(result[2]);
|
|
30
|
+
}
|
|
31
|
+
return keys;
|
|
32
|
+
}
|
|
33
|
+
function getParams(current, path) {
|
|
34
|
+
const params = {};
|
|
35
|
+
if (current) {
|
|
36
|
+
const matcher = current.matcher;
|
|
37
|
+
const data = matcher.exec(path);
|
|
38
|
+
if (data) {
|
|
39
|
+
const keys = getKeys(current.settings.path);
|
|
40
|
+
for (let i = 0; i < keys.length; i++) {
|
|
41
|
+
params[keys[i]] = data[i + 1];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return params;
|
|
46
|
+
}
|
|
47
|
+
function useParams(current, path) {
|
|
48
|
+
return React.useMemo(() => getParams(current, path), [current, path]);
|
|
49
|
+
}
|
|
14
50
|
const Breadcrumbs = () => {
|
|
15
|
-
const
|
|
16
|
-
const breadcrumbs = (0, useBreadcrumbs_1.useBreadcrumbs)(
|
|
51
|
+
const path = useNavigationPath();
|
|
52
|
+
const breadcrumbs = (0, useBreadcrumbs_1.useBreadcrumbs)(path);
|
|
17
53
|
const currentIndex = breadcrumbs.length - 1;
|
|
18
|
-
const
|
|
19
|
-
const { params } = (0, react_router_1.useRouteMatch)(current?.settings.path ?? '/');
|
|
54
|
+
const params = useParams(breadcrumbs[currentIndex], path);
|
|
20
55
|
const children = breadcrumbs.map(({ settings }, i) => {
|
|
21
56
|
const { title, path, ...props } = settings;
|
|
22
57
|
const key = `bc_${i}_${settings.path}`;
|
|
23
58
|
const current = i === currentIndex;
|
|
24
|
-
const computedPath = path.replace(
|
|
59
|
+
const computedPath = path.replace(getKey, (s, _, id) => {
|
|
25
60
|
if (id in params) {
|
|
26
61
|
return params[id] || '';
|
|
27
62
|
}
|
|
28
63
|
return s;
|
|
29
64
|
});
|
|
30
|
-
return (React.createElement(components_1.PiralBreadcrumbItem, { key: key, current: current, path: computedPath, ...props }, getContent(title,
|
|
65
|
+
return (React.createElement(components_1.PiralBreadcrumbItem, { key: key, current: current, path: computedPath, ...props }, getContent(title, computedPath, params)));
|
|
31
66
|
});
|
|
32
67
|
return React.createElement(components_1.PiralBreadcrumbsContainer, { children: children });
|
|
33
68
|
};
|
package/lib/Breadcrumbs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Breadcrumbs.js","sourceRoot":"","sources":["../src/Breadcrumbs.tsx"],"names":[],"mappings":";;;AAAA,+BAA+B;AAC/B
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.js","sourceRoot":"","sources":["../src/Breadcrumbs.tsx"],"names":[],"mappings":";;;AAAA,+BAA+B;AAC/B,2CAAmD;AACnD,6CAA8E;AAC9E,qDAAkD;AAGlD,MAAM,MAAM,GAAG,wBAAwB,CAAC;AAExC,SAAS,UAAU,CAAC,KAAkC,EAAE,IAAY,EAAE,MAA8B;IAClG,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE;QAC/B,OAAO,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;KAChC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB;IACxB,MAAM,EAAE,UAAU,EAAE,GAAG,IAAA,kCAAqB,GAAE,CAAC;IAC/C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAExD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,OAAO,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE;YAC5B,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,OAAO,CAAC,QAAgB;IAC/B,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,IAAI,MAAuB,CAAC;IAE5B,OAAO,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;QACrC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;KACtB;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS,CAAC,OAA+B,EAAE,IAAY;IAC9D,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,IAAI,OAAO,EAAE;QACX,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAChC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhC,IAAI,IAAI,EAAE;YACR,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAE5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACpC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;aAC/B;SACF;KAEF;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,OAA+B,EAAE,IAAY;IAC9D,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;AACxE,CAAC;AAEM,MAAM,WAAW,GAAa,GAAG,EAAE;IACxC,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,MAAM,WAAW,GAAG,IAAA,+BAAc,EAAC,IAAI,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,CAAC;IAE1D,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,EAAE;QACnD,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,GAAG,QAAQ,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,CAAC,KAAK,YAAY,CAAC;QACnC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE;YACrD,IAAI,EAAE,IAAI,MAAM,EAAE;gBAChB,OAAO,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;aACzB;YAED,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,OAAO,CACL,oBAAC,gCAAmB,IAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,KAAM,KAAK,IAC3E,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,CAAC,CACpB,CACvB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,oBAAC,sCAAyB,IAAC,QAAQ,EAAE,QAAQ,GAAI,CAAC;AAC3D,CAAC,CAAC;AA1BW,QAAA,WAAW,eA0BtB;AACF,mBAAW,CAAC,WAAW,GAAG,aAAa,CAAC"}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from 'react';
|
|
2
2
|
import type { Dict, BaseRegistration, RegistrationDisposer } from 'piral-core';
|
|
3
|
-
import type { Location } from 'history';
|
|
4
3
|
declare module 'piral-core/lib/types/custom' {
|
|
5
4
|
interface PiletCustomApi extends PiletBreadcrumbsApi {
|
|
6
5
|
}
|
|
@@ -54,7 +53,6 @@ export interface BreadcrumbItemProps extends Omit<BreadcrumbSettings, 'title'> {
|
|
|
54
53
|
export interface PiralCustomBreadcrumbSettings {
|
|
55
54
|
}
|
|
56
55
|
export interface BreadcrumbTitleParams {
|
|
57
|
-
location: Location;
|
|
58
56
|
path: string;
|
|
59
57
|
params: Record<string, string>;
|
|
60
58
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "piral-breadcrumbs",
|
|
3
|
-
"version": "1.5.3-beta.
|
|
3
|
+
"version": "1.5.3-beta.6919",
|
|
4
4
|
"description": "Plugin for creating a breadcrumb manager in Piral.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"piral",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"scripts": {
|
|
55
55
|
"cleanup": "rimraf esm lib piral-breadcrumbs.min.js",
|
|
56
56
|
"build": "yarn build:bundle && yarn build:commonjs && yarn build:esnext",
|
|
57
|
-
"build:bundle": "esbuild src/index.ts --outfile=piral-breadcrumbs.min.js --bundle --external:piral-core --external:react --
|
|
57
|
+
"build:bundle": "esbuild src/index.ts --outfile=piral-breadcrumbs.min.js --bundle --external:piral-core --external:react --minify",
|
|
58
58
|
"build:commonjs": "tsc --project tsconfig.json --outDir lib --module commonjs",
|
|
59
59
|
"build:esnext": "tsc --project tsconfig.json --outDir esm --module esnext",
|
|
60
60
|
"typedoc": "typedoc --json ../../../docs/types/piral-breadcrumbs.json src --exclude \"src/**/*.test.*\"",
|
|
@@ -62,10 +62,8 @@
|
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/react": "^18.0.0",
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"react": "^18.0.0",
|
|
68
|
-
"react-router": "^5.2.0"
|
|
65
|
+
"piral-core": "1.5.3-beta.6919",
|
|
66
|
+
"react": "^18.0.0"
|
|
69
67
|
},
|
|
70
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "e4b62b0aa688f440c99cb5db7951824ce5b8775a"
|
|
71
69
|
}
|
package/piral-breadcrumbs.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{var
|
|
1
|
+
(()=>{var F=Object.create;var f=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var K=Object.getPrototypeOf,O=Object.prototype.hasOwnProperty;var S=r=>f(r,"__esModule",{value:!0});var d=(r=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(r,{get:(e,t)=>(typeof require!="undefined"?require:e)[t]}):r)(function(r){if(typeof require!="undefined")return require.apply(this,arguments);throw new Error('Dynamic require of "'+r+'" is not supported')});var z=(r,e)=>{S(r);for(var t in e)f(r,t,{get:e[t],enumerable:!0})},Z=(r,e,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of $(e))!O.call(r,n)&&n!=="default"&&f(r,n,{get:()=>e[n],enumerable:!(t=M(e,n))||t.enumerable});return r},b=r=>Z(S(f(r!=null?F(K(r)):{},"default",r&&r.__esModule&&"default"in r?{get:()=>r.default,enumerable:!0}:{value:r,enumerable:!0})),r);var m=b(d("react")),G=b(d("piral-core"));var R=b(d("piral-core")),A=(0,R.getPiralComponent)("BreadcrumbsContainer"),D=(0,R.getPiralComponent)("BreadcrumbItem");var I=b(d("piral-core"));function q(r,e){let[t]=r.filter(n=>n.matcher.test(e));return t}function H(r,e){let t=e.split("/");for(;t.length>1;){t.pop();let n=t.join("/"),s=B(r,n);if(s)return s}}function B(r,e){if(e)return q(r,e)||H(r,e)}function E(r){let e=(0,I.useGlobalState)(n=>n.registry.breadcrumbs),t=Object.keys(e).map(n=>e[n]);if(t.length>0){let n=B(t,r);if(n){let s=[n],a=B(t,n.settings.parent);for(;a!==void 0;)s.push(a),a=B(t,a.settings.parent);return s.reverse()}}return[]}var k=/:(([A-Za-z0-9_]+)\*?)/g;function J(r,e,t){return typeof r=="function"?r({path:e,params:t}):r}function L(){let{navigation:r}=(0,G.useGlobalStateContext)(),[e,t]=m.useState(r.path);return m.useEffect(()=>r.listen(()=>{t(r.path)}),[]),e}function Q(r){let e=[],t;for(;t=k.exec(r);)e.push(t[2]);return e}function T(r,e){let t={};if(r){let s=r.matcher.exec(e);if(s){let a=Q(r.settings.path);for(let o=0;o<a.length;o++)t[a[o]]=s[o+1]}}return t}function U(r,e){return m.useMemo(()=>T(r,e),[r,e])}var x=()=>{let r=L(),e=E(r),t=e.length-1,n=U(e[t],r),s=e.map(({settings:a},o)=>{let{title:u,path:i,...p}=a,h=`bc_${o}_${a.path}`,y=o===t,l=i.replace(k,(j,rr,C)=>C in n?n[C]||"":j);return m.createElement(D,{key:h,current:y,path:l,...p},J(u,l,n))});return m.createElement(A,{children:s})};x.displayName="Breadcrumbs";var P={};z(P,{registerBreadcrumbs:()=>V,unregisterBreadcrumbs:()=>W});function V(r,e){r.dispatch(t=>({...t,registry:{...t.registry,breadcrumbs:{...t.registry.breadcrumbs,...e}}}))}function W(r,e){r.dispatch(t=>({...t,registry:{...t.registry,breadcrumbs:e.reduce((n,s)=>{let{[s]:a,...o}=n;return o},t.registry.breadcrumbs)}}))}var c=b(d("piral-core"));var w=b(d("react")),g=b(d("piral-core")),_=r=>w.createElement(g.ExtensionSlot,{name:"breadcrumbs",params:r,empty:()=>(0,g.defaultRender)(r.children,"default_breadcrumbs")}),v=r=>(0,g.defaultRender)(r.children);function N(r){return r.matcher instanceof RegExp?r.matcher:typeof r.matcher=="string"?(0,c.createRouteMatcher)(r.matcher):(0,c.createRouteMatcher)(r.path)}function X(r){let e={},t=0;for(let n of r)e[`global-${t++}`]={pilet:void 0,matcher:N(n),settings:n};return e}function Y(r){return e=>({...e,components:{BreadcrumbItem:v,BreadcrumbsContainer:_,...e.components},registry:{...e.registry,breadcrumbs:r}})}function pr(r={}){let{breadcrumbs:e=[]}=r;return t=>(t.defineActions(P),t.dispatch((0,c.withAll)(Y(X(e)),(0,c.withRootExtension)("piral-breadcrumbs",x))),(n,s)=>{let a=s.name,o=0;return{registerBreadcrumbs(u){let i={};for(let p of u){let{name:h=o++,...y}=p,l=(0,c.buildName)(a,h);i[l]=y}return t.registerBreadcrumbs(i),()=>t.unregisterBreadcrumbs(Object.keys(i))},registerBreadcrumb(u,i){typeof u!="string"&&(i=u,u=o++);let p=(0,c.buildName)(a,u);return t.registerBreadcrumbs({[p]:{pilet:a,matcher:N(i),settings:i}}),()=>t.unregisterBreadcrumbs([p])},unregisterBreadcrumb(u){let i=(0,c.buildName)(a,u);t.unregisterBreadcrumbs([i])}}})}})();
|
package/src/Breadcrumbs.test.tsx
CHANGED
|
@@ -7,7 +7,6 @@ import { describe, it, expect, vitest, afterEach } from 'vitest';
|
|
|
7
7
|
import { render, cleanup } from '@testing-library/react';
|
|
8
8
|
import { StateContext } from 'piral-core';
|
|
9
9
|
import { Breadcrumbs } from './Breadcrumbs';
|
|
10
|
-
import { useRouteMatch } from 'react-router';
|
|
11
10
|
|
|
12
11
|
const MockBcContainer: React.FC<any> = ({ children }) => <div role="container">{children}</div>;
|
|
13
12
|
MockBcContainer.displayName = 'MockBcContainer';
|
|
@@ -15,16 +14,7 @@ MockBcContainer.displayName = 'MockBcContainer';
|
|
|
15
14
|
const MockBcItem: React.FC<any> = ({ children }) => <div role="dialog">{children}</div>;
|
|
16
15
|
MockBcItem.displayName = 'MockBcTile';
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
useLocation() {
|
|
20
|
-
return {
|
|
21
|
-
pathname: '/example',
|
|
22
|
-
};
|
|
23
|
-
},
|
|
24
|
-
useRouteMatch: vitest.fn(() => ({})),
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
function createMockContainer(breadcrumbs = {}) {
|
|
17
|
+
function createMockContainer(breadcrumbs = {}, path = '/example') {
|
|
28
18
|
const state = create(() => ({
|
|
29
19
|
components: {
|
|
30
20
|
BreadcrumbsContainer: MockBcContainer,
|
|
@@ -47,6 +37,10 @@ function createMockContainer(breadcrumbs = {}) {
|
|
|
47
37
|
dispatch(update) {
|
|
48
38
|
state.setState(update(state.getState()));
|
|
49
39
|
},
|
|
40
|
+
navigation: {
|
|
41
|
+
path,
|
|
42
|
+
listen() {},
|
|
43
|
+
},
|
|
50
44
|
} as any,
|
|
51
45
|
api: {} as any,
|
|
52
46
|
};
|
|
@@ -104,11 +98,9 @@ describe('Piral-Breadcrumb Container component', () => {
|
|
|
104
98
|
});
|
|
105
99
|
|
|
106
100
|
it('dynamic title function replaces wildcard with route param', () => {
|
|
107
|
-
(useRouteMatch as any).mockReturnValueOnce({ params: { example: 'replacedWildcard' } });
|
|
108
|
-
|
|
109
101
|
const { context } = createMockContainer({
|
|
110
102
|
example: {
|
|
111
|
-
matcher: /^\/
|
|
103
|
+
matcher: /^\/([a-zA-Z]+)$/,
|
|
112
104
|
settings: {
|
|
113
105
|
path: '/:example*',
|
|
114
106
|
title: ({ path }) => {
|
|
@@ -117,7 +109,7 @@ describe('Piral-Breadcrumb Container component', () => {
|
|
|
117
109
|
parent: '/',
|
|
118
110
|
},
|
|
119
111
|
},
|
|
120
|
-
});
|
|
112
|
+
}, '/replacedWildcard');
|
|
121
113
|
const node = render(
|
|
122
114
|
<StateContext.Provider value={context}>
|
|
123
115
|
<Breadcrumbs />
|
|
@@ -129,35 +121,7 @@ describe('Piral-Breadcrumb Container component', () => {
|
|
|
129
121
|
expect(node.getAllByRole('container')[0].innerHTML).toBe('<div role="dialog">/replacedWildcard</div>');
|
|
130
122
|
});
|
|
131
123
|
|
|
132
|
-
it('dynamic title function no match in params', () => {
|
|
133
|
-
(useRouteMatch as any).mockReturnValueOnce({ params: { imNotHere: 'replacedWildcard' } });
|
|
134
|
-
|
|
135
|
-
const { context } = createMockContainer({
|
|
136
|
-
example: {
|
|
137
|
-
matcher: /^\/example$/,
|
|
138
|
-
settings: {
|
|
139
|
-
path: '/:example*',
|
|
140
|
-
title: ({ path }) => {
|
|
141
|
-
return path;
|
|
142
|
-
},
|
|
143
|
-
parent: '/',
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
const node = render(
|
|
148
|
-
<StateContext.Provider value={context}>
|
|
149
|
-
<Breadcrumbs />
|
|
150
|
-
</StateContext.Provider>,
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
expect(node.getAllByRole('container').length).toBe(1);
|
|
154
|
-
expect(node.getAllByRole('dialog').length).toBe(1);
|
|
155
|
-
expect(node.getAllByRole('container')[0].innerHTML).toBe('<div role="dialog">/:example*</div>');
|
|
156
|
-
});
|
|
157
|
-
|
|
158
124
|
it('dynamic title function with falsely route param', () => {
|
|
159
|
-
(useRouteMatch as any).mockReturnValueOnce({ params: { example: false } });
|
|
160
|
-
|
|
161
125
|
const { context } = createMockContainer({
|
|
162
126
|
example: {
|
|
163
127
|
matcher: /^\/example$/,
|
|
@@ -182,8 +146,6 @@ describe('Piral-Breadcrumb Container component', () => {
|
|
|
182
146
|
});
|
|
183
147
|
|
|
184
148
|
it('dynamic title function with static title', () => {
|
|
185
|
-
(useRouteMatch as any).mockReturnValueOnce({ params: { imNotHere: 'replacedWildcard' } });
|
|
186
|
-
|
|
187
149
|
const { context } = createMockContainer({
|
|
188
150
|
example: {
|
|
189
151
|
matcher: /^\/example$/,
|
|
@@ -208,8 +170,6 @@ describe('Piral-Breadcrumb Container component', () => {
|
|
|
208
170
|
});
|
|
209
171
|
|
|
210
172
|
it('static title', () => {
|
|
211
|
-
(useRouteMatch as any).mockReturnValueOnce({ params: {} });
|
|
212
|
-
|
|
213
173
|
const { context } = createMockContainer({
|
|
214
174
|
example: {
|
|
215
175
|
matcher: /^\/example$/,
|
package/src/Breadcrumbs.tsx
CHANGED
|
@@ -1,35 +1,78 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useGlobalStateContext } from 'piral-core';
|
|
3
3
|
import { PiralBreadcrumbsContainer, PiralBreadcrumbItem } from './components';
|
|
4
4
|
import { useBreadcrumbs } from './useBreadcrumbs';
|
|
5
|
-
import { BreadcrumbSettings } from './types';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
location: Location,
|
|
11
|
-
path: string,
|
|
12
|
-
params: Record<string, string>,
|
|
13
|
-
) {
|
|
5
|
+
import { BreadcrumbRegistration, BreadcrumbSettings } from './types';
|
|
6
|
+
|
|
7
|
+
const getKey = /:(([A-Za-z0-9_]+)\*?)/g;
|
|
8
|
+
|
|
9
|
+
function getContent(title: BreadcrumbSettings['title'], path: string, params: Record<string, string>) {
|
|
14
10
|
if (typeof title === 'function') {
|
|
15
|
-
return title({
|
|
11
|
+
return title({ path, params });
|
|
16
12
|
}
|
|
17
13
|
|
|
18
14
|
return title;
|
|
19
15
|
}
|
|
20
16
|
|
|
17
|
+
function useNavigationPath() {
|
|
18
|
+
const { navigation } = useGlobalStateContext();
|
|
19
|
+
const [path, setPath] = React.useState(navigation.path);
|
|
20
|
+
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
return navigation.listen(() => {
|
|
23
|
+
setPath(navigation.path);
|
|
24
|
+
});
|
|
25
|
+
}, []);
|
|
26
|
+
|
|
27
|
+
return path;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getKeys(template: string) {
|
|
31
|
+
const keys: Array<string> = [];
|
|
32
|
+
let result: RegExpExecArray;
|
|
33
|
+
|
|
34
|
+
while (result = getKey.exec(template)) {
|
|
35
|
+
keys.push(result[2]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return keys;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getParams(current: BreadcrumbRegistration, path: string) {
|
|
42
|
+
const params: Record<string, string> = {};
|
|
43
|
+
|
|
44
|
+
if (current) {
|
|
45
|
+
const matcher = current.matcher;
|
|
46
|
+
const data = matcher.exec(path);
|
|
47
|
+
|
|
48
|
+
if (data) {
|
|
49
|
+
const keys = getKeys(current.settings.path);
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < keys.length; i++) {
|
|
52
|
+
params[keys[i]] = data[i + 1];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return params;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function useParams(current: BreadcrumbRegistration, path: string) {
|
|
62
|
+
return React.useMemo(() => getParams(current, path), [current, path]);
|
|
63
|
+
}
|
|
64
|
+
|
|
21
65
|
export const Breadcrumbs: React.FC = () => {
|
|
22
|
-
const
|
|
23
|
-
const breadcrumbs = useBreadcrumbs(
|
|
66
|
+
const path = useNavigationPath();
|
|
67
|
+
const breadcrumbs = useBreadcrumbs(path);
|
|
24
68
|
const currentIndex = breadcrumbs.length - 1;
|
|
25
|
-
const
|
|
26
|
-
const { params } = useRouteMatch(current?.settings.path ?? '/');
|
|
69
|
+
const params = useParams(breadcrumbs[currentIndex], path);
|
|
27
70
|
|
|
28
71
|
const children = breadcrumbs.map(({ settings }, i) => {
|
|
29
72
|
const { title, path, ...props } = settings;
|
|
30
73
|
const key = `bc_${i}_${settings.path}`;
|
|
31
74
|
const current = i === currentIndex;
|
|
32
|
-
const computedPath = path.replace(
|
|
75
|
+
const computedPath = path.replace(getKey, (s, _, id) => {
|
|
33
76
|
if (id in params) {
|
|
34
77
|
return params[id] || '';
|
|
35
78
|
}
|
|
@@ -39,7 +82,7 @@ export const Breadcrumbs: React.FC = () => {
|
|
|
39
82
|
|
|
40
83
|
return (
|
|
41
84
|
<PiralBreadcrumbItem key={key} current={current} path={computedPath} {...props}>
|
|
42
|
-
{getContent(title,
|
|
85
|
+
{getContent(title, computedPath, params)}
|
|
43
86
|
</PiralBreadcrumbItem>
|
|
44
87
|
);
|
|
45
88
|
});
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from 'react';
|
|
2
2
|
import type { Dict, BaseRegistration, RegistrationDisposer } from 'piral-core';
|
|
3
|
-
import type { Location } from 'history';
|
|
4
3
|
|
|
5
4
|
declare module 'piral-core/lib/types/custom' {
|
|
6
5
|
interface PiletCustomApi extends PiletBreadcrumbsApi {}
|
|
@@ -61,7 +60,6 @@ export interface BreadcrumbItemProps extends Omit<BreadcrumbSettings, 'title'> {
|
|
|
61
60
|
export interface PiralCustomBreadcrumbSettings {}
|
|
62
61
|
|
|
63
62
|
export interface BreadcrumbTitleParams {
|
|
64
|
-
location: Location;
|
|
65
63
|
path: string;
|
|
66
64
|
params: Record<string, string>;
|
|
67
65
|
}
|