piral-breadcrumbs 1.0.0-pre.2077 → 1.0.0

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.
Files changed (52) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +16 -2
  3. package/esm/Breadcrumbs.d.ts +2 -0
  4. package/esm/Breadcrumbs.js +23 -0
  5. package/esm/Breadcrumbs.js.map +1 -0
  6. package/esm/actions.d.ts +4 -0
  7. package/esm/actions.js +11 -0
  8. package/esm/actions.js.map +1 -0
  9. package/esm/components.d.ts +3 -0
  10. package/esm/components.js +4 -0
  11. package/esm/components.js.map +1 -0
  12. package/esm/create.d.ts +16 -0
  13. package/esm/create.js +80 -0
  14. package/esm/create.js.map +1 -0
  15. package/esm/default.d.ts +4 -0
  16. package/esm/default.js +5 -0
  17. package/esm/default.js.map +1 -0
  18. package/esm/index.d.ts +5 -0
  19. package/esm/index.js +6 -0
  20. package/esm/index.js.map +1 -0
  21. package/esm/types.d.ts +112 -0
  22. package/esm/types.js +2 -0
  23. package/esm/types.js.map +1 -0
  24. package/esm/useBreadcrumbs.d.ts +2 -0
  25. package/esm/useBreadcrumbs.js +41 -0
  26. package/esm/useBreadcrumbs.js.map +1 -0
  27. package/lib/Breadcrumbs.js +18 -18
  28. package/lib/Breadcrumbs.js.map +1 -1
  29. package/lib/actions.d.ts +3 -3
  30. package/lib/actions.js +11 -9
  31. package/lib/actions.js.map +1 -1
  32. package/lib/components.d.ts +3 -4
  33. package/lib/components.js +3 -3
  34. package/lib/components.js.map +1 -1
  35. package/lib/create.js +45 -29
  36. package/lib/create.js.map +1 -1
  37. package/lib/default.js +6 -4
  38. package/lib/default.js.map +1 -1
  39. package/lib/index.js +1 -1
  40. package/lib/types.d.ts +21 -7
  41. package/lib/useBreadcrumbs.js +10 -10
  42. package/lib/useBreadcrumbs.js.map +1 -1
  43. package/package.json +38 -8
  44. package/piral-breadcrumbs.min.js +1 -0
  45. package/src/Breadcrumbs.test.tsx +14 -14
  46. package/src/actions.test.ts +12 -9
  47. package/src/actions.ts +11 -5
  48. package/src/components.tsx +2 -6
  49. package/src/create.test.ts +28 -27
  50. package/src/create.ts +46 -22
  51. package/src/default.test.tsx +9 -9
  52. package/src/types.ts +21 -8
@@ -1,8 +1,12 @@
1
- import { Atom, swap } from '@dbeining/react-atom';
1
+ import create from 'zustand';
2
2
  import { createBreadcrumbsApi } from './create';
3
3
 
