@genesislcap/foundation-react-utils 14.489.1-alpha-2e2874541.0 → 14.490.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.
- package/dist/custom-elements.json +0 -245
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -39
- package/dist/dts/router/app-routes.d.ts +0 -63
- package/dist/dts/router/app-routes.d.ts.map +0 -1
- package/dist/dts/router/index.d.ts +0 -33
- package/dist/dts/router/index.d.ts.map +0 -1
- package/dist/dts/router/pbc-routes.d.ts +0 -36
- package/dist/dts/router/pbc-routes.d.ts.map +0 -1
- package/dist/dts/router/post-login-redirect.d.ts +0 -25
- package/dist/dts/router/post-login-redirect.d.ts.map +0 -1
- package/dist/dts/router/protected-route.d.ts +0 -80
- package/dist/dts/router/protected-route.d.ts.map +0 -1
- package/dist/dts/router/router.test.d.ts +0 -2
- package/dist/dts/router/router.test.d.ts.map +0 -1
- package/dist/dts/router/single-component.d.ts +0 -52
- package/dist/dts/router/single-component.d.ts.map +0 -1
- package/dist/esm/router/app-routes.js +0 -22
- package/dist/esm/router/index.js +0 -27
- package/dist/esm/router/pbc-routes.js +0 -19
- package/dist/esm/router/post-login-redirect.js +0 -14
- package/dist/esm/router/protected-route.js +0 -46
- package/dist/esm/router/router.test.js +0 -82
- package/dist/esm/router/single-component.js +0 -51
- package/src/router/app-routes.tsx +0 -121
- package/src/router/index.ts +0 -41
- package/src/router/pbc-routes.ts +0 -56
- package/src/router/post-login-redirect.ts +0 -29
- package/src/router/protected-route.tsx +0 -121
- package/src/router/router.test.ts +0 -107
- package/src/router/single-component.tsx +0 -94
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
|
|
2
|
-
import { mergePbcRoutes } from './pbc-routes';
|
|
3
|
-
import { buildPostLoginRedirect } from './post-login-redirect';
|
|
4
|
-
import { createComponentRegistry } from './single-component';
|
|
5
|
-
|
|
6
|
-
const RedirectSuite = createLogicSuite('buildPostLoginRedirect');
|
|
7
|
-
|
|
8
|
-
RedirectSuite('falls back to `/` when there is no stashed origin', () => {
|
|
9
|
-
assert.is(buildPostLoginRedirect({}), '/');
|
|
10
|
-
assert.is(buildPostLoginRedirect({ state: null }), '/');
|
|
11
|
-
assert.is(buildPostLoginRedirect({ state: {} }), '/');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
RedirectSuite('honours a custom default path', () => {
|
|
15
|
-
assert.is(buildPostLoginRedirect({}, '/home'), '/home');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
RedirectSuite('returns the pathname when there is no search/hash', () => {
|
|
19
|
-
assert.is(buildPostLoginRedirect({ state: { from: { pathname: '/grids' } } }), '/grids');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
RedirectSuite('preserves search and hash so deep-link params survive', () => {
|
|
23
|
-
assert.is(
|
|
24
|
-
buildPostLoginRedirect({
|
|
25
|
-
state: { from: { pathname: '/', search: '?component=Home', hash: '#top' } },
|
|
26
|
-
}),
|
|
27
|
-
'/?component=Home#top',
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
RedirectSuite.run();
|
|
32
|
-
|
|
33
|
-
const RegistrySuite = createLogicSuite('createComponentRegistry');
|
|
34
|
-
|
|
35
|
-
const Home = () => null;
|
|
36
|
-
const GridsShowcase = () => null;
|
|
37
|
-
const registry = createComponentRegistry({ Home, GridsShowcase });
|
|
38
|
-
|
|
39
|
-
RegistrySuite('resolves an exact name', () => {
|
|
40
|
-
assert.is(registry.resolve('Home'), Home);
|
|
41
|
-
assert.is(registry.resolve('GridsShowcase'), GridsShowcase);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
RegistrySuite('resolves case- and separator-insensitively', () => {
|
|
45
|
-
assert.is(registry.resolve('home'), Home);
|
|
46
|
-
assert.is(registry.resolve('gridsshowcase'), GridsShowcase);
|
|
47
|
-
assert.is(registry.resolve('grids-showcase'), GridsShowcase);
|
|
48
|
-
assert.is(registry.resolve('grids_showcase'), GridsShowcase);
|
|
49
|
-
assert.is(registry.resolve('Grids Showcase'), GridsShowcase);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
RegistrySuite('returns undefined for unknown or empty names', () => {
|
|
53
|
-
assert.is(registry.resolve('nope'), undefined);
|
|
54
|
-
assert.is(registry.resolve(null), undefined);
|
|
55
|
-
assert.is(registry.resolve(undefined), undefined);
|
|
56
|
-
assert.is(registry.resolve(''), undefined);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
RegistrySuite('exposes the registered names via available()', () => {
|
|
60
|
-
assert.equal(registry.available(), ['Home', 'GridsShowcase']);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
RegistrySuite.run();
|
|
64
|
-
|
|
65
|
-
const PbcSuite = createLogicSuite('mergePbcRoutes');
|
|
66
|
-
|
|
67
|
-
PbcSuite('appends PBC routes after the static ones', () => {
|
|
68
|
-
const staticRoutes = [{ path: '/home', element: null }];
|
|
69
|
-
const merged = mergePbcRoutes(staticRoutes, [{ path: 'reporting' }], {
|
|
70
|
-
renderPbc: () => 'pbc',
|
|
71
|
-
});
|
|
72
|
-
assert.is(merged.length, 2);
|
|
73
|
-
assert.is(merged[0].path, '/home');
|
|
74
|
-
assert.is(merged[1].path, '/reporting');
|
|
75
|
-
assert.is(merged[1].element, 'pbc');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
PbcSuite('carries pbc element/tag + navItems + settings through `data`', () => {
|
|
79
|
-
const navItems = [{ navId: 'header', title: 'Reporting' }];
|
|
80
|
-
const el = () => 'loader';
|
|
81
|
-
const merged = mergePbcRoutes(
|
|
82
|
-
[],
|
|
83
|
-
[
|
|
84
|
-
{
|
|
85
|
-
path: 'reporting',
|
|
86
|
-
element: el,
|
|
87
|
-
elementTag: 'reporting-app',
|
|
88
|
-
navItems,
|
|
89
|
-
settings: { permissionCode: 'ReportView' },
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
{ renderPbc: () => null },
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
assert.is(merged[0].permissionCode, 'ReportView');
|
|
96
|
-
assert.is(merged[0].data?.pbcElement, el);
|
|
97
|
-
assert.is(merged[0].data?.pbcElementTag, 'reporting-app');
|
|
98
|
-
assert.equal(merged[0].data?.navItems, navItems);
|
|
99
|
-
assert.is(merged[0].data?.permissionCode, 'ReportView');
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
PbcSuite('returns only the static routes when there are no PBC routes', () => {
|
|
103
|
-
const staticRoutes = [{ path: '/home', element: null }];
|
|
104
|
-
assert.equal(mergePbcRoutes(staticRoutes, [], { renderPbc: () => null }), staticRoutes);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
PbcSuite.run();
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Read a query-string parameter from the current URL.
|
|
5
|
-
*
|
|
6
|
-
* Call this at **module-evaluation time** in your app (i.e. as a top-level
|
|
7
|
-
* `const`), before the app shell's async bootstrap rewrites the URL and drops
|
|
8
|
-
* the query string, and store the result. That way a deep-link param such as
|
|
9
|
-
* `?component=<name>` survives even though it is gone by the time the router
|
|
10
|
-
* mounts.
|
|
11
|
-
*/
|
|
12
|
-
export function readInitialParam(key: string): string | null {
|
|
13
|
-
const search = typeof window !== 'undefined' ? window.location.search : '';
|
|
14
|
-
return new URLSearchParams(search).get(key);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Normalize a name so lookups are case-insensitive and separator-agnostic. */
|
|
18
|
-
const normalize = (name: string): string => name.toLowerCase().replace(/[-_\s]/g, '');
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* A name → component registry with tolerant lookup. Create one with
|
|
22
|
-
* {@link createComponentRegistry}.
|
|
23
|
-
*/
|
|
24
|
-
export interface ComponentRegistry {
|
|
25
|
-
/** The underlying name → component map. */
|
|
26
|
-
entries: Record<string, ComponentType<any>>;
|
|
27
|
-
/** All registered names, for help/error output. */
|
|
28
|
-
available(): string[];
|
|
29
|
-
/** Resolve a registered component by name, tolerant of case and separators. */
|
|
30
|
-
resolve(name: string | null | undefined): ComponentType<any> | undefined;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Create a name → component registry whose `resolve` is case- and
|
|
35
|
-
* separator-insensitive (`LimitDistributionChart` === `limit-distribution-chart`).
|
|
36
|
-
*/
|
|
37
|
-
export function createComponentRegistry(
|
|
38
|
-
entries: Record<string, ComponentType<any>>,
|
|
39
|
-
): ComponentRegistry {
|
|
40
|
-
return {
|
|
41
|
-
entries,
|
|
42
|
-
available: () => Object.keys(entries),
|
|
43
|
-
resolve(name) {
|
|
44
|
-
if (!name) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
const direct = entries[name];
|
|
48
|
-
if (direct) {
|
|
49
|
-
return direct;
|
|
50
|
-
}
|
|
51
|
-
const target = normalize(name);
|
|
52
|
-
const key = Object.keys(entries).find((k) => normalize(k) === target);
|
|
53
|
-
return key ? entries[key] : undefined;
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Props for {@link SingleComponentOutlet}.
|
|
60
|
-
*/
|
|
61
|
-
export interface SingleComponentOutletProps {
|
|
62
|
-
/** The requested component name (typically captured via {@link readInitialParam}). */
|
|
63
|
-
name: string | null | undefined;
|
|
64
|
-
/** Registry to resolve the name against. */
|
|
65
|
-
registry: ComponentRegistry;
|
|
66
|
-
/**
|
|
67
|
-
* Render when no component matches. Defaults to a plain, unstyled
|
|
68
|
-
* "Unknown component" message; pass your own to theme it.
|
|
69
|
-
*/
|
|
70
|
-
renderUnknown?: (name: string | null | undefined, available: string[]) => ReactNode;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const defaultUnknown = (name: string | null | undefined, available: string[]): ReactNode => (
|
|
74
|
-
<div role="alert" style={{ padding: 16 }}>
|
|
75
|
-
{`Unknown component "${name ?? ''}". Available: ${available.join(', ')}`}
|
|
76
|
-
</div>
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Resolve `name` against `registry` and render the matching component, or a
|
|
81
|
-
* fallback when unmatched.
|
|
82
|
-
*
|
|
83
|
-
* Theming/provider chrome is intentionally left to the caller — wrap this outlet
|
|
84
|
-
* in your app's design-system provider so the standalone component is themed
|
|
85
|
-
* identically to how it appears in-app.
|
|
86
|
-
*/
|
|
87
|
-
export function SingleComponentOutlet({
|
|
88
|
-
name,
|
|
89
|
-
registry,
|
|
90
|
-
renderUnknown = defaultUnknown,
|
|
91
|
-
}: SingleComponentOutletProps) {
|
|
92
|
-
const Component = registry.resolve(name);
|
|
93
|
-
return <>{Component ? <Component /> : renderUnknown(name, registry.available())}</>;
|
|
94
|
-
}
|