piral-core 0.15.0-alpha.3592 → 0.15.0-alpha.3640
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/debug.codegen +24 -0
- package/debug.codegen.d.ts +11 -0
- package/dependencies.codegen +6 -4
- package/dependencies.codegen.d.ts +1 -0
- package/dependencies.codegen.native.js +1 -1
- package/esm/RootListener.js +1 -1
- package/esm/RootListener.js.map +1 -1
- package/esm/components/ExtensionSlot.js +20 -2
- package/esm/components/ExtensionSlot.js.map +1 -1
- package/esm/components/ForeignComponentContainer.d.ts +19 -0
- package/esm/components/ForeignComponentContainer.js +52 -0
- package/esm/components/ForeignComponentContainer.js.map +1 -0
- package/esm/components/index.d.ts +1 -0
- package/esm/components/index.js +1 -0
- package/esm/components/index.js.map +1 -1
- package/esm/components/wrapComponent.d.ts +7 -0
- package/esm/components/wrapComponent.js +42 -0
- package/esm/components/wrapComponent.js.map +1 -0
- package/esm/createInstance.js +1 -1
- package/esm/createInstance.js.map +1 -1
- package/esm/debugger.d.ts +1 -1
- package/esm/debugger.js +1 -1
- package/esm/debugger.js.map +1 -1
- package/esm/emulator.d.ts +1 -1
- package/esm/emulator.js +1 -1
- package/esm/emulator.js.map +1 -1
- package/esm/helpers.d.ts +1 -1
- package/esm/helpers.js +3 -10
- package/esm/helpers.js.map +1 -1
- package/esm/modules/dependencies.js +3 -23
- package/esm/modules/dependencies.js.map +1 -1
- package/esm/state/withApi.js +8 -92
- package/esm/state/withApi.js.map +1 -1
- package/esm/types/api.d.ts +2 -2
- package/esm/types/extension.d.ts +5 -1
- package/lib/RootListener.js +2 -2
- package/lib/RootListener.js.map +1 -1
- package/lib/components/ExtensionSlot.js +19 -1
- package/lib/components/ExtensionSlot.js.map +1 -1
- package/lib/components/ForeignComponentContainer.d.ts +19 -0
- package/lib/components/ForeignComponentContainer.js +56 -0
- package/lib/components/ForeignComponentContainer.js.map +1 -0
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +1 -0
- package/lib/components/index.js.map +1 -1
- package/lib/components/wrapComponent.d.ts +7 -0
- package/lib/components/wrapComponent.js +46 -0
- package/lib/components/wrapComponent.js.map +1 -0
- package/lib/createInstance.js +1 -1
- package/lib/createInstance.js.map +1 -1
- package/lib/debugger.d.ts +1 -1
- package/lib/debugger.js +3 -3
- package/lib/debugger.js.map +1 -1
- package/lib/emulator.d.ts +1 -1
- package/lib/emulator.js +3 -3
- package/lib/emulator.js.map +1 -1
- package/lib/helpers.d.ts +1 -1
- package/lib/helpers.js +3 -10
- package/lib/helpers.js.map +1 -1
- package/lib/modules/dependencies.js +3 -23
- package/lib/modules/dependencies.js.map +1 -1
- package/lib/state/withApi.js +7 -91
- package/lib/state/withApi.js.map +1 -1
- package/lib/types/api.d.ts +2 -2
- package/lib/types/extension.d.ts +5 -1
- package/package.json +7 -5
- package/src/RootListener.tsx +1 -1
- package/src/components/ExtensionSlot.tsx +25 -3
- package/src/components/ForeignComponentContainer.tsx +69 -0
- package/src/components/index.ts +1 -0
- package/src/components/wrapComponent.tsx +74 -0
- package/src/createInstance.tsx +1 -1
- package/src/debugger.ts +1 -1
- package/src/emulator.ts +1 -1
- package/src/helpers.tsx +4 -12
- package/src/modules/dependencies.ts +3 -22
- package/src/state/withApi.tsx +21 -156
- package/src/types/api.ts +2 -2
- package/src/types/extension.ts +12 -3
package/src/RootListener.tsx
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { isfunc } from 'piral-base';
|
|
3
|
-
import {
|
|
3
|
+
import { wrapComponent } from './wrapComponent';
|
|
4
|
+
import { useGlobalState, useGlobalStateContext } from '../hooks';
|
|
4
5
|
import { defaultRender, none } from '../utils';
|
|
5
|
-
import { ExtensionSlotProps } from '../types';
|
|
6
|
+
import { ExtensionRegistration, ExtensionSlotProps } from '../types';
|
|
7
|
+
|
|
8
|
+
const renderExtensions: [ExtensionRegistration] = [
|
|
9
|
+
{
|
|
10
|
+
component: (props) => {
|
|
11
|
+
const context = useGlobalStateContext();
|
|
12
|
+
const converters = context.converters;
|
|
13
|
+
const piral = context.apis._;
|
|
14
|
+
const { component, props: args } = props.params;
|
|
15
|
+
const Component = React.useMemo(
|
|
16
|
+
() => wrapComponent(converters, component, { piral }, defaultRender),
|
|
17
|
+
[component],
|
|
18
|
+
);
|
|
19
|
+
return <Component {...args} />;
|
|
20
|
+
},
|
|
21
|
+
defaults: {},
|
|
22
|
+
pilet: '',
|
|
23
|
+
reference: {
|
|
24
|
+
displayName: 'RenderExtension',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
];
|
|
6
28
|
|
|
7
29
|
/**
|
|
8
30
|
* The extension slot component to be used when the available
|
|
@@ -11,7 +33,7 @@ import { ExtensionSlotProps } from '../types';
|
|
|
11
33
|
*/
|
|
12
34
|
export function ExtensionSlot<T extends string>(props: ExtensionSlotProps<T>) {
|
|
13
35
|
const { name, render = defaultRender, empty, params, children } = props;
|
|
14
|
-
const extensions = useGlobalState((s) => s.registry.extensions[name] || none);
|
|
36
|
+
const extensions = useGlobalState((s) => (name ? s.registry.extensions[name] || none : renderExtensions));
|
|
15
37
|
return render(
|
|
16
38
|
extensions.length === 0 && isfunc(empty)
|
|
17
39
|
? [defaultRender(empty(), 'empty')]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { isfunc } from 'piral-base';
|
|
3
|
+
import { __RouterContext } from 'react-router';
|
|
4
|
+
import { ForeignComponent, BaseComponentProps, ComponentContext } from '../types';
|
|
5
|
+
|
|
6
|
+
interface ForeignComponentContainerProps<T> {
|
|
7
|
+
$portalId: string;
|
|
8
|
+
$component: ForeignComponent<T>;
|
|
9
|
+
$context: ComponentContext;
|
|
10
|
+
innerProps: T & BaseComponentProps;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class ForeignComponentContainer<T> extends React.Component<ForeignComponentContainerProps<T>> {
|
|
14
|
+
private current?: HTMLElement;
|
|
15
|
+
private previous?: HTMLElement;
|
|
16
|
+
private handler = (ev: CustomEvent) => {
|
|
17
|
+
const { innerProps } = this.props;
|
|
18
|
+
ev.stopPropagation();
|
|
19
|
+
innerProps.piral.renderHtmlExtension(ev.detail.target, ev.detail.props);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
private setNode = (node: HTMLDivElement) => {
|
|
23
|
+
this.current = node;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
componentDidMount() {
|
|
27
|
+
const node = this.current;
|
|
28
|
+
const { $component, $context, innerProps } = this.props;
|
|
29
|
+
const { mount } = $component;
|
|
30
|
+
|
|
31
|
+
if (node && isfunc(mount)) {
|
|
32
|
+
mount(node, innerProps, $context);
|
|
33
|
+
node.addEventListener('render-html', this.handler, false);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.previous = node;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
componentDidUpdate() {
|
|
40
|
+
const { current, previous } = this;
|
|
41
|
+
const { $component, $context, innerProps } = this.props;
|
|
42
|
+
const { update } = $component;
|
|
43
|
+
|
|
44
|
+
if (current !== previous) {
|
|
45
|
+
previous && this.componentWillUnmount();
|
|
46
|
+
current && this.componentDidMount();
|
|
47
|
+
} else if (isfunc(update)) {
|
|
48
|
+
update(current, innerProps, $context);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
componentWillUnmount() {
|
|
53
|
+
const node = this.previous;
|
|
54
|
+
const { $component } = this.props;
|
|
55
|
+
const { unmount } = $component;
|
|
56
|
+
|
|
57
|
+
if (node && isfunc(unmount)) {
|
|
58
|
+
unmount(node);
|
|
59
|
+
node.removeEventListener('render-html', this.handler, false);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.previous = undefined;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
render() {
|
|
66
|
+
const { $portalId } = this.props;
|
|
67
|
+
return <div data-portal-id={$portalId} ref={this.setNode} />;
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { __RouterContext } from 'react-router';
|
|
3
|
+
import { PortalRenderer } from './PortalRenderer';
|
|
4
|
+
import { ForeignComponentContainer } from './ForeignComponentContainer';
|
|
5
|
+
import { useGlobalStateContext } from '../hooks';
|
|
6
|
+
import { convertComponent, none } from '../utils';
|
|
7
|
+
import { AnyComponent, ComponentConverters, ForeignComponent, PiletApi, BaseComponentProps } from '../types';
|
|
8
|
+
|
|
9
|
+
// this is an arbitrary start number to have 6 digits
|
|
10
|
+
let portalIdBase = 123456;
|
|
11
|
+
|
|
12
|
+
interface CapturedProps {
|
|
13
|
+
piral: PiletApi;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function wrapReactComponent<T>(
|
|
17
|
+
Component: React.ComponentType<T & BaseComponentProps>,
|
|
18
|
+
captured: CapturedProps,
|
|
19
|
+
Wrapper: React.FC<T>,
|
|
20
|
+
): React.ComponentType<T> {
|
|
21
|
+
return (props: T) => (
|
|
22
|
+
<Wrapper {...props}>
|
|
23
|
+
<Component {...props} {...captured} />
|
|
24
|
+
</Wrapper>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function wrapForeignComponent<T>(
|
|
29
|
+
component: ForeignComponent<T & BaseComponentProps>,
|
|
30
|
+
captured: CapturedProps,
|
|
31
|
+
Wrapper: React.FC<T>,
|
|
32
|
+
) {
|
|
33
|
+
return React.memo((props: T) => {
|
|
34
|
+
const { state, readState, destroyPortal } = useGlobalStateContext();
|
|
35
|
+
const router = React.useContext(__RouterContext);
|
|
36
|
+
const id = React.useMemo(() => (portalIdBase++).toString(26), none);
|
|
37
|
+
const context = React.useMemo(() => ({ router, state, readState }), [router, state]);
|
|
38
|
+
const innerProps = React.useMemo(() => ({ ...props, ...captured }), [props]);
|
|
39
|
+
|
|
40
|
+
React.useEffect(() => () => destroyPortal(id), none);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Wrapper {...props}>
|
|
44
|
+
<PortalRenderer id={id} />
|
|
45
|
+
<ForeignComponentContainer innerProps={innerProps} $portalId={id} $component={component} $context={context} />
|
|
46
|
+
</Wrapper>
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isNotExotic(component: any): component is object {
|
|
52
|
+
return !(component as React.ExoticComponent).$$typeof;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function wrapComponent<T>(
|
|
56
|
+
converters: ComponentConverters<T & BaseComponentProps>,
|
|
57
|
+
component: AnyComponent<T & BaseComponentProps>,
|
|
58
|
+
captured: CapturedProps,
|
|
59
|
+
Wrapper: React.FC<T>,
|
|
60
|
+
) {
|
|
61
|
+
if (!component) {
|
|
62
|
+
const pilet = captured.piral.meta.name;
|
|
63
|
+
console.error(`[${pilet}] The given value is not a valid component.`);
|
|
64
|
+
// tslint:disable-next-line:no-null-keyword
|
|
65
|
+
component = () => null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (typeof component === 'object' && isNotExotic(component)) {
|
|
69
|
+
const result = convertComponent(converters[component.type], component);
|
|
70
|
+
return wrapForeignComponent<T>(result, captured, Wrapper);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return wrapReactComponent<T>(component, captured, Wrapper);
|
|
74
|
+
}
|
package/src/createInstance.tsx
CHANGED
|
@@ -49,7 +49,7 @@ export function createInstance(config: PiralInstanceOptions = {}): PiralInstance
|
|
|
49
49
|
const usedPlugins = Array.isArray(definedPlugins) ? definedPlugins : [definedPlugins];
|
|
50
50
|
const createApi = apiFactory(context, usedPlugins);
|
|
51
51
|
const root = createApi({
|
|
52
|
-
name: '
|
|
52
|
+
name: '_',
|
|
53
53
|
version: process.env.BUILD_PCKG_VERSION || '1.0.0',
|
|
54
54
|
spec: 'v0',
|
|
55
55
|
basePath: '',
|
package/src/debugger.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { LoadPiletsOptions } from 'piral-base';
|
|
|
3
3
|
import { installPiralDebug, DebuggerExtensionOptions } from 'piral-debug-utils';
|
|
4
4
|
import { GlobalStateContext } from './types';
|
|
5
5
|
|
|
6
|
-
export function
|
|
6
|
+
export function integrateDebugger(
|
|
7
7
|
context: GlobalStateContext,
|
|
8
8
|
options: LoadPiletsOptions,
|
|
9
9
|
debug: DebuggerExtensionOptions = {},
|
package/src/emulator.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { LoadPiletsOptions } from 'piral-base';
|
|
|
2
2
|
import { withEmulatorPilets } from 'piral-debug-utils';
|
|
3
3
|
import { GlobalStateContext } from './types';
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function integrateEmulator(context: GlobalStateContext, options: LoadPiletsOptions) {
|
|
6
6
|
options.fetchPilets = withEmulatorPilets(options.fetchPilets, {
|
|
7
7
|
addPilet: context.addPilet,
|
|
8
8
|
removePilet: context.removePilet,
|
package/src/helpers.tsx
CHANGED
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
PiletLoader,
|
|
9
9
|
PiletLifecycleHooks,
|
|
10
10
|
} from 'piral-base';
|
|
11
|
-
import { DebuggerExtensionOptions } from 'piral-debug-utils';
|
|
11
|
+
import type { DebuggerExtensionOptions } from 'piral-debug-utils';
|
|
12
12
|
import { globalDependencies } from './modules';
|
|
13
13
|
import type { Pilet, PiletRequester, GlobalStateContext, PiletLoadingStrategy, DependencySelector } from './types';
|
|
14
|
+
import { integrateDebugger, integrateEmulator } from '../debug.codegen';
|
|
14
15
|
|
|
15
16
|
export interface PiletOptionsConfig {
|
|
16
17
|
context: GlobalStateContext;
|
|
@@ -50,17 +51,8 @@ export function createPiletOptions({
|
|
|
50
51
|
dependencies: shareDependencies(globalDependencies),
|
|
51
52
|
};
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const { integrate } = require('./debugger');
|
|
56
|
-
integrate(context, options, debug);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// if we build the emulator version of piral (shipped to pilets)
|
|
60
|
-
if (process.env.DEBUG_PILET) {
|
|
61
|
-
const { integrate } = require('./emulator');
|
|
62
|
-
integrate(context, options);
|
|
63
|
-
}
|
|
54
|
+
integrateDebugger(context, options, debug);
|
|
55
|
+
integrateEmulator(context, options, debug);
|
|
64
56
|
|
|
65
57
|
return options;
|
|
66
58
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isfunc } from 'piral-base';
|
|
2
|
-
import { __assign } from 'tslib';
|
|
3
2
|
import type { AvailableDependencies, PiletEntries } from '../types';
|
|
3
|
+
import fillDependencies from '../../dependencies.codegen';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* The global dependencies, which represent the dependencies
|
|
@@ -8,27 +8,8 @@ import type { AvailableDependencies, PiletEntries } from '../types';
|
|
|
8
8
|
*/
|
|
9
9
|
export const globalDependencies: AvailableDependencies = {};
|
|
10
10
|
|
|
11
|
-
if (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (isfunc(fillDependencies)) {
|
|
15
|
-
fillDependencies(globalDependencies);
|
|
16
|
-
} else {
|
|
17
|
-
// fall back to the default list if the codegen is invalid / not supported
|
|
18
|
-
__assign(globalDependencies, {
|
|
19
|
-
react: require('react'),
|
|
20
|
-
'react-dom': require('react-dom'),
|
|
21
|
-
'react-router': require('react-router'),
|
|
22
|
-
'react-router-dom': require('react-router-dom'),
|
|
23
|
-
history: require('history'),
|
|
24
|
-
tslib: require('tslib'),
|
|
25
|
-
'path-to-regexp': require('path-to-regexp'),
|
|
26
|
-
'@libre/atom': require('@libre/atom'),
|
|
27
|
-
'@dbeining/react-atom': require('@dbeining/react-atom'),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
} else {
|
|
31
|
-
// App shell is built with something else than the Piral CLI - just don't fill ...
|
|
11
|
+
if (isfunc(fillDependencies)) {
|
|
12
|
+
fillDependencies(globalDependencies);
|
|
32
13
|
}
|
|
33
14
|
|
|
34
15
|
/**
|
package/src/state/withApi.tsx
CHANGED
|
@@ -1,147 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { isfunc } from 'piral-base';
|
|
3
2
|
import { __RouterContext } from 'react-router';
|
|
4
|
-
import { ErrorBoundary,
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
AnyComponent,
|
|
9
|
-
Errors,
|
|
10
|
-
ComponentConverters,
|
|
11
|
-
ForeignComponent,
|
|
12
|
-
PiletApi,
|
|
13
|
-
BaseComponentProps,
|
|
14
|
-
ComponentContext,
|
|
15
|
-
GlobalStateContext,
|
|
16
|
-
} from '../types';
|
|
17
|
-
|
|
18
|
-
// this is an arbitrary start number to have 6 digits
|
|
19
|
-
let portalIdBase = 123456;
|
|
3
|
+
import { ErrorBoundary, wrapComponent } from '../components';
|
|
4
|
+
import { defaultRender } from '../utils';
|
|
5
|
+
import { AnyComponent, Errors, PiletApi, BaseComponentProps, GlobalStateContext } from '../types';
|
|
20
6
|
|
|
21
7
|
const DefaultWrapper: React.FC = (props) => defaultRender(props.children);
|
|
22
8
|
|
|
23
|
-
interface CapturedProps {
|
|
24
|
-
piral: PiletApi;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
interface ForeignComponentContainerProps<T> {
|
|
28
|
-
$portalId: string;
|
|
29
|
-
$component: ForeignComponent<T>;
|
|
30
|
-
$context: ComponentContext;
|
|
31
|
-
innerProps: T & BaseComponentProps;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
class ForeignComponentContainer<T> extends React.Component<ForeignComponentContainerProps<T>> {
|
|
35
|
-
private current?: HTMLElement;
|
|
36
|
-
private previous?: HTMLElement;
|
|
37
|
-
private handler = (ev: CustomEvent) => {
|
|
38
|
-
const { innerProps } = this.props;
|
|
39
|
-
ev.stopPropagation();
|
|
40
|
-
innerProps.piral.renderHtmlExtension(ev.detail.target, ev.detail.props);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
private setNode = (node: HTMLDivElement) => {
|
|
44
|
-
this.current = node;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
componentDidMount() {
|
|
48
|
-
const node = this.current;
|
|
49
|
-
const { $component, $context, innerProps } = this.props;
|
|
50
|
-
const { mount } = $component;
|
|
51
|
-
|
|
52
|
-
if (node && isfunc(mount)) {
|
|
53
|
-
mount(node, innerProps, $context);
|
|
54
|
-
node.addEventListener('render-html', this.handler, false);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
this.previous = node;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
componentDidUpdate() {
|
|
61
|
-
const { current, previous } = this;
|
|
62
|
-
const { $component, $context, innerProps } = this.props;
|
|
63
|
-
const { update } = $component;
|
|
64
|
-
|
|
65
|
-
if (current !== previous) {
|
|
66
|
-
previous && this.componentWillUnmount();
|
|
67
|
-
current && this.componentDidMount();
|
|
68
|
-
} else if (isfunc(update)) {
|
|
69
|
-
update(current, innerProps, $context);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
componentWillUnmount() {
|
|
74
|
-
const node = this.previous;
|
|
75
|
-
const { $component } = this.props;
|
|
76
|
-
const { unmount } = $component;
|
|
77
|
-
|
|
78
|
-
if (node && isfunc(unmount)) {
|
|
79
|
-
unmount(node);
|
|
80
|
-
node.removeEventListener('render-html', this.handler, false);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
this.previous = undefined;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
render() {
|
|
87
|
-
const { $portalId } = this.props;
|
|
88
|
-
return <div data-portal-id={$portalId} ref={this.setNode} />;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function wrapReactComponent<T>(
|
|
93
|
-
Component: React.ComponentType<T & BaseComponentProps>,
|
|
94
|
-
captured: CapturedProps,
|
|
95
|
-
Wrapper: React.FC<T>,
|
|
96
|
-
): React.ComponentType<T> {
|
|
97
|
-
return (props: T) => (
|
|
98
|
-
<Wrapper {...props}>
|
|
99
|
-
<Component {...props} {...captured} />
|
|
100
|
-
</Wrapper>
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function wrapForeignComponent<T>(
|
|
105
|
-
component: ForeignComponent<T & BaseComponentProps>,
|
|
106
|
-
captured: CapturedProps,
|
|
107
|
-
Wrapper: React.FC<T>,
|
|
108
|
-
) {
|
|
109
|
-
return React.memo((props: T) => {
|
|
110
|
-
const { state, readState, destroyPortal } = useGlobalStateContext();
|
|
111
|
-
const router = React.useContext(__RouterContext);
|
|
112
|
-
const id = React.useMemo(() => (portalIdBase++).toString(26), none);
|
|
113
|
-
const context = React.useMemo(() => ({ router, state, readState }), [router, state]);
|
|
114
|
-
const innerProps = React.useMemo(() => ({ ...props, ...captured }), [props]);
|
|
115
|
-
|
|
116
|
-
React.useEffect(() => () => destroyPortal(id), none);
|
|
117
|
-
|
|
118
|
-
return (
|
|
119
|
-
<Wrapper {...props}>
|
|
120
|
-
<PortalRenderer id={id} />
|
|
121
|
-
<ForeignComponentContainer innerProps={innerProps} $portalId={id} $component={component} $context={context} />
|
|
122
|
-
</Wrapper>
|
|
123
|
-
);
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function isNotExotic(component: any): component is object {
|
|
128
|
-
return !(component as React.ExoticComponent).$$typeof;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function wrapComponent<T>(
|
|
132
|
-
converters: ComponentConverters<T & BaseComponentProps>,
|
|
133
|
-
component: AnyComponent<T & BaseComponentProps>,
|
|
134
|
-
captured: CapturedProps,
|
|
135
|
-
Wrapper: React.FC<T>,
|
|
136
|
-
) {
|
|
137
|
-
if (typeof component === 'object' && isNotExotic(component)) {
|
|
138
|
-
const result = convertComponent(converters[component.type], component);
|
|
139
|
-
return wrapForeignComponent<T>(result, captured, Wrapper);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return wrapReactComponent<T>(component, captured, Wrapper);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
9
|
function getWrapper(wrappers: Record<string, React.ComponentType<any>>, wrapperType: string) {
|
|
146
10
|
const WrapAll = wrappers['*'];
|
|
147
11
|
const WrapType = wrappers[wrapperType];
|
|
@@ -157,32 +21,33 @@ function getWrapper(wrappers: Record<string, React.ComponentType<any>>, wrapperT
|
|
|
157
21
|
return WrapType || WrapAll || DefaultWrapper;
|
|
158
22
|
}
|
|
159
23
|
|
|
160
|
-
|
|
24
|
+
function makeWrapper<TProps>(
|
|
161
25
|
context: GlobalStateContext,
|
|
162
|
-
|
|
163
|
-
|
|
26
|
+
outerProps: any,
|
|
27
|
+
wrapperType: string,
|
|
164
28
|
errorType: keyof Errors,
|
|
165
|
-
|
|
166
|
-
captured = {},
|
|
167
|
-
) {
|
|
168
|
-
const outerProps = { ...captured, piral };
|
|
169
|
-
const converters = context.converters;
|
|
29
|
+
): React.FC<TProps> {
|
|
170
30
|
const OuterWrapper = context.readState((m) => getWrapper(m.registry.wrappers, wrapperType));
|
|
171
31
|
|
|
172
|
-
|
|
32
|
+
return (props) => (
|
|
173
33
|
<OuterWrapper {...outerProps} {...props}>
|
|
174
34
|
<ErrorBoundary {...outerProps} {...props} errorType={errorType}>
|
|
175
35
|
{props.children}
|
|
176
36
|
</ErrorBoundary>
|
|
177
37
|
</OuterWrapper>
|
|
178
38
|
);
|
|
39
|
+
}
|
|
179
40
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
41
|
+
export function withApi<TProps>(
|
|
42
|
+
context: GlobalStateContext,
|
|
43
|
+
component: AnyComponent<TProps & BaseComponentProps>,
|
|
44
|
+
piral: PiletApi,
|
|
45
|
+
errorType: keyof Errors,
|
|
46
|
+
wrapperType: string = errorType,
|
|
47
|
+
captured = {},
|
|
48
|
+
) {
|
|
49
|
+
const outerProps = { ...captured, piral };
|
|
50
|
+
const converters = context.converters;
|
|
51
|
+
const Wrapper = makeWrapper<TProps>(context, outerProps, wrapperType, errorType);
|
|
52
|
+
return wrapComponent(converters, component, outerProps, Wrapper);
|
|
188
53
|
}
|
package/src/types/api.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
} from 'piral-base';
|
|
13
13
|
import type { PiletCustomApi, PiralCustomPageMeta } from './custom';
|
|
14
14
|
import type { AnyComponent } from './components';
|
|
15
|
-
import type { ExtensionSlotProps, PiralExtensionSlotMap } from './extension';
|
|
15
|
+
import type { ExtensionParams, ExtensionSlotProps, PiralExtensionSlotMap } from './extension';
|
|
16
16
|
import type { SharedData, DataStoreOptions } from './data';
|
|
17
17
|
import type { Disposable } from './utils';
|
|
18
18
|
|
|
@@ -113,7 +113,7 @@ export interface PiletCoreApi {
|
|
|
113
113
|
registerExtension<TName>(
|
|
114
114
|
name: TName extends string ? TName : string,
|
|
115
115
|
Component: AnyComponent<ExtensionComponentProps<TName>>,
|
|
116
|
-
defaults?: TName
|
|
116
|
+
defaults?: Partial<ExtensionParams<TName>>,
|
|
117
117
|
): RegistrationDisposer;
|
|
118
118
|
/**
|
|
119
119
|
* Unregisters a global extension component.
|
package/src/types/extension.ts
CHANGED
|
@@ -34,10 +34,19 @@ export interface BaseExtensionSlotProps<TName, TParams> {
|
|
|
34
34
|
name: TName;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Gives the extension params shape for the given extension slot name.
|
|
39
|
+
*/
|
|
40
|
+
export type ExtensionParams<TName> = TName extends keyof PiralExtensionSlotMap
|
|
41
|
+
? PiralExtensionSlotMap[TName]
|
|
42
|
+
: TName extends string
|
|
43
|
+
? any
|
|
44
|
+
: TName;
|
|
45
|
+
|
|
37
46
|
/**
|
|
38
47
|
* The props for defining an extension slot.
|
|
39
48
|
*/
|
|
40
|
-
export type ExtensionSlotProps<
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
export type ExtensionSlotProps<TName = string> = BaseExtensionSlotProps<
|
|
50
|
+
TName extends string ? TName : string,
|
|
51
|
+
ExtensionParams<TName>
|
|
43
52
|
>;
|