@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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d05046f: Add replaceable location
8
+
9
+ ## 0.7.7
10
+
11
+ ### Patch Changes
12
+
13
+ - 3e108d9: update elementor/ui
14
+
3
15
  ## 0.7.6
4
16
 
5
17
  ### Patch Changes
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 src_exports = {};
32
- __export(src_exports, {
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(src_exports);
37
+ module.exports = __toCommonJS(index_exports);
37
38
 
38
- // src/api.tsx
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/api.tsx
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__ */ React2.createElement(React2.Fragment, null, injections.map(({ id, component: Component2 }) => /* @__PURE__ */ React2.createElement(Component2, { ...props, key: id })));
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
- function createUseInjections(getInjections) {
116
- return () => (0, import_react3.useMemo)(() => getInjections(), []);
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/api.tsx","../src/components/injected-component-wrapper.tsx","../src/components/error-boundary.tsx"],"sourcesContent":["export * from './types';\n\nexport { createLocation, flushAllInjections as __flushAllInjections } from './api';\n","import * as React from 'react';\nimport { InjectedComponent, Injection, InjectArgs, AnyProps, Location, Id } from './types';\nimport InjectedComponentWrapper from './components/injected-component-wrapper';\nimport { useMemo } from 'react';\n\ntype InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;\n\nconst DEFAULT_PRIORITY = 10;\n\n// Allow flushing all injections at once, for testing purposes.\nconst flushInjectionsFns: ( () => void )[] = [];\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\nexport function flushAllInjections() {\n\tflushInjectionsFns.forEach( ( flush ) => flush() );\n}\n\nfunction 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\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 createGetInjections< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {\n\treturn () => [ ...injections.values() ].sort( ( a, b ) => a.priority - b.priority );\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\nfunction createUseInjections< TProps extends object = AnyProps >(\n\tgetInjections: Location< TProps >[ 'getInjections' ]\n) {\n\treturn () => useMemo( () => getInjections(), [] );\n}\n","import * as React from 'react';\nimport { ReactNode, Suspense } from 'react';\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, 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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,SAAuB;;;ACAvB,YAAuB;AACvB,IAAAC,gBAAoC;;;ACDpC,mBAAqC;AAWrC,IAAqB,gBAArB,cAA2C,uBAA0B;AAAA,EAC7D,QAAe;AAAA,IACrB,UAAU;AAAA,EACX;AAAA,EAEA,OAAc,2BAAkC;AAE/C,WAAO,EAAE,UAAU,KAAK;AAAA,EACzB;AAAA,EAEO,SAAS;AACf,QAAK,KAAK,MAAM,UAAW;AAC1B,aAAO,KAAK,MAAM;AAAA,IACnB;AAEA,WAAO,KAAK,MAAM;AAAA,EACnB;AACD;;;ADxBe,SAAR,yBAA2C,EAAE,SAAS,GAA6B;AACzF,SACC,oCAAC,iBAAc,UAAW,QACzB,oCAAC,0BAAS,UAAW,QAAS,QAAU,CACzC;AAEF;;;ADPA,IAAAC,gBAAwB;AAIxB,IAAM,mBAAmB;AAGzB,IAAM,qBAAuC,CAAC;AAEvC,SAAS,iBAAyE;AACxF,QAAM,aAAsC,oBAAI,IAAI;AAEpD,QAAM,gBAAgB,oBAAqB,UAAW;AACtD,QAAM,gBAAgB,oBAAqB,aAAc;AACzD,QAAM,OAAO,WAAY,aAAc;AACvC,QAAM,SAAS,aAAc,UAAW;AAGxC,qBAAmB,KAAM,MAAM,WAAW,MAAM,CAAE;AAElD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAEO,SAAS,qBAAqB;AACpC,qBAAmB,QAAS,CAAE,UAAW,MAAM,CAAE;AAClD;AAEA,SAAS,sBAA2DC,YAAyC;AAC5G,SAAO,CAAE,UACR,qCAAC,gCACA,qCAACA,YAAA,EAAY,GAAG,OAAQ,CACzB;AAEF;AAEA,SAAS,WAAgD,eAAuD;AAC/G,SAAO,CAAE,UAAmB;AAC3B,UAAM,aAAa,cAAc;AAEjC,WACC,4DACG,WAAW,IAAK,CAAE,EAAE,IAAI,WAAWA,WAAU,MAC9C,qCAACA,YAAA,EAAY,GAAG,OAAQ,KAAM,IAAK,CAClC,CACH;AAAA,EAEF;AACD;AAEA,SAAS,oBAAyD,YAAsC;AACvG,SAAO,MAAM,CAAE,GAAG,WAAW,OAAO,CAAE,EAAE,KAAM,CAAE,GAAG,MAAO,EAAE,WAAW,EAAE,QAAS;AACnF;AAEA,SAAS,aAAkD,YAAsC;AAChG,SAAO,CAAE,EAAE,WAAW,IAAI,UAAU,CAAC,EAAE,MAA6B;AACnE,QAAK,WAAW,IAAK,EAAG,KAAK,CAAE,SAAS,WAAY;AAEnD,cAAQ;AAAA,QACP,6BAA8B,EAAG;AAAA,MAClC;AAEA;AAAA,IACD;AAEA,eAAW,IAAK,IAAI;AAAA,MACnB;AAAA,MACA,WAAW,sBAAuB,SAAU;AAAA,MAC5C,UAAU,QAAQ,YAAY;AAAA,IAC/B,CAAE;AAAA,EACH;AACD;AAEA,SAAS,oBACR,eACC;AACD,SAAO,UAAM,uBAAS,MAAM,cAAc,GAAG,CAAC,CAAE;AACjD;","names":["React","import_react","import_react","Component"]}
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/api.tsx
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/api.tsx
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__ */ React2.createElement(React2.Fragment, null, injections.map(({ id, component: Component2 }) => /* @__PURE__ */ React2.createElement(Component2, { ...props, key: id })));
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
- function createUseInjections(getInjections) {
79
- return () => useMemo(() => getInjections(), []);
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
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api.tsx","../src/components/injected-component-wrapper.tsx","../src/components/error-boundary.tsx"],"sourcesContent":["import * as React from 'react';\nimport { InjectedComponent, Injection, InjectArgs, AnyProps, Location, Id } from './types';\nimport InjectedComponentWrapper from './components/injected-component-wrapper';\nimport { useMemo } from 'react';\n\ntype InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;\n\nconst DEFAULT_PRIORITY = 10;\n\n// Allow flushing all injections at once, for testing purposes.\nconst flushInjectionsFns: ( () => void )[] = [];\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\nexport function flushAllInjections() {\n\tflushInjectionsFns.forEach( ( flush ) => flush() );\n}\n\nfunction 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\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 createGetInjections< TProps extends object = AnyProps >( injections: InjectionsMap< TProps > ) {\n\treturn () => [ ...injections.values() ].sort( ( a, b ) => a.priority - b.priority );\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\nfunction createUseInjections< TProps extends object = AnyProps >(\n\tgetInjections: Location< TProps >[ 'getInjections' ]\n) {\n\treturn () => useMemo( () => getInjections(), [] );\n}\n","import * as React from 'react';\nimport { ReactNode, Suspense } from 'react';\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, 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"],"mappings":";AAAA,YAAYA,YAAW;;;ACAvB,YAAY,WAAW;AACvB,SAAoB,gBAAgB;;;ACDpC,SAAS,iBAA4B;AAWrC,IAAqB,gBAArB,cAA2C,UAA0B;AAAA,EAC7D,QAAe;AAAA,IACrB,UAAU;AAAA,EACX;AAAA,EAEA,OAAc,2BAAkC;AAE/C,WAAO,EAAE,UAAU,KAAK;AAAA,EACzB;AAAA,EAEO,SAAS;AACf,QAAK,KAAK,MAAM,UAAW;AAC1B,aAAO,KAAK,MAAM;AAAA,IACnB;AAEA,WAAO,KAAK,MAAM;AAAA,EACnB;AACD;;;ADxBe,SAAR,yBAA2C,EAAE,SAAS,GAA6B;AACzF,SACC,oCAAC,iBAAc,UAAW,QACzB,oCAAC,YAAS,UAAW,QAAS,QAAU,CACzC;AAEF;;;ADPA,SAAS,eAAe;AAIxB,IAAM,mBAAmB;AAGzB,IAAM,qBAAuC,CAAC;AAEvC,SAAS,iBAAyE;AACxF,QAAM,aAAsC,oBAAI,IAAI;AAEpD,QAAM,gBAAgB,oBAAqB,UAAW;AACtD,QAAM,gBAAgB,oBAAqB,aAAc;AACzD,QAAM,OAAO,WAAY,aAAc;AACvC,QAAM,SAAS,aAAc,UAAW;AAGxC,qBAAmB,KAAM,MAAM,WAAW,MAAM,CAAE;AAElD,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAEO,SAAS,qBAAqB;AACpC,qBAAmB,QAAS,CAAE,UAAW,MAAM,CAAE;AAClD;AAEA,SAAS,sBAA2DC,YAAyC;AAC5G,SAAO,CAAE,UACR,qCAAC,gCACA,qCAACA,YAAA,EAAY,GAAG,OAAQ,CACzB;AAEF;AAEA,SAAS,WAAgD,eAAuD;AAC/G,SAAO,CAAE,UAAmB;AAC3B,UAAM,aAAa,cAAc;AAEjC,WACC,4DACG,WAAW,IAAK,CAAE,EAAE,IAAI,WAAWA,WAAU,MAC9C,qCAACA,YAAA,EAAY,GAAG,OAAQ,KAAM,IAAK,CAClC,CACH;AAAA,EAEF;AACD;AAEA,SAAS,oBAAyD,YAAsC;AACvG,SAAO,MAAM,CAAE,GAAG,WAAW,OAAO,CAAE,EAAE,KAAM,CAAE,GAAG,MAAO,EAAE,WAAW,EAAE,QAAS;AACnF;AAEA,SAAS,aAAkD,YAAsC;AAChG,SAAO,CAAE,EAAE,WAAW,IAAI,UAAU,CAAC,EAAE,MAA6B;AACnE,QAAK,WAAW,IAAK,EAAG,KAAK,CAAE,SAAS,WAAY;AAEnD,cAAQ;AAAA,QACP,6BAA8B,EAAG;AAAA,MAClC;AAEA;AAAA,IACD;AAEA,eAAW,IAAK,IAAI;AAAA,MACnB;AAAA,MACA,WAAW,sBAAuB,SAAU;AAAA,MAC5C,UAAU,QAAQ,YAAY;AAAA,IAC/B,CAAE;AAAA,EACH;AACD;AAEA,SAAS,oBACR,eACC;AACD,SAAO,MAAM,QAAS,MAAM,cAAc,GAAG,CAAC,CAAE;AACjD;","names":["React","Component"]}
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.7.6",
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,4 +1,4 @@
1
- import { Component, ReactNode } from 'react';
1
+ import { Component, type ReactNode } from 'react';
2
2
 
3
3
  interface Props {
4
4
  children?: ReactNode;
@@ -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
- type InjectionsMap< TProps extends object = AnyProps > = Map< Id, Injection< TProps > >;
7
-
8
- const DEFAULT_PRIORITY = 10;
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
- // Allow flushing all injections at once, for testing purposes.
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, flushAllInjections as __flushAllInjections } from './api';
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
+ };