4
4
  function createMockContainer() {
5
- const state = Atom.of({});
5
+ const state = create(() => ({
6
+ registry: {
7
+ extensions: {},
8
+ },
9
+ }));
6
10
  return {
7
11
  context: {
8
12
  on: jest.fn(),
@@ -11,7 +15,7 @@ function createMockContainer() {
11
15
  defineActions() {},
12
16
  state,
13
17
  dispatch(update) {
14
- swap(state, update);
18
+ state.setState(update(state.getState()));
15
19
  },
16
20
  } as any,
17
21
  api: {} as any,
@@ -34,55 +38,52 @@ const moduleMetadata = {
34
38
  describe('Create Breadcrumb API Extensions', () => {
35
39
  it('createBreadcrumbsApi can register and unregister a breadcrumb', () => {
36
40
  const container = createMockContainer();
37
- container.context.registerBreadcrumb = jest.fn();
38
- container.context.unregisterBreadcrumb = jest.fn();
41
+ container.context.registerBreadcrumbs = jest.fn();
42
+ container.context.unregisterBreadcrumbs = jest.fn();
39
43
  const api = createApi(container);
40
44
  api.registerBreadcrumb('my-bc', {
41
45
  title: 'My breadcrumb',
42
46
  path: '/example',
43
47
  });
44
- expect(container.context.registerBreadcrumb).toHaveBeenCalledTimes(1);
45
- expect(container.context.unregisterBreadcrumb).toHaveBeenCalledTimes(0);
48
+ expect(container.context.registerBreadcrumbs).toHaveBeenCalledTimes(1);
49
+ expect(container.context.unregisterBreadcrumbs).toHaveBeenCalledTimes(0);
46
50
  api.unregisterBreadcrumb('my-bc');
47
- expect(container.context.unregisterBreadcrumb).toHaveBeenCalledTimes(1);
48
- expect(container.context.unregisterBreadcrumb.mock.calls[0][0]).toBe(
49
- container.context.registerBreadcrumb.mock.calls[0][0],
50
- );
51
+ expect(container.context.unregisterBreadcrumbs).toHaveBeenCalledTimes(1);
52
+ const ids = Object.keys(container.context.registerBreadcrumbs.mock.calls[0][0]);
53
+ expect(container.context.unregisterBreadcrumbs.mock.calls[0][0]).toEqual(ids);
51
54
  });
52
55
 
53
56
  it('createBreadcrumbsApi can dispose a registered breadcrumb', () => {
54
57
  const container = createMockContainer();
55
- container.context.registerBreadcrumb = jest.fn();
56
- container.context.unregisterBreadcrumb = jest.fn();
58
+ container.context.registerBreadcrumbs = jest.fn();
59
+ container.context.unregisterBreadcrumbs = jest.fn();
57
60
  const api = createApi(container);
58
61
  const dispose = api.registerBreadcrumb('my-bc', {
59
62
  title: 'My breadcrumb',
60
63
  path: '/example',
61
64
  });
62
- expect(container.context.registerBreadcrumb).toHaveBeenCalledTimes(1);
63
- expect(container.context.unregisterBreadcrumb).toHaveBeenCalledTimes(0);
65
+ expect(container.context.registerBreadcrumbs).toHaveBeenCalledTimes(1);
66
+ expect(container.context.unregisterBreadcrumbs).toHaveBeenCalledTimes(0);
64
67
  dispose();
65
- expect(container.context.unregisterBreadcrumb).toHaveBeenCalledTimes(1);
66
- expect(container.context.unregisterBreadcrumb.mock.calls[0][0]).toBe(
67
- container.context.registerBreadcrumb.mock.calls[0][0],
68
- );
68
+ expect(container.context.unregisterBreadcrumbs).toHaveBeenCalledTimes(1);
69
+ const ids = Object.keys(container.context.registerBreadcrumbs.mock.calls[0][0]);
70
+ expect(container.context.unregisterBreadcrumbs.mock.calls[0][0]).toEqual(ids);
69
71
  });
70
72
 
71
73
  it('createBreadcrumbsApi can dispose a registered anonymous breadcrumb', () => {
72
74
  const container = createMockContainer();
73
- container.context.registerBreadcrumb = jest.fn();
74
- container.context.unregisterBreadcrumb = jest.fn();
75
+ container.context.registerBreadcrumbs = jest.fn();
76
+ container.context.unregisterBreadcrumbs = jest.fn();
75
77
  const api = createApi(container);
76
78
  const dispose = api.registerBreadcrumb({
77
79
  title: 'My breadcrumb',
78
80
  path: '/example',
79
81
  });
80
- expect(container.context.registerBreadcrumb).toHaveBeenCalledTimes(1);
81
- expect(container.context.unregisterBreadcrumb).toHaveBeenCalledTimes(0);
82
+ expect(container.context.registerBreadcrumbs).toHaveBeenCalledTimes(1);
83
+ expect(container.context.unregisterBreadcrumbs).toHaveBeenCalledTimes(0);
82
84
  dispose();
83
- expect(container.context.unregisterBreadcrumb).toHaveBeenCalledTimes(1);
84
- expect(container.context.unregisterBreadcrumb.mock.calls[0][0]).toBe(
85
- container.context.registerBreadcrumb.mock.calls[0][0],
86
- );
85
+ expect(container.context.unregisterBreadcrumbs).toHaveBeenCalledTimes(1);
86
+ const ids = Object.keys(container.context.registerBreadcrumbs.mock.calls[0][0]);
87
+ expect(container.context.unregisterBreadcrumbs.mock.calls[0][0]).toEqual(ids);
87
88
  });
88
89
  });
package/src/create.ts CHANGED
@@ -1,9 +1,13 @@
1
- import * as ptr from 'path-to-regexp';
2
1
  import * as actions from './actions';
3
- import { buildName, PiralPlugin, Dict } from 'piral-core';
2
+ import { buildName, PiralPlugin, Dict, withRootExtension, withAll, GlobalState } from 'piral-core';
4
3
  import { DefaultBreadbrumbItem, DefaultBreadcrumbsContainer } from './default';
4
+ import { Breadcrumbs } from './Breadcrumbs';
5
5
  import { PiletBreadcrumbsApi, BreadcrumbSettings, BreadcrumbRegistration } from './types';
6
6
 
7
+ // Unfortunately `require`d:
8
+ // * exports are otherwise potentially converted by, e.g., Parcel (see #385)
9
+ const ptr = require('path-to-regexp');
10
+
7
11
  /**
8
12
  * Available configuration options for the breadcrumbs plugin.
9
13
  */
@@ -15,7 +19,7 @@ export interface DashboardConfig {
15
19
  breadcrumbs?: Array<BreadcrumbSettings>;
16
20
  }
17
21
 
18
- function getMatcher(settings: BreadcrumbSettings) {
22
+ function getMatcher(settings: BreadcrumbSettings): RegExp {
19
23
  if (settings.matcher instanceof RegExp) {
20
24
  return settings.matcher;
21
25
  } else if (typeof settings.matcher === 'string') {
@@ -40,6 +44,21 @@ function getBreadcrumbs(items: Array<BreadcrumbSettings>) {
40
44
  return breadcrumbs;
41
45
  }
42
46
 
47
+ function withBreadcrumbs(breadcrumbs: Dict<BreadcrumbRegistration>) {
48
+ return (state: GlobalState): GlobalState => ({
49
+ ...state,
50
+ components: {
51
+ BreadcrumbItem: DefaultBreadbrumbItem,
52
+ BreadcrumbsContainer: DefaultBreadcrumbsContainer,
53
+ ...state.components,
54
+ },
55
+ registry: {
56
+ ...state.registry,
57
+ breadcrumbs,
58
+ },
59
+ });
60
+ }
61
+
43
62
  /**
44
63
  * Creates the Pilet API extension for activating breadcrumbs support.
45
64
  */
@@ -49,24 +68,27 @@ export function createBreadcrumbsApi(config: DashboardConfig = {}): PiralPlugin<
49
68
  return (context) => {
50
69
  context.defineActions(actions);
51
70
 
52
- context.dispatch((state) => ({
53
- ...state,
54
- components: {
55
- BreadcrumbItem: DefaultBreadbrumbItem,
56
- BreadcrumbsContainer: DefaultBreadcrumbsContainer,
57
- ...state.components,
58
- },
59
- registry: {
60
- ...state.registry,
61
- breadcrumbs: getBreadcrumbs(breadcrumbs),
62
- },
63
- }));
71
+ context.dispatch(
72
+ withAll(withBreadcrumbs(getBreadcrumbs(breadcrumbs)), withRootExtension('piral-breadcrumbs', Breadcrumbs)),
73
+ );
64
74
 
65
- return (api, target) => {
75
+ return (_, target) => {
66
76
  const pilet = target.name;
67
77
  let next = 0;
68
78
 
69
79
  return {
80
+ registerBreadcrumbs(values) {
81
+ const bc = {};
82
+
83
+ for (const value of values) {
84
+ const { name = next++, ...settings } = value;
85
+ const id = buildName(pilet, name);
86
+ bc[id] = settings;
87
+ }
88
+
89
+ context.registerBreadcrumbs(bc);
90
+ return () => context.unregisterBreadcrumbs(Object.keys(bc));
91
+ },
70
92
  registerBreadcrumb(name, settings?) {
71
93
  if (typeof name !== 'string') {
72
94
  settings = name;
@@ -74,16 +96,18 @@ export function createBreadcrumbsApi(config: DashboardConfig = {}): PiralPlugin<
74
96
  }
75
97
 
76
98
  const id = buildName(pilet, name);
77
- context.registerBreadcrumb(id, {
78
- pilet,
79
- matcher: getMatcher(settings),
80
- settings,
99
+ context.registerBreadcrumbs({
100
+ [id]: {
101
+ pilet,
102
+ matcher: getMatcher(settings),
103
+ settings,
104
+ },
81
105
  });
82
- return () => api.unregisterBreadcrumb(name);
106
+ return () => context.unregisterBreadcrumbs([id]);
83
107
  },
84
108
  unregisterBreadcrumb(name) {
85
109
  const id = buildName(pilet, name);
86
- context.unregisterBreadcrumb(id);
110
+ context.unregisterBreadcrumbs([id]);
87
111
  },
88
112
  };
89
113
  };
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { mount } from 'enzyme';
2
+ import { render } from '@testing-library/react';
3
3
  import { DefaultBreadcrumbsContainer } from './default';
4
4
 
5
5
  jest.mock('piral-core', () => ({
@@ -35,10 +35,10 @@ const state = {
35
35
 
36
36
  (React as any).useMemo = (cb) => cb();
37
37
 
38
- const StubBreadcrumbsContainer: React.FC = () => <div />;
38
+ const StubBreadcrumbsContainer: React.FC = () => <ul />;
39
39
  StubBreadcrumbsContainer.displayName = 'StubBreadcrumbsContainer';
40
40
 
41
- const StubBreadcrumbItem: React.FC = () => <div />;
41
+ const StubBreadcrumbItem: React.FC = () => <li />;
42
42
  StubBreadcrumbItem.displayName = 'BreadcrumbItem';
43
43
 
44
44
  describe('Default Breadcrumbs Component', () => {
@@ -47,13 +47,13 @@ describe('Default Breadcrumbs Component', () => {
47
47
  component: StubBreadcrumbItem,
48
48
  preferences: {},
49
49
  };
50
- const node = mount(
50
+ const node = render(
51
51
  <DefaultBreadcrumbsContainer>
52
52
  <StubBreadcrumbItem />
53
53
  </DefaultBreadcrumbsContainer>,
54
54
  );
55
- expect(node.find(StubBreadcrumbsContainer).length).toBe(0);
56
- expect(node.find(StubBreadcrumbItem).length).toBe(1);
55
+ expect(node.queryByRole('list')).toBe(null);
56
+ expect(node.getAllByRole('listitem').length).toBe(1);
57
57
  });
58
58
 
59
59
  it('renders the provided extension in the default case', () => {
@@ -62,12 +62,12 @@ describe('Default Breadcrumbs Component', () => {
62
62
  component: StubBreadcrumbsContainer,
63
63
  },
64
64
  ];
65
- const node = mount(
65
+ const node = render(
66
66
  <DefaultBreadcrumbsContainer>
67
67
  <StubBreadcrumbItem />
68
68
  </DefaultBreadcrumbsContainer>,
69
69
  );
70
- expect(node.find(StubBreadcrumbItem).length).toBe(0);
71
- expect(node.find(StubBreadcrumbsContainer).length).toBe(1);
70
+ expect(node.queryByRole('listitem')).toBe(null);
71
+ expect(node.getAllByRole('list').length).toBe(1);
72
72
  });
73
73
  });
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ComponentType, ReactChild } from 'react';
2
- import { Dict, BaseRegistration, RegistrationDisposer } from 'piral-core';
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type { Dict, BaseRegistration, RegistrationDisposer } from 'piral-core';
3
3
 
4
4
  declare module 'piral-core/lib/types/custom' {
5
5
  interface PiletCustomApi extends PiletBreadcrumbsApi {}
@@ -9,15 +9,14 @@ declare module 'piral-core/lib/types/custom' {
9
9
  interface PiralCustomActions {
10
10
  /**
11
11
  * Registers a new breadcrumb.
12
- * @param name The name of the breadcrumb.
13
- * @param value The breadcrumb registration.
12
+ * @param values The breadcrumbs to register.
14
13
  */
15
- registerBreadcrumb(name: string, value: BreadcrumbRegistration): void;
14
+ registerBreadcrumbs(values: Dict<BreadcrumbRegistration>): void;
16
15
  /**
17
16
  * Unregisters an existing breadcrumb.
18
17
  * @param name The name of the breadcrumb to be removed.
19
18
  */
20
- unregisterBreadcrumb(name: string): void;
19
+ unregisterBreadcrumbs(names: Array<string>): void;
21
20
  }
22
21
 
23
22
  interface PiralCustomRegistryState {
@@ -39,13 +38,22 @@ declare module 'piral-core/lib/types/custom' {
39
38
  }
40
39
  }
41
40
 
42
- export interface BreadcrumbsContainerProps {}
41
+ export interface BreadcrumbsContainerProps {
42
+ /**
43
+ * The breadcrumbs to display.
44
+ */
45
+ children?: ReactNode;
46
+ }
43
47
 
44
48
  export interface BreadcrumbItemProps extends Omit<BreadcrumbSettings, 'title'> {
45
49
  /**
46
50
  * Determins if the breadcrumb is the current page.
47
51
  */
48
52
  current: boolean;
53
+ /**
54
+ * The title of the breadcrumb to display.
55
+ */
56
+ children?: ReactNode;
49
57
  }
50
58
 
51
59
  export interface PiralCustomBreadcrumbSettings {}
@@ -75,7 +83,7 @@ export interface BreadcrumbSettings extends PiralCustomBreadcrumbSettings {
75
83
  /**
76
84
  * The title of the breadcrumb.
77
85
  */
78
- title: ReactChild;
86
+ title: ReactNode;
79
87
  }
80
88
 
81
89
  export interface BreadcrumbRegistration extends BaseRegistration {
@@ -84,6 +92,11 @@ export interface BreadcrumbRegistration extends BaseRegistration {
84
92
  }
85
93
 
86
94
  export interface PiletBreadcrumbsApi {
95
+ /**
96
+ * Registers a set of breadcrumbs.
97
+ * @param values The different breadcrumb settings.
98
+ */
99
+ registerBreadcrumbs(values: Array<{ name?: string; } & BreadcrumbSettings>): RegistrationDisposer;
87
100
  /**
88
101
  * Registers a breadcrumb with the provided settings.
89
102
  * @param settings The settings for configuring the breadcrumb.