@openmrs/esm-react-utils 10.0.1-pre.5255 → 10.0.1-pre.5295

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.
Files changed (38) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/Extension.d.ts.map +1 -1
  3. package/dist/Extension.js +86 -44
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -0
  7. package/dist/useAssignedExtensionIds.d.ts +1 -1
  8. package/dist/useAssignedExtensionIds.d.ts.map +1 -1
  9. package/dist/useAssignedExtensionIds.js +7 -14
  10. package/dist/useAssignedExtensions.d.ts +13 -1
  11. package/dist/useAssignedExtensions.d.ts.map +1 -1
  12. package/dist/useAssignedExtensions.js +31 -4
  13. package/dist/useCandidateExtensions.d.ts +11 -0
  14. package/dist/useCandidateExtensions.d.ts.map +1 -0
  15. package/dist/useCandidateExtensions.js +12 -0
  16. package/dist/useExtensionSlot.d.ts.map +1 -1
  17. package/dist/useExtensionSlot.js +8 -13
  18. package/dist/useExtensionSlotStore.d.ts +0 -1
  19. package/dist/useExtensionSlotStore.d.ts.map +1 -1
  20. package/dist/useExtensionSlotStore.js +19 -2
  21. package/dist/useShallowStableValue.d.ts +13 -0
  22. package/dist/useShallowStableValue.d.ts.map +1 -0
  23. package/dist/useShallowStableValue.js +19 -0
  24. package/dist/useStore.d.ts.map +1 -1
  25. package/dist/useStore.js +25 -11
  26. package/package.json +23 -23
  27. package/src/Extension.tsx +110 -54
  28. package/src/extensions.test.tsx +112 -0
  29. package/src/index.ts +2 -0
  30. package/src/useAssignedExtensionIds.ts +5 -15
  31. package/src/useAssignedExtensions.ts +30 -3
  32. package/src/useCandidateExtensions.ts +15 -0
  33. package/src/useExtensionSlot.ts +7 -17
  34. package/src/useExtensionSlotStore.ts +23 -3
  35. package/src/useShallowStableValue.test.ts +69 -0
  36. package/src/useShallowStableValue.ts +24 -0
  37. package/src/useStore.test.ts +39 -0
  38. package/src/useStore.ts +17 -10
@@ -1,3 +1,3 @@
1
- [0] Successfully compiled: 53 files with swc (166.72ms)
1
+ [0] Successfully compiled: 55 files with swc (152.36ms)
2
2
  [0] swc --strip-leading-paths src -d dist exited with code 0
3
3
  [1] tsc --project tsconfig.build.json exited with code 0
