@openmrs/esm-react-utils 4.0.1-pre.214 → 4.0.1-pre.219

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-react-utils",
3
- "version": "4.0.1-pre.214",
3
+ "version": "4.0.1-pre.219",
4
4
  "license": "MPL-2.0",
5
5
  "description": "React utilities for OpenMRS.",
6
6
  "browser": "dist/openmrs-esm-react-utils.js",
@@ -55,11 +55,11 @@
55
55
  "react-i18next": "11.x"
56
56
  },
57
57
  "devDependencies": {
58
- "@openmrs/esm-api": "^4.0.1-pre.214",
59
- "@openmrs/esm-config": "^4.0.1-pre.214",
60
- "@openmrs/esm-error-handling": "^4.0.1-pre.214",
61
- "@openmrs/esm-extensions": "^4.0.1-pre.214",
62
- "@openmrs/esm-globals": "^4.0.1-pre.214",
58
+ "@openmrs/esm-api": "^4.0.1-pre.219",
59
+ "@openmrs/esm-config": "^4.0.1-pre.219",
60
+ "@openmrs/esm-error-handling": "^4.0.1-pre.219",
61
+ "@openmrs/esm-extensions": "^4.0.1-pre.219",
62
+ "@openmrs/esm-globals": "^4.0.1-pre.219",
63
63
  "dayjs": "^1.10.8",
64
64
  "i18next": "^19.6.0",
65
65
  "react": "^18.1.0",
@@ -68,5 +68,5 @@
68
68
  "rxjs": "^6.5.3",
69
69
  "unistore": "^3.5.2"
70
70
  },
71
- "gitHead": "0096329ba29b288471a77451224337bb052d050e"
71
+ "gitHead": "e4225fe2ac3947ab26751d4b618bf3aafe9059e2"
72
72
  }
@@ -1,5 +1,9 @@
1
1
  /** @module @category Navigation */
2
- import React, { MouseEvent, AnchorHTMLAttributes } from "react";
2
+ import React, {
3
+ MouseEvent,
4
+ AnchorHTMLAttributes,
5
+ PropsWithChildren,
6
+ } from "react";
3
7
  import { navigate, interpolateUrl, TemplateParams } from "@openmrs/esm-config";
4
8
 
5
9
  function handleClick(
@@ -40,7 +44,7 @@ export function ConfigurableLink({
40
44
  templateParams,
41
45
  children,
42
46
  ...otherProps
43
- }: ConfigurableLinkProps) {
47
+ }: PropsWithChildren<ConfigurableLinkProps>) {
44
48
  return (
45
49
  <a
46
50
  onClick={(event) => handleClick(event, to, templateParams)}
package/src/Extension.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import { renderExtension } from "@openmrs/esm-extensions";
2
2
  import React, {
3
+ PropsWithChildren,
3
4
  useCallback,
4
5
  useContext,
5
6
  useEffect,
@@ -10,14 +11,18 @@ import { Parcel } from "single-spa";
10
11
  import { ComponentContext } from ".";
11
12
  import { ExtensionData } from "./ComponentContext";
12
13
 
13
- export interface ExtensionProps {
14
+ export type ExtensionProps = {
14
15
  state?: Record<string, any>;
15
16
  /** @deprecated Pass a function as the child of `ExtensionSlot` instead. */
16
17
  wrap?(
17
18
  slot: React.ReactNode,
18
19
  extension: ExtensionData
19
20
  ): React.ReactElement<any, any> | null;
20
- }
21
+ } & Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
22
+ children?:
23
+ | React.ReactNode
24
+ | ((extension: React.ReactNode) => React.ReactNode);
25
+ };
21
26
 
22
27
  /**
23
28
  * Represents the position in the DOM where each extension within
@@ -28,21 +33,37 @@ export interface ExtensionProps {
28
33
  * Usage of this component *must* have an ancestor `<ExtensionSlot>`,
29
34
  * and *must* only be used once within that `<ExtensionSlot>`.
30
35
  */
31
- export const Extension: React.FC<ExtensionProps> = ({ state, wrap }) => {
36
+ export const Extension: React.FC<ExtensionProps> = ({
37
+ state,
38
+ children,
39
+ wrap,
40
+ ...divProps
41
+ }) => {
32
42
  const [domElement, setDomElement] = useState<HTMLDivElement>();
33
43
  const { extension } = useContext(ComponentContext);
34
44
  const parcel = useRef<Parcel | null>();
35
45
 
36
- if (wrap) {
37
- console.warn(
38
- "`wrap` prop of Extension is being used. This will be removed in a future release."
39
- );
40
- }
41
-
42
- const ref = useCallback((node) => {
43
- setDomElement(node);
46
+ useEffect(() => {
47
+ if (wrap) {
48
+ console.warn(
49
+ `'wrap' prop of Extension is being used ${
50
+ extension?.extensionId
51
+ ? `by ${extension.extensionId} in ${extension.extensionSlotName}`
52
+ : ""
53
+ }. This will be removed in a future release.`
54
+ );
55
+ }
56
+ // we only warn when component mounts
57
+ // eslint-disable-next-line eslintreact-hooks/exhaustive-deps
44
58
  }, []);
45
59
 
60
+ const ref = useCallback(
61
+ (node) => {
62
+ setDomElement(node);
63
+ },
64
+ [setDomElement]
65
+ );
66
+
46
67
  useEffect(() => {
47
68
  if (domElement != null && extension && !parcel.current) {
48
69
  parcel.current = renderExtension(
@@ -79,8 +100,13 @@ export const Extension: React.FC<ExtensionProps> = ({ state, wrap }) => {
79
100
  ref={ref}
80
101
  data-extension-id={extension?.extensionId}
81
102
  style={{ position: "relative" }}
103
+ {...divProps}
82
104
  />
83
105
  );
84
106
 
107
+ if (typeof children == "function" && !React.isValidElement(children)) {
108
+ return <>{children(slot)}</>;
109
+ }
110
+
85
111
  return extension && wrap ? wrap(slot, extension) : slot;
86
112
  };
@@ -254,6 +254,42 @@ describe("ExtensionSlot, Extension, and useExtensionSlotMeta", () => {
254
254
  within(screen.getByTestId("Hindi")).getByRole("heading")
255
255
  ).toHaveTextContent("hi");
256
256
  });
257
+
258
+ test("Extension renders with child function", async () => {
259
+ registerSimpleExtension("Hindi", "esm-languages-app", undefined, {
260
+ code: "hi",
261
+ });
262
+ attach("Box", "Hindi");
263
+ const App = openmrsComponentDecorator({
264
+ moduleName: "esm-languages-app",
265
+ featureName: "Languages",
266
+ disableTranslations: true,
267
+ })(() => {
268
+ return (
269
+ <div>
270
+ <ExtensionSlot name="Box">
271
+ {() => (
272
+ <Extension>
273
+ {(slot) => <div data-testid="custom-wrapper">{slot}</div>}
274
+ </Extension>
275
+ )}
276
+ </ExtensionSlot>
277
+ </div>
278
+ );
279
+ });
280
+
281
+ render(<App />);
282
+
283
+ await waitFor(() =>
284
+ expect(screen.getByTestId("custom-wrapper")).toBeInTheDocument()
285
+ );
286
+
287
+ // essentially: is the first child of custom-wrapper the extension?
288
+ expect(screen.getByTestId("custom-wrapper").children[0]).toHaveAttribute(
289
+ "data-extension-id",
290
+ "Hindi"
291
+ );
292
+ });
257
293
  });
258
294
 
259
295
  function registerSimpleExtension(