@elementor/locations 0.7.6 → 0.8.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/CHANGELOG.md +12 -0
- package/dist/index.d.mts +36 -2
- package/dist/index.d.ts +36 -2
- package/dist/index.js +64 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -1
- package/src/components/error-boundary.tsx +1 -1
- package/src/components/injected-component-wrapper.tsx +2 -1
- package/src/{api.tsx → create-location.tsx} +9 -30
- package/src/create-replaceable-location.tsx +65 -0
- package/src/index.ts +3 -1
- package/src/injections.tsx +34 -0
- package/src/types.ts +39 -1
package/CHANGELOG.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType } from 'react';
|
|
1
|
+
import { ComponentType, PropsWithChildren } from 'react';
|
|
2
2
|
|
|
3
3
|
type AnyProps = object;
|
|
4
4
|
type InjectedComponent<TProps extends object = AnyProps> = ComponentType<TProps>;
|
|
@@ -18,6 +18,12 @@ type Injection<TProps extends object = AnyProps> = {
|
|
|
18
18
|
*/
|
|
19
19
|
priority: Priority;
|
|
20
20
|
};
|
|
21
|
+
type ReplaceableInjection<TProps extends object = AnyProps> = Injection<TProps> & {
|
|
22
|
+
/**
|
|
23
|
+
* A function that returns a boolean indicating whether the injection should be applied or not.
|
|
24
|
+
*/
|
|
25
|
+
condition?: (props: TProps) => boolean;
|
|
26
|
+
};
|
|
21
27
|
type InjectArgs<TProps extends object = AnyProps> = {
|
|
22
28
|
/**
|
|
23
29
|
* A unique id (per location) of the component to be injected.
|
|
@@ -38,6 +44,18 @@ type InjectArgs<TProps extends object = AnyProps> = {
|
|
|
38
44
|
overwrite?: boolean;
|
|
39
45
|
};
|
|
40
46
|
};
|
|
47
|
+
type ReplaceableInjectArgs<TProps extends object = AnyProps> = Pick<InjectArgs<TProps>, 'id' | 'component'> & {
|
|
48
|
+
/**
|
|
49
|
+
* A function that returns a boolean indicating whether the injection should be applied or not.
|
|
50
|
+
*/
|
|
51
|
+
condition?: (props: TProps) => boolean;
|
|
52
|
+
options?: {
|
|
53
|
+
/**
|
|
54
|
+
* Priority of the injected component inside the location. Lower value means higher priority.
|
|
55
|
+
*/
|
|
56
|
+
priority?: Priority;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
41
59
|
type Location<TProps extends object = AnyProps> = {
|
|
42
60
|
/**
|
|
43
61
|
* Inject a component into the location.
|
|
@@ -51,8 +69,24 @@ type Location<TProps extends object = AnyProps> = {
|
|
|
51
69
|
useInjections: () => Injection<TProps>[];
|
|
52
70
|
Slot: ComponentType<TProps>;
|
|
53
71
|
};
|
|
72
|
+
type ReplaceableLocation<TProps extends object = AnyProps> = {
|
|
73
|
+
/**
|
|
74
|
+
* Register a component into the location.
|
|
75
|
+
*/
|
|
76
|
+
inject: (args: ReplaceableInjectArgs<TProps>) => void;
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @return All the injections in the location.
|
|
80
|
+
*/
|
|
81
|
+
getInjections: () => ReplaceableInjection<TProps>[];
|
|
82
|
+
useInjections: () => ReplaceableInjection<TProps>[];
|
|
83
|
+
Slot: ComponentType<PropsWithChildren<TProps>>;
|
|
84
|
+
};
|
|
54
85
|
|
|
55
86
|
declare function createLocation<TProps extends object = AnyProps>(): Location<TProps>;
|
|
87
|
+
|
|
88
|
+
declare function createReplaceableLocation<TProps extends object = AnyProps>(): ReplaceableLocation<TProps>;
|
|
89
|
+
|
|
56
90
|
declare function flushAllInjections(): void;
|
|
57
91
|
|
|
58
|
-
export { type AnyProps, type Id, type InjectArgs, type InjectedComponent, type Injection, type Location, type Priority, flushAllInjections as __flushAllInjections, createLocation };
|
|
92
|
+
export { type AnyProps, type Id, type InjectArgs, type InjectedComponent, type Injection, type Location, type Priority, type ReplaceableInjectArgs, type ReplaceableInjection, type ReplaceableLocation, flushAllInjections as __flushAllInjections, createLocation, createReplaceableLocation };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType } from 'react';
|
|
1
|
+
import { ComponentType, PropsWithChildren } from 'react';
|
|
2
2
|
|
|
3
3
|
type AnyProps = object;
|
|
4
4
|
type InjectedComponent<TProps extends object = AnyProps> = ComponentType<TProps>;
|
|
@@ -18,6 +18,12 @@ type Injection<TProps extends object = AnyProps> = {
|
|
|
18
18
|
*/
|
|
19
19
|
priority: Priority;
|
|
20
20
|
};
|
|
21
|
+
type ReplaceableInjection<TProps extends object = AnyProps> = Injection<TProps> & {
|
|
22
|
+
/**
|
|
23
|
+
* A function that returns a boolean indicating whether the injection should be applied or not.
|
|
24
|
+
*/
|
|
25
|
+
condition?: (props: TProps) => boolean;
|
|
26
|
+
};
|
|
21
27
|
type InjectArgs<TProps extends object = AnyProps> = {
|
|
22
28
|
/**
|
|
23
29
|
* A unique id (per location) of the component to be injected.
|
|
@@ -38,6 +44,18 @@ type InjectArgs<TProps extends object = AnyProps> = {
|
|
|
38
44
|
overwrite?: boolean;
|
|
39
45
|
};
|
|
40
46
|
};
|
|
47
|
+
type ReplaceableInjectArgs<TProps extends object = AnyProps> = Pick<InjectArgs<TProps>, 'id' | 'component'> & {
|
|
48
|
+
/**
|
|
49
|
+
* A function that returns a boolean indicating whether the injection should be applied or not.
|
|
50
|
+
*/
|
|
51
|
+
condition?: (props: TProps) => boolean;
|
|
52
|
+
options?: {
|
|
53
|
+
/**
|
|
54
|
+
* Priority of the injected component inside the location. Lower value means higher priority.
|
|
55
|
+
*/
|
|
56
|
+
priority?: Priority;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
41
59
|
type Location<TProps extends object = AnyProps> = {
|
|
42
60
|
/**
|
|
43
61
|
* Inject a component into the location.
|
|
@@ -51,8 +69,24 @@ type Location<TProps extends object = AnyProps> = {
|
|
|
51
69
|
useInjections: () => Injection<TProps>[];
|
|
52
70
|
Slot: ComponentType<TProps>;
|
|
53
71
|
};
|
|
72
|
+
type ReplaceableLocation<TProps extends object = AnyProps> = {
|
|
73
|
+
/**
|
|
74
|
+
* Register a component into the location.
|
|
75
|
+
*/
|
|
76
|
+
inject: (args: ReplaceableInjectArgs<TProps>) => void;
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @return All the injections in the location.
|
|
80
|
+
*/
|
|
81
|
+
getInjections: () => ReplaceableInjection<TProps>[];
|
|
82
|
+
useInjections: () => ReplaceableInjection<TProps>[];
|
|
83
|
+
Slot: ComponentType<PropsWithChildren<TProps>>;
|
|
84
|
+
};
|
|
54
85
|
|
|
55
86
|
declare function createLocation<TProps extends object = AnyProps>(): Location<TProps>;
|
|
87
|
+
|
|
88
|
+
declare function createReplaceableLocation<TProps extends object = AnyProps>(): ReplaceableLocation<TProps>;
|
|
89
|
+
|
|
56
90
|
declare function flushAllInjections(): void;
|
|
57
91
|
|
|
58
|
-
export { type AnyProps, type Id, type InjectArgs, type InjectedComponent, type Injection, type Location, type Priority, flushAllInjections as __flushAllInjections, createLocation };
|
|
92
|
+
export { type AnyProps, type Id, type InjectArgs, type InjectedComponent, type Injection, type Location, type Priority, type ReplaceableInjectArgs, type ReplaceableInjection, type ReplaceableLocation, flushAllInjections as __flushAllInjections, createLocation, createReplaceableLocation };
|
package/dist/index.js
CHANGED
|
@@ -28,15 +28,20 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
30
|
// src/index.ts
|
|
31
|
-
var
|
|
32
|
-
__export(
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
33
|
__flushAllInjections: () => flushAllInjections,
|
|
34
|
-
createLocation: () => createLocation
|
|
34
|
+
createLocation: () => createLocation,
|
|
35
|
+
createReplaceableLocation: () => createReplaceableLocation
|
|
35
36
|
});
|
|
36
|
-
module.exports = __toCommonJS(
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
38
|
|
|
38
|
-
// src/
|
|
39
|
+
// src/create-location.tsx
|
|
40
|
+
var React3 = __toESM(require("react"));
|
|
41
|
+
|
|
42
|
+
// src/injections.tsx
|
|
39
43
|
var React2 = __toESM(require("react"));
|
|
44
|
+
var import_react3 = require("react");
|
|
40
45
|
|
|
41
46
|
// src/components/injected-component-wrapper.tsx
|
|
42
47
|
var React = __toESM(require("react"));
|
|
@@ -64,10 +69,23 @@ function InjectedComponentWrapper({ children }) {
|
|
|
64
69
|
return /* @__PURE__ */ React.createElement(ErrorBoundary, { fallback: null }, /* @__PURE__ */ React.createElement(import_react2.Suspense, { fallback: null }, children));
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
// src/
|
|
68
|
-
var import_react3 = require("react");
|
|
72
|
+
// src/injections.tsx
|
|
69
73
|
var DEFAULT_PRIORITY = 10;
|
|
70
74
|
var flushInjectionsFns = [];
|
|
75
|
+
function flushAllInjections() {
|
|
76
|
+
flushInjectionsFns.forEach((flush) => flush());
|
|
77
|
+
}
|
|
78
|
+
function createGetInjections(injections) {
|
|
79
|
+
return () => [...injections.values()].sort((a, b) => a.priority - b.priority);
|
|
80
|
+
}
|
|
81
|
+
function createUseInjections(getInjections) {
|
|
82
|
+
return () => (0, import_react3.useMemo)(() => getInjections(), []);
|
|
83
|
+
}
|
|
84
|
+
function wrapInjectedComponent(Component2) {
|
|
85
|
+
return (props) => /* @__PURE__ */ React2.createElement(InjectedComponentWrapper, null, /* @__PURE__ */ React2.createElement(Component2, { ...props }));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/create-location.tsx
|
|
71
89
|
function createLocation() {
|
|
72
90
|
const injections = /* @__PURE__ */ new Map();
|
|
73
91
|
const getInjections = createGetInjections(injections);
|
|
@@ -82,21 +100,12 @@ function createLocation() {
|
|
|
82
100
|
Slot
|
|
83
101
|
};
|
|
84
102
|
}
|
|
85
|
-
function flushAllInjections() {
|
|
86
|
-
flushInjectionsFns.forEach((flush) => flush());
|
|
87
|
-
}
|
|
88
|
-
function wrapInjectedComponent(Component2) {
|
|
89
|
-
return (props) => /* @__PURE__ */ React2.createElement(InjectedComponentWrapper, null, /* @__PURE__ */ React2.createElement(Component2, { ...props }));
|
|
90
|
-
}
|
|
91
103
|
function createSlot(useInjections) {
|
|
92
104
|
return (props) => {
|
|
93
105
|
const injections = useInjections();
|
|
94
|
-
return /* @__PURE__ */
|
|
106
|
+
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, injections.map(({ id, component: Component2 }) => /* @__PURE__ */ React3.createElement(Component2, { ...props, key: id })));
|
|
95
107
|
};
|
|
96
108
|
}
|
|
97
|
-
function createGetInjections(injections) {
|
|
98
|
-
return () => [...injections.values()].sort((a, b) => a.priority - b.priority);
|
|
99
|
-
}
|
|
100
109
|
function createInject(injections) {
|
|
101
110
|
return ({ component, id, options = {} }) => {
|
|
102
111
|
if (injections.has(id) && !options?.overwrite) {
|
|
@@ -112,12 +121,47 @@ function createInject(injections) {
|
|
|
112
121
|
});
|
|
113
122
|
};
|
|
114
123
|
}
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
|
|
125
|
+
// src/create-replaceable-location.tsx
|
|
126
|
+
var React4 = __toESM(require("react"));
|
|
127
|
+
function createReplaceableLocation() {
|
|
128
|
+
const injections = /* @__PURE__ */ new Map();
|
|
129
|
+
const getInjections = createGetInjections(injections);
|
|
130
|
+
const useInjections = createUseInjections(getInjections);
|
|
131
|
+
const Slot = createReplaceable(useInjections);
|
|
132
|
+
const inject = createRegister(injections);
|
|
133
|
+
flushInjectionsFns.push(() => injections.clear());
|
|
134
|
+
return {
|
|
135
|
+
getInjections,
|
|
136
|
+
useInjections,
|
|
137
|
+
inject,
|
|
138
|
+
Slot
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function createReplaceable(useInjections) {
|
|
142
|
+
return (props) => {
|
|
143
|
+
const injections = useInjections();
|
|
144
|
+
const { component: Component2 } = injections.find(({ condition }) => condition?.(props)) ?? {};
|
|
145
|
+
if (!Component2) {
|
|
146
|
+
return props.children;
|
|
147
|
+
}
|
|
148
|
+
return /* @__PURE__ */ React4.createElement(Component2, { ...props });
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function createRegister(injections) {
|
|
152
|
+
return ({ component, id, condition = () => true, options = {} }) => {
|
|
153
|
+
injections.set(id, {
|
|
154
|
+
id,
|
|
155
|
+
component: wrapInjectedComponent(component),
|
|
156
|
+
condition,
|
|
157
|
+
priority: options.priority ?? DEFAULT_PRIORITY
|
|
158
|
+
});
|
|
159
|
+
};
|
|
117
160
|
}
|
|
118
161
|
// Annotate the CommonJS export names for ESM import in node:
|
|
119
162
|
0 && (module.exports = {
|
|
120
163
|
__flushAllInjections,
|
|
121
|
-
createLocation
|
|
164
|
+
createLocation,
|
|
165
|
+
createReplaceableLocation
|
|
122
166
|
});
|
|
123
167
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create-location.tsx","../src/injections.tsx","../src/components/injected-component-wrapper.tsx","../src/components/error-boundary.tsx","../src/create-replaceable-location.tsx"],"sourcesContent":["export * from './types';\n\nexport { createLocation } from './create-location';\nexport { createReplaceableLocation } from './create-replaceable-location';\nexport { flushAllInjections as __flushAllInjections } from './injections';\n","import * as React from 'react';\n\nimport {\n\tcreateGetInjections,\n\tcreateUseInjections,\n\tDEFAULT_PRIORITY,\n\tflushInjectionsFns,\n\twrapInjectedComponent,\n} from './injections';\nimport { type AnyProps, type Id, type InjectArgs, type Injection, type Location } from './types';\n\ntype InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;\n\nexport function createLocation< TProps extends object = AnyProps >(): Location< TProps > {\n\tconst injections: InjectionsMap< TProps > = new Map();\n\n\tconst getInjections = createGetInjections( injections );\n\tconst useInjections = createUseInjections( getInjections );\n\tconst Slot = createSlot( useInjections );\n\tconst inject = createInject( injections );\n\n\t// Push the clear function to the flushInjectionsFns array, so we can flush all injections at once.\n\tflushInjectionsFns.push( () => injections.clear() );\n\n\treturn {\n\t\tinject,\n\t\tgetInjections,\n\t\tuseInjections,\n\t\tSlot,\n\t};\n}\n\nfunction createSlot< TProps extends object = AnyProps >( useInjections: Location< TProps >[ 'useInjections' ] ) {\n\treturn ( props: TProps ) => {\n\t\tconst injections = useInjections();\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{ injections.map( ( { id, component: Component } ) => (\n\t\t\t\t\t<Component { ...props } key={ id } />\n\t\t\t\t) ) }\n\t\t\t</>\n\t\t);\n\t};\n}\n\nfunction createInject< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {\n\treturn ( { component, id, options = {} }: InjectArgs< TProps > ) => {\n\t\tif ( injections.has( id ) && ! options?.overwrite ) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(\n\t\t\t\t`An injection with the id \"${ id }\" already exists. Did you mean to use \"options.overwrite\"?`\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tinjections.set( id, {\n\t\t\tid,\n\t\t\tcomponent: wrapInjectedComponent( component ),\n\t\t\tpriority: options.priority ?? DEFAULT_PRIORITY,\n\t\t} );\n\t};\n}\n","import * as React from 'react';\nimport { useMemo } from 'react';\n\nimport InjectedComponentWrapper from './components/injected-component-wrapper';\nimport { type AnyProps, type Id, type InjectedComponent, type Injection, type Location } from './types';\n\ntype InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;\n\nexport const DEFAULT_PRIORITY = 10;\n\n// Allow flushing all injections at once, for testing purposes.\nexport const flushInjectionsFns: ( () => void )[] = [];\n\nexport function flushAllInjections() {\n\tflushInjectionsFns.forEach( ( flush ) => flush() );\n}\n\nexport function createGetInjections< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {\n\treturn () => [ ...injections.values() ].sort( ( a, b ) => a.priority - b.priority );\n}\n\nexport function createUseInjections< TProps extends object = AnyProps >(\n\tgetInjections: Location< TProps >[ 'getInjections' ]\n) {\n\treturn () => useMemo( () => getInjections(), [] );\n}\n\nexport function wrapInjectedComponent< TProps extends object = AnyProps >( Component: InjectedComponent< TProps > ) {\n\treturn ( props: TProps ) => (\n\t\t<InjectedComponentWrapper>\n\t\t\t<Component { ...props } />\n\t\t</InjectedComponentWrapper>\n\t);\n}\n","import * as React from 'react';\nimport { type ReactNode, Suspense } from 'react';\n\nimport ErrorBoundary from './error-boundary';\n\nexport default function InjectedComponentWrapper( { children }: { children: ReactNode } ) {\n\treturn (\n\t\t<ErrorBoundary fallback={ null }>\n\t\t\t<Suspense fallback={ null }>{ children }</Suspense>\n\t\t</ErrorBoundary>\n\t);\n}\n","import { Component, type ReactNode } from 'react';\n\ninterface Props {\n\tchildren?: ReactNode;\n\tfallback: ReactNode;\n}\n\ninterface State {\n\thasError: boolean;\n}\n\nexport default class ErrorBoundary extends Component< Props, State > {\n\tpublic state: State = {\n\t\thasError: false,\n\t};\n\n\tpublic static getDerivedStateFromError(): State {\n\t\t// Update state so the next render will show the fallback UI.\n\t\treturn { hasError: true };\n\t}\n\n\tpublic render() {\n\t\tif ( this.state.hasError ) {\n\t\t\treturn this.props.fallback;\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n","import * as React from 'react';\nimport { type PropsWithChildren } from 'react';\n\nimport {\n\tcreateGetInjections,\n\tcreateUseInjections,\n\tDEFAULT_PRIORITY,\n\tflushInjectionsFns,\n\twrapInjectedComponent,\n} from './injections';\nimport {\n\ttype AnyProps,\n\ttype Id,\n\ttype ReplaceableInjectArgs,\n\ttype ReplaceableInjection,\n\ttype ReplaceableLocation,\n} from './types';\n\ntype ReplaceableInjectionsMap< TProps extends object = AnyProps > = Map< Id, ReplaceableInjection< TProps > >;\n\nexport function createReplaceableLocation< TProps extends object = AnyProps >(): ReplaceableLocation< TProps > {\n\tconst injections: ReplaceableInjectionsMap< TProps > = new Map();\n\n\tconst getInjections = createGetInjections( injections );\n\tconst useInjections = createUseInjections( getInjections );\n\tconst Slot = createReplaceable( useInjections );\n\tconst inject = createRegister( injections );\n\n\t// Push the clear function to the flushInjectionsFns array, so we can flush all injections at once.\n\tflushInjectionsFns.push( () => injections.clear() );\n\n\treturn {\n\t\tgetInjections,\n\t\tuseInjections,\n\t\tinject,\n\t\tSlot,\n\t};\n}\n\nfunction createReplaceable< TProps extends PropsWithChildren< object > = AnyProps >(\n\tuseInjections: ReplaceableLocation< TProps >[ 'useInjections' ]\n) {\n\treturn ( props: TProps ) => {\n\t\tconst injections = useInjections();\n\n\t\tconst { component: Component } = injections.find( ( { condition } ) => condition?.( props ) ) ?? {};\n\n\t\tif ( ! Component ) {\n\t\t\treturn props.children;\n\t\t}\n\n\t\treturn <Component { ...props } />;\n\t};\n}\n\nfunction createRegister< TProps extends object = AnyProps >( injections: ReplaceableInjectionsMap< TProps > ) {\n\treturn ( { component, id, condition = () => true, options = {} }: ReplaceableInjectArgs< TProps > ) => {\n\t\tinjections.set( id, {\n\t\t\tid,\n\t\t\tcomponent: wrapInjectedComponent( component ),\n\t\t\tcondition,\n\t\t\tpriority: options.priority ?? DEFAULT_PRIORITY,\n\t\t} );\n\t};\n}\n"],"mappings":"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","names":["React","React","import_react","import_react","Component","Component","React","Component"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/create-location.tsx
|
|
2
|
+
import * as React3 from "react";
|
|
3
|
+
|
|
4
|
+
// src/injections.tsx
|
|
2
5
|
import * as React2 from "react";
|
|
6
|
+
import { useMemo } from "react";
|
|
3
7
|
|
|
4
8
|
// src/components/injected-component-wrapper.tsx
|
|
5
9
|
import * as React from "react";
|
|
@@ -27,10 +31,23 @@ function InjectedComponentWrapper({ children }) {
|
|
|
27
31
|
return /* @__PURE__ */ React.createElement(ErrorBoundary, { fallback: null }, /* @__PURE__ */ React.createElement(Suspense, { fallback: null }, children));
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
// src/
|
|
31
|
-
import { useMemo } from "react";
|
|
34
|
+
// src/injections.tsx
|
|
32
35
|
var DEFAULT_PRIORITY = 10;
|
|
33
36
|
var flushInjectionsFns = [];
|
|
37
|
+
function flushAllInjections() {
|
|
38
|
+
flushInjectionsFns.forEach((flush) => flush());
|
|
39
|
+
}
|
|
40
|
+
function createGetInjections(injections) {
|
|
41
|
+
return () => [...injections.values()].sort((a, b) => a.priority - b.priority);
|
|
42
|
+
}
|
|
43
|
+
function createUseInjections(getInjections) {
|
|
44
|
+
return () => useMemo(() => getInjections(), []);
|
|
45
|
+
}
|
|
46
|
+
function wrapInjectedComponent(Component2) {
|
|
47
|
+
return (props) => /* @__PURE__ */ React2.createElement(InjectedComponentWrapper, null, /* @__PURE__ */ React2.createElement(Component2, { ...props }));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/create-location.tsx
|
|
34
51
|
function createLocation() {
|
|
35
52
|
const injections = /* @__PURE__ */ new Map();
|
|
36
53
|
const getInjections = createGetInjections(injections);
|
|
@@ -45,21 +62,12 @@ function createLocation() {
|
|
|
45
62
|
Slot
|
|
46
63
|
};
|
|
47
64
|
}
|
|
48
|
-
function flushAllInjections() {
|
|
49
|
-
flushInjectionsFns.forEach((flush) => flush());
|
|
50
|
-
}
|
|
51
|
-
function wrapInjectedComponent(Component2) {
|
|
52
|
-
return (props) => /* @__PURE__ */ React2.createElement(InjectedComponentWrapper, null, /* @__PURE__ */ React2.createElement(Component2, { ...props }));
|
|
53
|
-
}
|
|
54
65
|
function createSlot(useInjections) {
|
|
55
66
|
return (props) => {
|
|
56
67
|
const injections = useInjections();
|
|
57
|
-
return /* @__PURE__ */
|
|
68
|
+
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, injections.map(({ id, component: Component2 }) => /* @__PURE__ */ React3.createElement(Component2, { ...props, key: id })));
|
|
58
69
|
};
|
|
59
70
|
}
|
|
60
|
-
function createGetInjections(injections) {
|
|
61
|
-
return () => [...injections.values()].sort((a, b) => a.priority - b.priority);
|
|
62
|
-
}
|
|
63
71
|
function createInject(injections) {
|
|
64
72
|
return ({ component, id, options = {} }) => {
|
|
65
73
|
if (injections.has(id) && !options?.overwrite) {
|
|
@@ -75,11 +83,46 @@ function createInject(injections) {
|
|
|
75
83
|
});
|
|
76
84
|
};
|
|
77
85
|
}
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
|
|
87
|
+
// src/create-replaceable-location.tsx
|
|
88
|
+
import * as React4 from "react";
|
|
89
|
+
function createReplaceableLocation() {
|
|
90
|
+
const injections = /* @__PURE__ */ new Map();
|
|
91
|
+
const getInjections = createGetInjections(injections);
|
|
92
|
+
const useInjections = createUseInjections(getInjections);
|
|
93
|
+
const Slot = createReplaceable(useInjections);
|
|
94
|
+
const inject = createRegister(injections);
|
|
95
|
+
flushInjectionsFns.push(() => injections.clear());
|
|
96
|
+
return {
|
|
97
|
+
getInjections,
|
|
98
|
+
useInjections,
|
|
99
|
+
inject,
|
|
100
|
+
Slot
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function createReplaceable(useInjections) {
|
|
104
|
+
return (props) => {
|
|
105
|
+
const injections = useInjections();
|
|
106
|
+
const { component: Component2 } = injections.find(({ condition }) => condition?.(props)) ?? {};
|
|
107
|
+
if (!Component2) {
|
|
108
|
+
return props.children;
|
|
109
|
+
}
|
|
110
|
+
return /* @__PURE__ */ React4.createElement(Component2, { ...props });
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function createRegister(injections) {
|
|
114
|
+
return ({ component, id, condition = () => true, options = {} }) => {
|
|
115
|
+
injections.set(id, {
|
|
116
|
+
id,
|
|
117
|
+
component: wrapInjectedComponent(component),
|
|
118
|
+
condition,
|
|
119
|
+
priority: options.priority ?? DEFAULT_PRIORITY
|
|
120
|
+
});
|
|
121
|
+
};
|
|
80
122
|
}
|
|
81
123
|
export {
|
|
82
124
|
flushAllInjections as __flushAllInjections,
|
|
83
|
-
createLocation
|
|
125
|
+
createLocation,
|
|
126
|
+
createReplaceableLocation
|
|
84
127
|
};
|
|
85
128
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/
|
|
1
|
+
{"version":3,"sources":["../src/create-location.tsx","../src/injections.tsx","../src/components/injected-component-wrapper.tsx","../src/components/error-boundary.tsx","../src/create-replaceable-location.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n\tcreateGetInjections,\n\tcreateUseInjections,\n\tDEFAULT_PRIORITY,\n\tflushInjectionsFns,\n\twrapInjectedComponent,\n} from './injections';\nimport { type AnyProps, type Id, type InjectArgs, type Injection, type Location } from './types';\n\ntype InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;\n\nexport function createLocation< TProps extends object = AnyProps >(): Location< TProps > {\n\tconst injections: InjectionsMap< TProps > = new Map();\n\n\tconst getInjections = createGetInjections( injections );\n\tconst useInjections = createUseInjections( getInjections );\n\tconst Slot = createSlot( useInjections );\n\tconst inject = createInject( injections );\n\n\t// Push the clear function to the flushInjectionsFns array, so we can flush all injections at once.\n\tflushInjectionsFns.push( () => injections.clear() );\n\n\treturn {\n\t\tinject,\n\t\tgetInjections,\n\t\tuseInjections,\n\t\tSlot,\n\t};\n}\n\nfunction createSlot< TProps extends object = AnyProps >( useInjections: Location< TProps >[ 'useInjections' ] ) {\n\treturn ( props: TProps ) => {\n\t\tconst injections = useInjections();\n\n\t\treturn (\n\t\t\t<>\n\t\t\t\t{ injections.map( ( { id, component: Component } ) => (\n\t\t\t\t\t<Component { ...props } key={ id } />\n\t\t\t\t) ) }\n\t\t\t</>\n\t\t);\n\t};\n}\n\nfunction createInject< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {\n\treturn ( { component, id, options = {} }: InjectArgs< TProps > ) => {\n\t\tif ( injections.has( id ) && ! options?.overwrite ) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(\n\t\t\t\t`An injection with the id \"${ id }\" already exists. Did you mean to use \"options.overwrite\"?`\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tinjections.set( id, {\n\t\t\tid,\n\t\t\tcomponent: wrapInjectedComponent( component ),\n\t\t\tpriority: options.priority ?? DEFAULT_PRIORITY,\n\t\t} );\n\t};\n}\n","import * as React from 'react';\nimport { useMemo } from 'react';\n\nimport InjectedComponentWrapper from './components/injected-component-wrapper';\nimport { type AnyProps, type Id, type InjectedComponent, type Injection, type Location } from './types';\n\ntype InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;\n\nexport const DEFAULT_PRIORITY = 10;\n\n// Allow flushing all injections at once, for testing purposes.\nexport const flushInjectionsFns: ( () => void )[] = [];\n\nexport function flushAllInjections() {\n\tflushInjectionsFns.forEach( ( flush ) => flush() );\n}\n\nexport function createGetInjections< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {\n\treturn () => [ ...injections.values() ].sort( ( a, b ) => a.priority - b.priority );\n}\n\nexport function createUseInjections< TProps extends object = AnyProps >(\n\tgetInjections: Location< TProps >[ 'getInjections' ]\n) {\n\treturn () => useMemo( () => getInjections(), [] );\n}\n\nexport function wrapInjectedComponent< TProps extends object = AnyProps >( Component: InjectedComponent< TProps > ) {\n\treturn ( props: TProps ) => (\n\t\t<InjectedComponentWrapper>\n\t\t\t<Component { ...props } />\n\t\t</InjectedComponentWrapper>\n\t);\n}\n","import * as React from 'react';\nimport { type ReactNode, Suspense } from 'react';\n\nimport ErrorBoundary from './error-boundary';\n\nexport default function InjectedComponentWrapper( { children }: { children: ReactNode } ) {\n\treturn (\n\t\t<ErrorBoundary fallback={ null }>\n\t\t\t<Suspense fallback={ null }>{ children }</Suspense>\n\t\t</ErrorBoundary>\n\t);\n}\n","import { Component, type ReactNode } from 'react';\n\ninterface Props {\n\tchildren?: ReactNode;\n\tfallback: ReactNode;\n}\n\ninterface State {\n\thasError: boolean;\n}\n\nexport default class ErrorBoundary extends Component< Props, State > {\n\tpublic state: State = {\n\t\thasError: false,\n\t};\n\n\tpublic static getDerivedStateFromError(): State {\n\t\t// Update state so the next render will show the fallback UI.\n\t\treturn { hasError: true };\n\t}\n\n\tpublic render() {\n\t\tif ( this.state.hasError ) {\n\t\t\treturn this.props.fallback;\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n","import * as React from 'react';\nimport { type PropsWithChildren } from 'react';\n\nimport {\n\tcreateGetInjections,\n\tcreateUseInjections,\n\tDEFAULT_PRIORITY,\n\tflushInjectionsFns,\n\twrapInjectedComponent,\n} from './injections';\nimport {\n\ttype AnyProps,\n\ttype Id,\n\ttype ReplaceableInjectArgs,\n\ttype ReplaceableInjection,\n\ttype ReplaceableLocation,\n} from './types';\n\ntype ReplaceableInjectionsMap< TProps extends object = AnyProps > = Map< Id, ReplaceableInjection< TProps > >;\n\nexport function createReplaceableLocation< TProps extends object = AnyProps >(): ReplaceableLocation< TProps > {\n\tconst injections: ReplaceableInjectionsMap< TProps > = new Map();\n\n\tconst getInjections = createGetInjections( injections );\n\tconst useInjections = createUseInjections( getInjections );\n\tconst Slot = createReplaceable( useInjections );\n\tconst inject = createRegister( injections );\n\n\t// Push the clear function to the flushInjectionsFns array, so we can flush all injections at once.\n\tflushInjectionsFns.push( () => injections.clear() );\n\n\treturn {\n\t\tgetInjections,\n\t\tuseInjections,\n\t\tinject,\n\t\tSlot,\n\t};\n}\n\nfunction createReplaceable< TProps extends PropsWithChildren< object > = AnyProps >(\n\tuseInjections: ReplaceableLocation< TProps >[ 'useInjections' ]\n) {\n\treturn ( props: TProps ) => {\n\t\tconst injections = useInjections();\n\n\t\tconst { component: Component } = injections.find( ( { condition } ) => condition?.( props ) ) ?? {};\n\n\t\tif ( ! Component ) {\n\t\t\treturn props.children;\n\t\t}\n\n\t\treturn <Component { ...props } />;\n\t};\n}\n\nfunction createRegister< TProps extends object = AnyProps >( injections: ReplaceableInjectionsMap< TProps > ) {\n\treturn ( { component, id, condition = () => true, options = {} }: ReplaceableInjectArgs< TProps > ) => {\n\t\tinjections.set( id, {\n\t\t\tid,\n\t\t\tcomponent: wrapInjectedComponent( component ),\n\t\t\tcondition,\n\t\t\tpriority: options.priority ?? DEFAULT_PRIORITY,\n\t\t} );\n\t};\n}\n"],"mappings":"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","names":["React","React","Component","Component","React","Component"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elementor/locations",
|
|
3
3
|
"description": "Create & manage pluggable React applications",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Elementor Team",
|
|
7
7
|
"homepage": "https://elementor.com/",
|
|
@@ -41,5 +41,8 @@
|
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"react": "^18.3.1"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"tsup": "^8.3.5"
|
|
44
47
|
}
|
|
45
48
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ReactNode, Suspense } from 'react';
|
|
2
|
+
import { type ReactNode, Suspense } from 'react';
|
|
3
|
+
|
|
3
4
|
import ErrorBoundary from './error-boundary';
|
|
4
5
|
|
|
5
6
|
export default function InjectedComponentWrapper( { children }: { children: ReactNode } ) {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { InjectedComponent, Injection, InjectArgs, AnyProps, Location, Id } from './types';
|
|
3
|
-
import InjectedComponentWrapper from './components/injected-component-wrapper';
|
|
4
|
-
import { useMemo } from 'react';
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
import {
|
|
4
|
+
createGetInjections,
|
|
5
|
+
createUseInjections,
|
|
6
|
+
DEFAULT_PRIORITY,
|
|
7
|
+
flushInjectionsFns,
|
|
8
|
+
wrapInjectedComponent,
|
|
9
|
+
} from './injections';
|
|
10
|
+
import { type AnyProps, type Id, type InjectArgs, type Injection, type Location } from './types';
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
const flushInjectionsFns: ( () => void )[] = [];
|
|
12
|
+
type InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;
|
|
12
13
|
|
|
13
14
|
export function createLocation< TProps extends object = AnyProps >(): Location< TProps > {
|
|
14
15
|
const injections: InjectionsMap< TProps > = new Map();
|
|
@@ -29,18 +30,6 @@ export function createLocation< TProps extends object = AnyProps >(): Location<
|
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
export function flushAllInjections() {
|
|
33
|
-
flushInjectionsFns.forEach( ( flush ) => flush() );
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function wrapInjectedComponent< TProps extends object = AnyProps >( Component: InjectedComponent< TProps > ) {
|
|
37
|
-
return ( props: TProps ) => (
|
|
38
|
-
<InjectedComponentWrapper>
|
|
39
|
-
<Component { ...props } />
|
|
40
|
-
</InjectedComponentWrapper>
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
33
|
function createSlot< TProps extends object = AnyProps >( useInjections: Location< TProps >[ 'useInjections' ] ) {
|
|
45
34
|
return ( props: TProps ) => {
|
|
46
35
|
const injections = useInjections();
|
|
@@ -55,10 +44,6 @@ function createSlot< TProps extends object = AnyProps >( useInjections: Location
|
|
|
55
44
|
};
|
|
56
45
|
}
|
|
57
46
|
|
|
58
|
-
function createGetInjections< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {
|
|
59
|
-
return () => [ ...injections.values() ].sort( ( a, b ) => a.priority - b.priority );
|
|
60
|
-
}
|
|
61
|
-
|
|
62
47
|
function createInject< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {
|
|
63
48
|
return ( { component, id, options = {} }: InjectArgs< TProps > ) => {
|
|
64
49
|
if ( injections.has( id ) && ! options?.overwrite ) {
|
|
@@ -77,9 +62,3 @@ function createInject< TProps extends object = AnyProps >( injections: Injection
|
|
|
77
62
|
} );
|
|
78
63
|
};
|
|
79
64
|
}
|
|
80
|
-
|
|
81
|
-
function createUseInjections< TProps extends object = AnyProps >(
|
|
82
|
-
getInjections: Location< TProps >[ 'getInjections' ]
|
|
83
|
-
) {
|
|
84
|
-
return () => useMemo( () => getInjections(), [] );
|
|
85
|
-
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PropsWithChildren } from 'react';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
createGetInjections,
|
|
6
|
+
createUseInjections,
|
|
7
|
+
DEFAULT_PRIORITY,
|
|
8
|
+
flushInjectionsFns,
|
|
9
|
+
wrapInjectedComponent,
|
|
10
|
+
} from './injections';
|
|
11
|
+
import {
|
|
12
|
+
type AnyProps,
|
|
13
|
+
type Id,
|
|
14
|
+
type ReplaceableInjectArgs,
|
|
15
|
+
type ReplaceableInjection,
|
|
16
|
+
type ReplaceableLocation,
|
|
17
|
+
} from './types';
|
|
18
|
+
|
|
19
|
+
type ReplaceableInjectionsMap< TProps extends object = AnyProps > = Map< Id, ReplaceableInjection< TProps > >;
|
|
20
|
+
|
|
21
|
+
export function createReplaceableLocation< TProps extends object = AnyProps >(): ReplaceableLocation< TProps > {
|
|
22
|
+
const injections: ReplaceableInjectionsMap< TProps > = new Map();
|
|
23
|
+
|
|
24
|
+
const getInjections = createGetInjections( injections );
|
|
25
|
+
const useInjections = createUseInjections( getInjections );
|
|
26
|
+
const Slot = createReplaceable( useInjections );
|
|
27
|
+
const inject = createRegister( injections );
|
|
28
|
+
|
|
29
|
+
// Push the clear function to the flushInjectionsFns array, so we can flush all injections at once.
|
|
30
|
+
flushInjectionsFns.push( () => injections.clear() );
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
getInjections,
|
|
34
|
+
useInjections,
|
|
35
|
+
inject,
|
|
36
|
+
Slot,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createReplaceable< TProps extends PropsWithChildren< object > = AnyProps >(
|
|
41
|
+
useInjections: ReplaceableLocation< TProps >[ 'useInjections' ]
|
|
42
|
+
) {
|
|
43
|
+
return ( props: TProps ) => {
|
|
44
|
+
const injections = useInjections();
|
|
45
|
+
|
|
46
|
+
const { component: Component } = injections.find( ( { condition } ) => condition?.( props ) ) ?? {};
|
|
47
|
+
|
|
48
|
+
if ( ! Component ) {
|
|
49
|
+
return props.children;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return <Component { ...props } />;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createRegister< TProps extends object = AnyProps >( injections: ReplaceableInjectionsMap< TProps > ) {
|
|
57
|
+
return ( { component, id, condition = () => true, options = {} }: ReplaceableInjectArgs< TProps > ) => {
|
|
58
|
+
injections.set( id, {
|
|
59
|
+
id,
|
|
60
|
+
component: wrapInjectedComponent( component ),
|
|
61
|
+
condition,
|
|
62
|
+
priority: options.priority ?? DEFAULT_PRIORITY,
|
|
63
|
+
} );
|
|
64
|
+
};
|
|
65
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export * from './types';
|
|
2
2
|
|
|
3
|
-
export { createLocation
|
|
3
|
+
export { createLocation } from './create-location';
|
|
4
|
+
export { createReplaceableLocation } from './create-replaceable-location';
|
|
5
|
+
export { flushAllInjections as __flushAllInjections } from './injections';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
import InjectedComponentWrapper from './components/injected-component-wrapper';
|
|
5
|
+
import { type AnyProps, type Id, type InjectedComponent, type Injection, type Location } from './types';
|
|
6
|
+
|
|
7
|
+
type InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;
|
|
8
|
+
|
|
9
|
+
export const DEFAULT_PRIORITY = 10;
|
|
10
|
+
|
|
11
|
+
// Allow flushing all injections at once, for testing purposes.
|
|
12
|
+
export const flushInjectionsFns: ( () => void )[] = [];
|
|
13
|
+
|
|
14
|
+
export function flushAllInjections() {
|
|
15
|
+
flushInjectionsFns.forEach( ( flush ) => flush() );
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function createGetInjections< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {
|
|
19
|
+
return () => [ ...injections.values() ].sort( ( a, b ) => a.priority - b.priority );
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createUseInjections< TProps extends object = AnyProps >(
|
|
23
|
+
getInjections: Location< TProps >[ 'getInjections' ]
|
|
24
|
+
) {
|
|
25
|
+
return () => useMemo( () => getInjections(), [] );
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function wrapInjectedComponent< TProps extends object = AnyProps >( Component: InjectedComponent< TProps > ) {
|
|
29
|
+
return ( props: TProps ) => (
|
|
30
|
+
<InjectedComponentWrapper>
|
|
31
|
+
<Component { ...props } />
|
|
32
|
+
</InjectedComponentWrapper>
|
|
33
|
+
);
|
|
34
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType } from 'react';
|
|
1
|
+
import { type ComponentType, type PropsWithChildren } from 'react';
|
|
2
2
|
|
|
3
3
|
// Allow passing the `key` prop even when there are no props for the component
|
|
4
4
|
export type AnyProps = object;
|
|
@@ -22,6 +22,13 @@ export type Injection< TProps extends object = AnyProps > = {
|
|
|
22
22
|
priority: Priority;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
export type ReplaceableInjection< TProps extends object = AnyProps > = Injection< TProps > & {
|
|
26
|
+
/**
|
|
27
|
+
* A function that returns a boolean indicating whether the injection should be applied or not.
|
|
28
|
+
*/
|
|
29
|
+
condition?: ( props: TProps ) => boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
25
32
|
export type InjectArgs< TProps extends object = AnyProps > = {
|
|
26
33
|
/**
|
|
27
34
|
* A unique id (per location) of the component to be injected.
|
|
@@ -44,6 +51,23 @@ export type InjectArgs< TProps extends object = AnyProps > = {
|
|
|
44
51
|
};
|
|
45
52
|
};
|
|
46
53
|
|
|
54
|
+
export type ReplaceableInjectArgs< TProps extends object = AnyProps > = Pick<
|
|
55
|
+
InjectArgs< TProps >,
|
|
56
|
+
'id' | 'component'
|
|
57
|
+
> & {
|
|
58
|
+
/**
|
|
59
|
+
* A function that returns a boolean indicating whether the injection should be applied or not.
|
|
60
|
+
*/
|
|
61
|
+
condition?: ( props: TProps ) => boolean;
|
|
62
|
+
|
|
63
|
+
options?: {
|
|
64
|
+
/**
|
|
65
|
+
* Priority of the injected component inside the location. Lower value means higher priority.
|
|
66
|
+
*/
|
|
67
|
+
priority?: Priority;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
47
71
|
export type Location< TProps extends object = AnyProps > = {
|
|
48
72
|
/**
|
|
49
73
|
* Inject a component into the location.
|
|
@@ -57,3 +81,17 @@ export type Location< TProps extends object = AnyProps > = {
|
|
|
57
81
|
useInjections: () => Injection< TProps >[];
|
|
58
82
|
Slot: ComponentType< TProps >;
|
|
59
83
|
};
|
|
84
|
+
|
|
85
|
+
export type ReplaceableLocation< TProps extends object = AnyProps > = {
|
|
86
|
+
/**
|
|
87
|
+
* Register a component into the location.
|
|
88
|
+
*/
|
|
89
|
+
inject: ( args: ReplaceableInjectArgs< TProps > ) => void;
|
|
90
|
+
/**
|
|
91
|
+
*
|
|
92
|
+
* @return All the injections in the location.
|
|
93
|
+
*/
|
|
94
|
+
getInjections: () => ReplaceableInjection< TProps >[];
|
|
95
|
+
useInjections: () => ReplaceableInjection< TProps >[];
|
|
96
|
+
Slot: ComponentType< PropsWithChildren< TProps > >;
|
|
97
|
+
};
|