@@ -1 +1 @@
1
- {"version":3,"file":"Extension.d.ts","sourceRoot":"","sources":["../src/Extension.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAqD,MAAM,OAAO,CAAC;AAI1E,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CA+E9C,CAAC"}
1
+ {"version":3,"file":"Extension.d.ts","sourceRoot":"","sources":["../src/Extension.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAqD,MAAM,OAAO,CAAC;AAI1E,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAuI9C,CAAC"}
package/dist/Extension.js CHANGED
@@ -13,58 +13,100 @@ import { ComponentContext } from "./index.js";
13
13
  const { extension } = useContext(ComponentContext);
14
14
  const parcel = useRef(null);
15
15
  const updatePromise = useRef(Promise.resolve());
16
+ const isUnmounted = useRef(false);
17
+ const isRendering = useRef(false);
18
+ const latestState = useRef(state);
19
+ // Takes the parcel to tear down rather than reading `parcel.current`, which can be reassigned
20
+ // between scheduling this and running it.
21
+ const unmountParcel = useCallback((target)=>{
22
+ if (!target) {
23
+ return;
24
+ }
25
+ const unmountWhenMounted = ()=>{
26
+ if (target.getStatus() === 'MOUNTED') {
27
+ target.unmount();
28
+ }
29
+ };
30
+ switch(target.getStatus()){
31
+ case 'MOUNTED':
32
+ target.unmount();
33
+ break;
34
+ case 'UPDATING':
35
+ // The rejection is reported by whoever owns `updatePromise`; here it only matters that a
36
+ // failed update still runs the teardown, or the parcel is left broken and mounted.
37
+ updatePromise.current?.then(unmountWhenMounted, unmountWhenMounted);
38
+ break;
39
+ default:
40
+ // Any other status: the parcel either hasn't finished coming up or is already gone.
41
+ // `mountPromise` has settled or will, and `unmountWhenMounted` re-checks the status.
42
+ target.mountPromise.then(unmountWhenMounted, ()=>{});
43
+ }
44
+ }, []);
45
+ const applyUpdate = useCallback((target, nextState)=>{
46
+ if (!target.update || target.getStatus() === 'UNMOUNTING') {
47
+ return;
48
+ }
49
+ // Every later update chains onto this promise, so it has to settle even when an update fails.
50
+ updatePromise.current = Promise.all([
51
+ target.mountPromise,
52
+ updatePromise.current
53
+ ]).then(()=>{
54
+ if (parcel.current?.getStatus() === 'MOUNTED' && parcel.current.update) {
55
+ return parcel.current.update({
56
+ ...nextState
57
+ });
58
+ }
59
+ }).catch((err)=>{
60
+ // A parcel torn down while its update was in flight rejects, and that race is expected.
61
+ // We use the status to distinguish reject reasons as the message isn't reliable
62
+ const status = parcel.current?.getStatus();
63
+ if (status !== 'UNMOUNTING' && status !== 'NOT_MOUNTED' && status !== 'UNLOADING') {
64
+ console.error(`The extension '${extension?.extensionId}' failed to update`, err);
65
+ }
66
+ });
67
+ }, []);
16
68
  const ref = useCallback((node)=>{
17
- if (extension?.extensionSlotName && extension.extensionSlotModuleName && extension.extensionSlotModuleName && !parcel.current) {
18
- renderExtension(node, extension.extensionSlotName, extension.extensionSlotModuleName, extension.extensionId, undefined, state).then((newParcel)=>{
19
- parcel.current = newParcel;
20
- });
69
+ // React detaches a ref by calling it with null. If we render something in response to this,
70
+ // React ignores it and we're left tracking a parcel with no visible DOM, so skip conditions
71
+ // we can't handle.
72
+ if (!node || parcel.current || isRendering.current || !extension?.extensionSlotName || !extension.extensionSlotModuleName) {
73
+ return;
21
74
  }
75
+ isRendering.current = true;
76
+ renderExtension(node, extension.extensionSlotName, extension.extensionSlotModuleName, extension.extensionId, undefined, state).then((newParcel)=>{
77
+ isRendering.current = false;
78
+ parcel.current = newParcel;
79
+ // Loading an extension's bundle can outlast the component that asked for it: the cleanup
80
+ // effect has already run and saw no parcel, so teardown has to happen here instead, or the
81
+ // parcel mounts into a detached node and its rendering record outlives the page.
82
+ if (isUnmounted.current) {
83
+ unmountParcel(newParcel);
84
+ return;
85
+ }
86
+ // Ensure we update the state of the parcel to the latest version we've received
87
+ if (newParcel && latestState.current !== state) {
88
+ applyUpdate(newParcel, latestState.current);
89
+ }
90
+ }, // Cleared so a later reattach can try again; `renderExtension` reports its own failures.
91
+ ()=>{
92
+ isRendering.current = false;
93
+ });
22
94
  }, []);
23
95
  useEffect(()=>{
96
+ // Reset on every run, not just the first: StrictMode mounts, tears down and mounts again, so
97
+ // a flag only ever set by the cleanup would still read "unmounted" for the live component.
98
+ isUnmounted.current = false;
24
99
  return ()=>{
25
- if (parcel && parcel.current) {
26
- const status = parcel.current.getStatus();
27
- switch(status){
28
- case 'MOUNTING':
29
- parcel.current.mountPromise.then(()=>{
30
- if (parcel.current?.getStatus() === 'MOUNTED') {
31
- parcel.current.unmount();
32
- }
33
- });
34
- break;
35
- case 'MOUNTED':
36
- parcel.current.unmount();
37
- break;
38
- case 'UPDATING':
39
- if (updatePromise.current) {
40
- updatePromise.current.then(()=>{
41
- if (parcel.current?.getStatus() === 'MOUNTED') {
42
- parcel.current.unmount();
43
- }
44
- });
45
- }
46
- }
47
- }
100
+ isUnmounted.current = true;
101
+ unmountParcel(parcel.current);
48
102
  };
49
103
  }, []);
50
104
  useEffect(()=>{
51
- if (parcel.current && parcel.current.update && parcel.current.getStatus() !== 'UNMOUNTING') {
52
- Promise.all([
53
- parcel.current.mountPromise,
54
- updatePromise.current
55
- ]).then(()=>{
56
- if (parcel?.current?.getStatus() === 'MOUNTED' && parcel.current.update) {
57
- updatePromise.current = parcel.current.update({
58
- ...state
59
- }).catch((err)=>{
60
- // if we were trying to update but the component was unmounted
61
- // while this was happening, ignore the error
62
- if (!(err instanceof Error) || !err.message.includes('minified message #32') || parcel.current?.getStatus() === 'MOUNTED') {
63
- throw err;
64
- }
65
- });
66
- }
67
- });
105
+ // Recorded before the parcel is checked, so that a state that arrives before there is a parcel
106
+ // to receive it is still the one applied once there is.
107
+ latestState.current = state;
108
+ if (parcel.current) {
109
+ applyUpdate(parcel.current, state);
68
110
  }
69
111
  }, [
70
112
  state
package/dist/index.d.ts CHANGED
@@ -10,6 +10,8 @@ export * from './useAbortController';
10
10
  export * from './useAppContext';
11
11
  export * from './useAssignedExtensionIds';
12
12
  export * from './useAssignedExtensions';
13
+ export * from './useCandidateExtensions';
14
+ export * from './useShallowStableValue';
13
15
  export * from './useAttachments';
14
16
  export * from './useBodyScrollLock';
15
17
  export * from './useConfig';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC/F,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kBAAkB,CAAC;AACjC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AACzF,OAAO,EAAE,oBAAoB,EAAE,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC/F,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,cAAc,CAAC;AAC7B,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -10,6 +10,8 @@ export * from "./useAbortController.js";
10
10
  export * from "./useAppContext.js";
11
11
  export * from "./useAssignedExtensionIds.js";
12
12
  export * from "./useAssignedExtensions.js";
13
+ export * from "./useCandidateExtensions.js";
14
+ export * from "./useShallowStableValue.js";
13
15
  export * from "./useAttachments.js";
14
16
  export * from "./useBodyScrollLock.js";
15
17
  export * from "./useConfig.js";
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Gets the assigned extension ids for a given extension slot name.
3
- * Does not consider if offline or online.
3
+ *
4
4
  * @param slotName The name of the slot to get the assigned IDs for.
5
5
  *
6
6
  * @deprecated Use `useAssignedExtensions`
@@ -1 +1 @@
1
- {"version":3,"file":"useAssignedExtensionIds.d.ts","sourceRoot":"","sources":["../src/useAssignedExtensionIds.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,YAavD"}
1
+ {"version":3,"file":"useAssignedExtensionIds.d.ts","sourceRoot":"","sources":["../src/useAssignedExtensionIds.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,YAIvD"}
@@ -1,21 +1,14 @@
1
- /** @module @category Extension */ import { useEffect, useState } from "react";
2
- import { getExtensionStore } from "@openmrs/esm-extensions";
3
- import { isEqual } from "lodash-es";
1
+ /** @module @category Extension */ import { useMemo } from "react";
2
+ import { useAssignedExtensions } from "./useAssignedExtensions.js";
4
3
  /**
5
4
  * Gets the assigned extension ids for a given extension slot name.
6
- * Does not consider if offline or online.
5
+ *
7
6
  * @param slotName The name of the slot to get the assigned IDs for.
8
7
  *
9
8
  * @deprecated Use `useAssignedExtensions`
10
9
  */ export function useAssignedExtensionIds(slotName) {
11
- const [ids, setIds] = useState([]);
12
- useEffect(()=>{
13
- return getExtensionStore().subscribe((state)=>{
14
- const newIds = state.slots[slotName]?.assignedExtensions.map((e)=>e.id) ?? [];
15
- if (!isEqual(newIds, ids)) {
16
- setIds(newIds);
17
- }
18
- });
19
- }, []);
20
- return ids;
10
+ const assignedExtensions = useAssignedExtensions(slotName);
11
+ return useMemo(()=>assignedExtensions.map((extension)=>extension.id), [
12
+ assignedExtensions
13
+ ]);
21
14
  }
@@ -1,6 +1,18 @@
1
+ import { type ExtensionSlotCustomState } from '@openmrs/esm-extensions';
1
2
  /**
2
3
  * Gets the assigned extensions for a given extension slot name.
4
+ *
5
+ * The reactive form of `getAssignedExtensions`, and it answers the same thing: display conditions
6
+ * are always applied, so the result is what should actually be displayed. Pass `state` whenever you
7
+ * know it: the same slot can be rendered in several places at once with different state, so
8
+ * conditions are resolved against the state of this rendering. Omitting it resolves them against
9
+ * the session alone, hiding any extension whose condition depends on state.
10
+ *
11
+ * The returned array is a copy, so sorting or filtering it in place can't corrupt the extension
12
+ * store. Its reference is stable for as long as the slot's extensions, the state and the session are.
13
+ *
3
14
  * @param slotName The name of the slot to get the assigned extensions for.
15
+ * @param state The state of this rendering of the slot.
4
16
  */
5
- export declare function useAssignedExtensions(slotName: string): import("@openmrs/esm-extensions").AssignedExtension[];
17
+ export declare function useAssignedExtensions(slotName: string, state?: ExtensionSlotCustomState): import("@openmrs/esm-extensions").AssignedExtension[];
6
18
  //# sourceMappingURL=useAssignedExtensions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAssignedExtensions.d.ts","sourceRoot":"","sources":["../src/useAssignedExtensions.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,yDAGrD"}
1
+ {"version":3,"file":"useAssignedExtensions.d.ts","sourceRoot":"","sources":["../src/useAssignedExtensions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,wBAAwB,EAAyB,MAAM,yBAAyB,CAAC;AAO/F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,wBAAwB,yDAYvF"}
@@ -1,8 +1,35 @@
1
- /** @module @category Extension */ import { useExtensionSlotStore } from "./useExtensionSlotStore.js";
1
+ /** @module @category Extension */ import { useMemo } from "react";
2
+ import { sessionStore } from "@openmrs/esm-api";
3
+ import { getAssignedExtensions } from "@openmrs/esm-extensions";
4
+ import { useShallowStableValue } from "./useShallowStableValue.js";
5
+ import { useExtensionSlotStore } from "./useExtensionSlotStore.js";
6
+ import { useStore } from "./useStore.js";
7
+ const selectSession = (state)=>state.session;
2
8
  /**
3
9
  * Gets the assigned extensions for a given extension slot name.
10
+ *
11
+ * The reactive form of `getAssignedExtensions`, and it answers the same thing: display conditions
12
+ * are always applied, so the result is what should actually be displayed. Pass `state` whenever you
13
+ * know it: the same slot can be rendered in several places at once with different state, so
14
+ * conditions are resolved against the state of this rendering. Omitting it resolves them against
15
+ * the session alone, hiding any extension whose condition depends on state.
16
+ *
17
+ * The returned array is a copy, so sorting or filtering it in place can't corrupt the extension
18
+ * store. Its reference is stable for as long as the slot's extensions, the state and the session are.
19
+ *
4
20
  * @param slotName The name of the slot to get the assigned extensions for.
5
- */ export function useAssignedExtensions(slotName) {
6
- const slotStore = useExtensionSlotStore(slotName);
7
- return slotStore?.assignedExtensions ?? [];
21
+ * @param state The state of this rendering of the slot.
22
+ */ export function useAssignedExtensions(slotName, state) {
23
+ // Subscribes so that this re-runs when the slot's extensions change; `getAssignedExtensions` reads
24
+ // the same store, so the value below is what it is about to return.
25
+ const { candidateExtensions } = useExtensionSlotStore(slotName);
26
+ // Display conditions may refer to `session`, so they have to be re-evaluated when it changes.
27
+ const session = useStore(sessionStore, selectSession);
28
+ const stableState = useShallowStableValue(state);
29
+ return useMemo(()=>getAssignedExtensions(slotName, stableState), [
30
+ slotName,
31
+ stableState,
32
+ session,
33
+ candidateExtensions
34
+ ]);
8
35
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The reactive form of `getCandidateExtensions`: everything assigned to a slot, with no display
3
+ * condition evaluated. Intended for tools that present a slot's configuration rather than render it.
4
+ *
5
+ * Use {@link useAssignedExtensions} to decide what to display.
6
+ *
7
+ * @param slotName The name of the slot to get the candidate extensions for.
8
+ * @internal
9
+ */
10
+ export declare function useCandidateExtensions(slotName: string): import("@openmrs/esm-extensions").AssignedExtension[];
11
+ //# sourceMappingURL=useCandidateExtensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useCandidateExtensions.d.ts","sourceRoot":"","sources":["../src/useCandidateExtensions.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,yDAEtD"}
@@ -0,0 +1,12 @@
1
+ /** @module @category Extension */ import { useExtensionSlotStore } from "./useExtensionSlotStore.js";
2
+ /**
3
+ * The reactive form of `getCandidateExtensions`: everything assigned to a slot, with no display
4
+ * condition evaluated. Intended for tools that present a slot's configuration rather than render it.
5
+ *
6
+ * Use {@link useAssignedExtensions} to decide what to display.
7
+ *
8
+ * @param slotName The name of the slot to get the candidate extensions for.
9
+ * @internal
10
+ */ export function useCandidateExtensions(slotName) {
11
+ return useExtensionSlotStore(slotName).candidateExtensions;
12
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"useExtensionSlot.d.ts","sourceRoot":"","sources":["../src/useExtensionSlot.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,wBAAwB,EAG9B,MAAM,yBAAyB,CAAC;AAIjC,gBAAgB;AAChB,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,wBAAwB;;;;EA0BlF"}
1
+ {"version":3,"file":"useExtensionSlot.d.ts","sourceRoot":"","sources":["../src/useExtensionSlot.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,wBAAwB,EAAyB,MAAM,yBAAyB,CAAC;AAI/F,gBAAgB;AAChB,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,wBAAwB;;;;EAoBlF"}
@@ -1,26 +1,21 @@
1
- import { useContext, useEffect, useRef } from "react";
2
- import { registerExtensionSlot, updateExtensionSlotState } from "@openmrs/esm-extensions";
1
+ import { useContext, useEffect } from "react";
2
+ import { registerExtensionSlot } from "@openmrs/esm-extensions";
3
3
  import { ComponentContext } from "./ComponentContext.js";
4
4
  import { useAssignedExtensions } from "./useAssignedExtensions.js";
5
5
  /** @internal */ export function useExtensionSlot(slotName, state) {
6
6
  const { moduleName } = useContext(ComponentContext);
7
- const isInitialRender = useRef(true);
8
7
  if (!moduleName) {
9
8
  throw Error('ComponentContext has not been provided. This should come from @openmrs/esm-react-utils.');
10
9
  }
11
10
  useEffect(()=>{
12
- registerExtensionSlot(moduleName, slotName, state);
13
- isInitialRender.current = false;
14
- }, []);
15
- useEffect(()=>{
16
- if (!isInitialRender.current) {
17
- updateExtensionSlotState(slotName, state);
18
- }
11
+ registerExtensionSlot(moduleName, slotName);
19
12
  }, [
20
- slotName,
21
- state
13
+ moduleName,
14
+ slotName
22
15
  ]);
23
- const extensions = useAssignedExtensions(slotName);
16
+ // `state` must be local to the rendering rather than written to the store as state is
17
+ // render-specific
18
+ const extensions = useAssignedExtensions(slotName, state);
24
19
  return {
25
20
  extensions,
26
21
  extensionSlotName: slotName,
@@ -1,4 +1,3 @@
1
- /** @module @category Extension */
2
1
  import { type ExtensionSlotState } from '@openmrs/esm-extensions';
3
2
  export declare const useExtensionSlotStore: (slot: string) => ExtensionSlotState;
4
3
  //# sourceMappingURL=useExtensionSlotStore.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useExtensionSlotStore.d.ts","sourceRoot":"","sources":["../src/useExtensionSlotStore.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,OAAO,EAAE,KAAK,kBAAkB,EAA0C,MAAM,yBAAyB,CAAC;AAG1G,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,uBACiD,CAAC"}
1
+ {"version":3,"file":"useExtensionSlotStore.d.ts","sourceRoot":"","sources":["../src/useExtensionSlotStore.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,yBAAyB,CAAC;AAcjC,eAAO,MAAM,qBAAqB,GAAI,MAAM,MAAM,uBAIjD,CAAC"}
@@ -1,3 +1,20 @@
1
- /** @module @category Extension */ import { getExtensionStore } from "@openmrs/esm-extensions";
1
+ /** @module @category Extension */ import { useCallback } from "react";
2
+ import { getExtensionStore } from "@openmrs/esm-extensions";
2
3
  import { useStore } from "./useStore.js";
3
- export const useExtensionSlotStore = (slot)=>useStore(getExtensionStore(), (state)=>state.slots?.[slot]);
4
+ /**
5
+ * Stands in for a slot that has not been registered or attached to. Shared rather than built per
6
+ * call, so the snapshot stays reference-stable across renders — and frozen because that sharing
7
+ * means an in-place sort or push would otherwise corrupt every unregistered slot in the page.
8
+ */ const emptyCandidates = [];
9
+ Object.freeze(emptyCandidates);
10
+ const emptySlotState = {
11
+ candidateExtensions: emptyCandidates
12
+ };
13
+ Object.freeze(emptySlotState);
14
+ export const useExtensionSlotStore = (slot)=>{
15
+ // Memoized so that `useStore`'s snapshot function is stable across renders.
16
+ const select = useCallback((state)=>state.slots?.[slot] ?? emptySlotState, [
17
+ slot
18
+ ]);
19
+ return useStore(getExtensionStore(), select);
20
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Returns `value` with a reference that only changes when its contents do, so that it can be used
3
+ * as a dependency of `useMemo`, `useEffect` and friends.
4
+ *
5
+ * This exists for props that are almost always written as object literals — `state={{ patientUuid }}`
6
+ * — which get a new identity on every render while meaning the same thing. Comparison is shallow,
7
+ * so a value nested more than one level deep still reads as a change.
8
+ *
9
+ * @param value The value to stabilize
10
+ * @returns `value`, or the last value this hook returned if the two are shallowly equal
11
+ */
12
+ export declare function useShallowStableValue<T>(value: T): T;
13
+ //# sourceMappingURL=useShallowStableValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShallowStableValue.d.ts","sourceRoot":"","sources":["../src/useShallowStableValue.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAQpD"}
@@ -0,0 +1,19 @@
1
+ /** @module @category Utility */ import { useRef } from "react";
2
+ import { shallowEqual } from "@openmrs/esm-utils";
3
+ /**
4
+ * Returns `value` with a reference that only changes when its contents do, so that it can be used
5
+ * as a dependency of `useMemo`, `useEffect` and friends.
6
+ *
7
+ * This exists for props that are almost always written as object literals — `state={{ patientUuid }}`
8
+ * — which get a new identity on every render while meaning the same thing. Comparison is shallow,
9
+ * so a value nested more than one level deep still reads as a change.
10
+ *
11
+ * @param value The value to stabilize
12
+ * @returns `value`, or the last value this hook returned if the two are shallowly equal
13
+ */ export function useShallowStableValue(value) {
14
+ const stable = useRef(value);
15
+ if (!shallowEqual(stable.current, value)) {
16
+ stable.current = value;
17
+ }
18
+ return stable.current;
19
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"useStore.d.ts","sourceRoot":"","sources":["../src/useStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useStore.d.ts","sourceRoot":"","sources":["../src/useStore.ts"],"names":[],"mappings":"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"}
package/dist/useStore.js CHANGED
@@ -14,7 +14,12 @@ function bindActions(store, actions) {
14
14
  }
15
15
  return bound;
16
16
  }
17
- const defaultSelectFunction = ()=>(x)=>x;
17
+ /**
18
+ * A single shared identity function, rather than one built per call: `getSnapshot` below takes
19
+ * the selector as a dependency, so a fresh default each render would leave it unstable for every
20
+ * caller that doesn't pass a selector of its own.
21
+ */ const identitySelect = (x)=>x;
22
+ const defaultSelectFunction = ()=>identitySelect;
18
23
  function useStore(store, select = defaultSelectFunction(), actions) {
19
24
  // Use useSyncExternalStore to subscribe synchronously during render
20
25
  // This ensures React can properly track all state updates
@@ -28,14 +33,20 @@ function useStore(store, select = defaultSelectFunction(), actions) {
28
33
  select
29
34
  ]);
30
35
  const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
31
- let boundActions = useMemo(()=>actions ? bindActions(store, actions) : {}, [
36
+ let boundActions = useMemo(()=>actions ? bindActions(store, actions) : null, [
32
37
  store,
33
38
  actions
34
39
  ]);
35
- return {
36
- ...state,
37
- ...boundActions
38
- };
40
+ // Returned as-is when there are no actions to merge in, so the reference stays stable for as
41
+ // long as the selected value does. That value is not a copy — it is whatever the selector
42
+ // returned, usually the store's own state.
43
+ return useMemo(()=>boundActions ? {
44
+ ...state,
45
+ ...boundActions
46
+ } : state, [
47
+ state,
48
+ boundActions
49
+ ]);
39
50
  }
40
51
  /**
41
52
  *
@@ -53,13 +64,16 @@ function useStore(store, select = defaultSelectFunction(), actions) {
53
64
  const subscribe = useCallback((callback)=>store.subscribe(callback), []);
54
65
  const getSnapshot = useCallback(()=>store.getState(), []);
55
66
  const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
56
- let boundActions = useMemo(()=>actions ? bindActions(store, actions) : {}, [
67
+ let boundActions = useMemo(()=>actions ? bindActions(store, actions) : null, [
57
68
  actions
58
69
  ]);
59
- return {
60
- ...state,
61
- ...boundActions
62
- };
70
+ return useMemo(()=>boundActions ? {
71
+ ...state,
72
+ ...boundActions
73
+ } : state, [
74
+ state,
75
+ boundActions
76
+ ]);
63
77
  }
64
78
  return useStore;
65
79
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-react-utils",
3
- "version": "10.0.1-pre.5255",
3
+ "version": "10.0.1-pre.5295",
4
4
  "license": "MPL-2.0",
5
5
  "description": "React utilities for OpenMRS.",
6
6
  "type": "module",
@@ -60,17 +60,17 @@
60
60
  "single-spa-react": "^6.0.2"
61
61
  },
62
62
  "peerDependencies": {
63
- "@openmrs/esm-api": "^10.0.1-pre.5255",
64
- "@openmrs/esm-config": "^10.0.1-pre.5255",
65
- "@openmrs/esm-context": "^10.0.1-pre.5255",
66
- "@openmrs/esm-emr-api": "^10.0.1-pre.5255",
67
- "@openmrs/esm-error-handling": "^10.0.1-pre.5255",
68
- "@openmrs/esm-extensions": "^10.0.1-pre.5255",
69
- "@openmrs/esm-feature-flags": "^10.0.1-pre.5255",
70
- "@openmrs/esm-globals": "^10.0.1-pre.5255",
71
- "@openmrs/esm-navigation": "^10.0.1-pre.5255",
72
- "@openmrs/esm-state": "^10.0.1-pre.5255",
73
- "@openmrs/esm-utils": "^10.0.1-pre.5255",
63
+ "@openmrs/esm-api": "^10.0.1-pre.5295",
64
+ "@openmrs/esm-config": "^10.0.1-pre.5295",
65
+ "@openmrs/esm-context": "^10.0.1-pre.5295",
66
+ "@openmrs/esm-emr-api": "^10.0.1-pre.5295",
67
+ "@openmrs/esm-error-handling": "^10.0.1-pre.5295",
68
+ "@openmrs/esm-extensions": "^10.0.1-pre.5295",
69
+ "@openmrs/esm-feature-flags": "^10.0.1-pre.5295",
70
+ "@openmrs/esm-globals": "^10.0.1-pre.5295",
71
+ "@openmrs/esm-navigation": "^10.0.1-pre.5295",
72
+ "@openmrs/esm-state": "^10.0.1-pre.5295",
73
+ "@openmrs/esm-utils": "^10.0.1-pre.5295",
74
74
  "dayjs": "1.x",
75
75
  "i18next": "25.x",
76
76
  "react": "18.x",
@@ -80,17 +80,17 @@
80
80
  "swr": "2.x"
81
81
  },
82
82
  "devDependencies": {
83
- "@openmrs/esm-api": "10.0.1-pre.5255",
84
- "@openmrs/esm-config": "10.0.1-pre.5255",
85
- "@openmrs/esm-context": "10.0.1-pre.5255",
86
- "@openmrs/esm-emr-api": "10.0.1-pre.5255",
87
- "@openmrs/esm-error-handling": "10.0.1-pre.5255",
88
- "@openmrs/esm-extensions": "10.0.1-pre.5255",
89
- "@openmrs/esm-feature-flags": "10.0.1-pre.5255",
90
- "@openmrs/esm-globals": "10.0.1-pre.5255",
91
- "@openmrs/esm-navigation": "10.0.1-pre.5255",
92
- "@openmrs/esm-state": "10.0.1-pre.5255",
93
- "@openmrs/esm-utils": "10.0.1-pre.5255",
83
+ "@openmrs/esm-api": "10.0.1-pre.5295",
84
+ "@openmrs/esm-config": "10.0.1-pre.5295",
85
+ "@openmrs/esm-context": "10.0.1-pre.5295",
86
+ "@openmrs/esm-emr-api": "10.0.1-pre.5295",
87
+ "@openmrs/esm-error-handling": "10.0.1-pre.5295",
88
+ "@openmrs/esm-extensions": "10.0.1-pre.5295",
89
+ "@openmrs/esm-feature-flags": "10.0.1-pre.5295",
90
+ "@openmrs/esm-globals": "10.0.1-pre.5295",
91
+ "@openmrs/esm-navigation": "10.0.1-pre.5295",
92
+ "@openmrs/esm-state": "10.0.1-pre.5295",
93
+ "@openmrs/esm-utils": "10.0.1-pre.5295",
94
94
  "@swc/cli": "0.8.1",
95
95
  "@swc/core": "1.15.21",
96
96
  "@vitest/coverage-v8": "^4.1.2",