@openmrs/esm-react-utils 3.2.1-pre.967 → 3.2.1-pre.970

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": "3.2.1-pre.967",
3
+ "version": "3.2.1-pre.970",
4
4
  "license": "MPL-2.0",
5
5
  "description": "React utilities for OpenMRS.",
6
6
  "browser": "dist/openmrs-esm-react-utils.js",
@@ -53,11 +53,11 @@
53
53
  "react-i18next": "11.x"
54
54
  },
55
55
  "devDependencies": {
56
- "@openmrs/esm-api": "^3.2.1-pre.967",
57
- "@openmrs/esm-config": "^3.2.1-pre.967",
58
- "@openmrs/esm-error-handling": "^3.2.1-pre.967",
59
- "@openmrs/esm-extensions": "^3.2.1-pre.967",
60
- "@openmrs/esm-globals": "^3.2.1-pre.967",
56
+ "@openmrs/esm-api": "^3.2.1-pre.970",
57
+ "@openmrs/esm-config": "^3.2.1-pre.970",
58
+ "@openmrs/esm-error-handling": "^3.2.1-pre.970",
59
+ "@openmrs/esm-extensions": "^3.2.1-pre.970",
60
+ "@openmrs/esm-globals": "^3.2.1-pre.970",
61
61
  "i18next": "^19.6.0",
62
62
  "react": "^16.13.1",
63
63
  "react-dom": "^16.13.1",
@@ -65,5 +65,5 @@
65
65
  "rxjs": "^6.5.3",
66
66
  "unistore": "^3.5.2"
67
67
  },
68
- "gitHead": "5433fe8ad70b47ae8c9c6976d2f5bbf33e39d5ad"
68
+ "gitHead": "57dc1a5a7b655a60a431d88cd7991f2b9ab23ed9"
69
69
  }
package/src/Extension.tsx CHANGED
@@ -1,6 +1,7 @@
1
- import React from "react";
1
+ import { renderExtension } from "@openmrs/esm-extensions";
2
+ import React, { useCallback, useContext, useEffect, useState } from "react";
3
+ import { ComponentContext } from ".";
2
4
  import { ExtensionData } from "./ComponentContext";
3
- import { useExtension } from "./useExtension";
4
5
 
5
6
  export interface ExtensionProps {
6
7
  state?: Record<string, any>;
@@ -20,7 +21,31 @@ export interface ExtensionProps {
20
21
  * and *must* only be used once within that `<ExtensionSlot>`.
21
22
  */
22
23
  export const Extension: React.FC<ExtensionProps> = ({ state, wrap }) => {
23
- const [ref, extension] = useExtension<HTMLDivElement>(state);
24
+ const [domElement, setDomElement] = useState<HTMLDivElement>();
25
+ const { extension } = useContext(ComponentContext);
26
+
27
+ const ref = useCallback((node) => {
28
+ setDomElement(node);
29
+ }, []);
30
+
31
+ useEffect(() => {
32
+ if (domElement != null && extension) {
33
+ return renderExtension(
34
+ domElement,
35
+ extension.extensionSlotName,
36
+ extension.extensionSlotModuleName,
37
+ extension.extensionId,
38
+ undefined,
39
+ state
40
+ );
41
+ }
42
+ }, [
43
+ extension?.extensionSlotName,
44
+ extension?.extensionId,
45
+ extension?.extensionSlotModuleName,
46
+ state,
47
+ domElement,
48
+ ]);
24
49
 
25
50
  // The extension is rendered into the `<slot>`. It is surrounded by a
26
51
  // `<div>` with relative positioning in order to allow the UI Editor
@@ -1,5 +1,5 @@
1
1
  import React, { useRef, useMemo } from "react";
2
- import { ConnectedExtension } from "./useConnectedExtensions";
2
+ import { ConnectedExtension } from "@openmrs/esm-extensions";
3
3
  import { ComponentContext } from "./ComponentContext";
4
4
  import { Extension } from "./Extension";
5
5
  import { useExtensionSlot } from "./useExtensionSlot";
@@ -76,7 +76,7 @@ export const ExtensionSlot: React.FC<ExtensionSlotProps> = ({
76
76
  <ComponentContext.Provider
77
77
  key={extension.id}
78
78
  value={{
79
- moduleName: extension.moduleName,
79
+ moduleName: extensionSlotModuleName, // moduleName is not used by the receiving Extension
80
80
  extension: {
81
81
  extensionId: extension.id,
82
82
  extensionSlotName,
package/src/index.ts CHANGED
@@ -5,15 +5,15 @@ export * from "./Extension";
5
5
  export * from "./ExtensionSlot";
6
6
  export * from "./getLifecycle";
7
7
  export * from "./openmrsComponentDecorator";
8
+ export * from "./useAssignedExtensions";
8
9
  export * from "./useAssignedExtensionIds";
9
- export * from "./useAttachedExtensionIds";
10
10
  export * from "./useBodyScrollLock";
11
11
  export * from "./useConfig";
12
12
  export * from "./useConnectedExtensions";
13
13
  export * from "./useConnectivity";
14
14
  export * from "./usePatient";
15
15
  export * from "./useCurrentPatient";
16
- export * from "./useExtension";
16
+ export * from "./useExtensionInternalStore";
17
17
  export * from "./useExtensionSlotConfig";
18
18
  export * from "./useExtensionSlot";
19
19
  export * from "./useExtensionSlotMeta";
@@ -1,29 +1,26 @@
1
1
  import { useEffect, useState } from "react";
2
- import { getAssignedIds } from "@openmrs/esm-extensions";
3
- import { useExtensionSlotConfig } from "./useExtensionSlotConfig";
4
- import { useAttachedExtensionIds } from "./useAttachedExtensionIds";
2
+ import { getExtensionStore } from "@openmrs/esm-extensions";
3
+ import { isEqual } from "lodash";
5
4
 
6
5
  /**
7
6
  * Gets the assigned extension ids for a given extension slot name.
8
7
  * Does not consider if offline or online.
9
- * @param extensionSlotName The name of the slot to get the assigned IDs for.
8
+ * @param slotName The name of the slot to get the assigned IDs for.
9
+ *
10
+ * @deprecated Use `useAssignedExtensions`
10
11
  */
11
- export function useAssignedExtensionIds(extensionSlotName: string) {
12
- const config = useExtensionSlotConfig(extensionSlotName);
13
- const attachedIds = useAttachedExtensionIds(extensionSlotName);
14
- const [assignedIds, setAssignedIds] = useState<Array<string>>([]);
12
+ export function useAssignedExtensionIds(slotName: string) {
13
+ const [ids, setIds] = useState<Array<string>>([]);
15
14
 
16
15
  useEffect(() => {
17
- const newAssignedIds = getAssignedIds(
18
- extensionSlotName,
19
- config,
20
- attachedIds
21
- );
16
+ return getExtensionStore().subscribe((state) => {
17
+ const newIds =
18
+ state.slots[slotName]?.assignedExtensions.map((e) => e.id) ?? [];
19
+ if (!isEqual(newIds, ids)) {
20
+ setIds(newIds);
21
+ }
22
+ });
23
+ }, []);
22
24
 
23
- if (newAssignedIds.join(",") !== assignedIds.join(",")) {
24
- setAssignedIds(newAssignedIds);
25
- }
26
- }, [attachedIds, config]);
27
-
28
- return assignedIds;
25
+ return ids;
29
26
  }
@@ -0,0 +1,23 @@
1
+ import { useEffect, useState } from "react";
2
+ import { AssignedExtension, getExtensionStore } from "@openmrs/esm-extensions";
3
+ import { isEqual } from "lodash";
4
+
5
+ /**
6
+ * Gets the assigned extensions for a given extension slot name.
7
+ * Does not consider if offline or online.
8
+ * @param slotName The name of the slot to get the assigned extensions for.
9
+ */
10
+ export function useAssignedExtensions(slotName: string) {
11
+ const [extensions, setExtensions] = useState<Array<AssignedExtension>>([]);
12
+
13
+ useEffect(() => {
14
+ return getExtensionStore().subscribe((state) => {
15
+ const newExtensions = state.slots[slotName]?.assignedExtensions ?? [];
16
+ if (!isEqual(newExtensions, extensions)) {
17
+ setExtensions(newExtensions);
18
+ }
19
+ });
20
+ }, []);
21
+
22
+ return extensions;
23
+ }
package/src/useConfig.ts CHANGED
@@ -120,8 +120,5 @@ export function useConfig() {
120
120
  [normalConfig, extensionConfig]
121
121
  );
122
122
 
123
- const configNameForDebugMessage = extension
124
- ? `${extension?.extensionSlotModuleName}-${extension?.extensionSlotName}-${extension?.extensionId}`
125
- : moduleName;
126
123
  return config;
127
124
  }
@@ -1,51 +1,25 @@
1
1
  import { useMemo } from "react";
2
2
  import {
3
- checkStatusFor,
4
- ExtensionMeta,
5
- ExtensionRegistration,
6
- extensionStore,
7
- getExtensionRegistrationFrom,
3
+ ConnectedExtension,
4
+ getConnectedExtensions,
8
5
  } from "@openmrs/esm-extensions";
9
- import { useAssignedExtensionIds } from "./useAssignedExtensionIds";
10
6
  import { useConnectivity } from "./useConnectivity";
11
-
12
- function isValidExtension(
13
- extension: ConnectedExtension | { id: string }
14
- ): extension is ConnectedExtension {
15
- return extension.hasOwnProperty("name");
16
- }
17
-
18
- /**
19
- * We have the following extension modes:
20
- *
21
- * - attached (set via code in form of: attach, detach, ...)
22
- * - configured (set via configuration in form of: added, removed, ...)
23
- * - assigned (computed from attached and configured)
24
- * - connected (computed from assigned using connectivity and online / offline)
25
- */
26
-
27
- export interface ConnectedExtension extends ExtensionRegistration {
28
- id: string;
29
- }
7
+ import { useAssignedExtensions } from "./useAssignedExtensions";
30
8
 
31
9
  /**
32
10
  * Gets the assigned extension for a given extension slot name.
33
11
  * Considers if offline or online.
34
- * @param extensionSlotName The name of the slot to get the assigned extensions for.
12
+ * @param slotName The name of the slot to get the assigned extensions for.
35
13
  */
36
14
  export function useConnectedExtensions(
37
- extensionSlotName: string
15
+ slotName: string
38
16
  ): Array<ConnectedExtension> {
39
17
  const online = useConnectivity();
40
- const extensionIdsToRender = useAssignedExtensionIds(extensionSlotName);
18
+ const assignedExtensions = useAssignedExtensions(slotName);
41
19
 
42
- const extensions = useMemo(() => {
43
- const state = extensionStore.getState();
44
- return extensionIdsToRender
45
- .map((id) => ({ id, ...getExtensionRegistrationFrom(state, id) }))
46
- .filter(isValidExtension)
47
- .filter((m) => checkStatusFor(online, m.online, m.offline));
48
- }, [extensionIdsToRender, online]);
20
+ const connectedExtensions = useMemo(() => {
21
+ return getConnectedExtensions(assignedExtensions, online);
22
+ }, [assignedExtensions, online]);
49
23
 
50
- return extensions;
24
+ return connectedExtensions;
51
25
  }
@@ -0,0 +1,10 @@
1
+ import {
2
+ ExtensionInternalStore,
3
+ getExtensionInternalStore,
4
+ } from "@openmrs/esm-extensions";
5
+ import { createUseStore } from "./createUseStore";
6
+
7
+ /** @internal */
8
+ export const useExtensionInternalStore = createUseStore<ExtensionInternalStore>(
9
+ getExtensionInternalStore()
10
+ );
@@ -1,12 +1,10 @@
1
1
  import { useContext, useEffect } from "react";
2
- import {
3
- registerExtensionSlot,
4
- unregisterExtensionSlot,
5
- } from "@openmrs/esm-extensions";
2
+ import { registerExtensionSlot } from "@openmrs/esm-extensions";
6
3
  import { ComponentContext } from "./ComponentContext";
7
4
  import { useConnectedExtensions } from "./useConnectedExtensions";
8
5
 
9
- export function useExtensionSlot(extensionSlotName: string) {
6
+ /** @internal */
7
+ export function useExtensionSlot(slotName: string) {
10
8
  const { moduleName } = useContext(ComponentContext);
11
9
 
12
10
  if (!moduleName) {
@@ -16,15 +14,14 @@ export function useExtensionSlot(extensionSlotName: string) {
16
14
  }
17
15
 
18
16
  useEffect(() => {
19
- registerExtensionSlot(moduleName, extensionSlotName);
20
- return () => unregisterExtensionSlot(moduleName, extensionSlotName);
17
+ registerExtensionSlot(moduleName, slotName);
21
18
  }, []);
22
19
 
23
- const extensions = useConnectedExtensions(extensionSlotName);
20
+ const extensions = useConnectedExtensions(slotName);
24
21
 
25
22
  return {
26
23
  extensions,
27
- extensionSlotName,
24
+ extensionSlotName: slotName,
28
25
  extensionSlotModuleName: moduleName,
29
26
  };
30
27
  }
@@ -1,10 +1,9 @@
1
- import { useContext, useCallback } from "react";
1
+ import { useCallback } from "react";
2
2
  import {
3
3
  ExtensionSlotConfigObject,
4
- ExtensionSlotConfigsStore,
5
- getExtensionSlotsConfigStore,
4
+ ExtensionSlotConfigStore,
5
+ getExtensionSlotConfigStore,
6
6
  } from "@openmrs/esm-config";
7
- import { ComponentContext } from "./ComponentContext";
8
7
  import { useStoreState } from "./useStoreState";
9
8
 
10
9
  const defaultConfig: ExtensionSlotConfigObject = {
@@ -13,12 +12,12 @@ const defaultConfig: ExtensionSlotConfigObject = {
13
12
  remove: [],
14
13
  };
15
14
 
16
- export function useExtensionSlotConfig(extensionSlotName: string) {
17
- const { moduleName } = useContext(ComponentContext);
18
- const store = getExtensionSlotsConfigStore(moduleName);
15
+ /** @internal */
16
+ export function useExtensionSlotConfig(slotName: string) {
17
+ const store = getExtensionSlotConfigStore(slotName);
19
18
  const select = useCallback(
20
- (s: ExtensionSlotConfigsStore) => s.extensionSlotConfigs[extensionSlotName],
21
- [extensionSlotName]
19
+ (s: ExtensionSlotConfigStore) => s.config,
20
+ [slotName]
22
21
  );
23
22
  const config = useStoreState(store, select);
24
23
  return config || defaultConfig;
@@ -1,4 +1,13 @@
1
- import { ExtensionStore, extensionStore } from "@openmrs/esm-extensions";
1
+ import {
2
+ ExtensionInternalStore,
3
+ getExtensionInternalStore,
4
+ } from "@openmrs/esm-extensions";
2
5
  import { createUseStore } from "./createUseStore";
3
6
 
4
- export const useExtensionStore = createUseStore<ExtensionStore>(extensionStore);
7
+ /**
8
+ * The implementation of this will soon undergo a breaking change.
9
+ * This will return an `ExtensionStore` rather than `ExtensionInternalStore`.
10
+ */
11
+ export const useExtensionStore = createUseStore<ExtensionInternalStore>(
12
+ getExtensionInternalStore()
13
+ );
@@ -1,18 +0,0 @@
1
- import { useCallback } from "react";
2
- import { extensionStore, ExtensionStore } from "@openmrs/esm-extensions";
3
- import { useStoreState } from "./useStoreState";
4
-
5
- const defaultArray: Array<string> = [];
6
-
7
- /**
8
- * Gets the assigned extension ids for the given slot.
9
- * @param extensionSlotName
10
- */
11
- export function useAttachedExtensionIds(extensionSlotName: string) {
12
- const select = useCallback(
13
- (s: ExtensionStore) => s.slots[extensionSlotName]?.attachedIds,
14
- [extensionSlotName]
15
- );
16
- const extensions = useStoreState(extensionStore, select);
17
- return extensions || defaultArray;
18
- }
@@ -1,31 +0,0 @@
1
- import { RefObject, useContext, useRef, useEffect } from "react";
2
- import { renderExtension } from "@openmrs/esm-extensions";
3
- import { ComponentContext, ExtensionData } from "./ComponentContext";
4
-
5
- export function useExtension<TRef extends HTMLElement>(
6
- state?: Record<string, any>
7
- ): [RefObject<TRef>, ExtensionData | undefined] {
8
- const ref = useRef<TRef>(null);
9
- const { extension } = useContext(ComponentContext);
10
-
11
- useEffect(() => {
12
- if (ref.current && extension) {
13
- return renderExtension(
14
- ref.current,
15
- extension.extensionSlotName,
16
- extension.extensionSlotModuleName,
17
- extension.extensionId,
18
- undefined,
19
- state
20
- );
21
- }
22
- }, [
23
- extension?.extensionSlotName,
24
- extension?.extensionId,
25
- extension?.extensionSlotModuleName,
26
- ref.current,
27
- state,
28
- ]);
29
-
30
- return [ref, extension];
31
- }