@openmrs/esm-react-utils 6.3.1-pre.2965 → 6.3.1-pre.2986

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 (136) hide show
  1. package/.swcrc +16 -0
  2. package/.turbo/turbo-build.log +3 -14
  3. package/dist/ComponentContext.d.ts +15 -0
  4. package/dist/ComponentContext.js +7 -0
  5. package/dist/ConfigurableLink.d.ts +21 -0
  6. package/dist/ConfigurableLink.js +48 -0
  7. package/dist/Extension.d.ts +14 -0
  8. package/dist/Extension.js +83 -0
  9. package/dist/ExtensionSlot.d.ts +69 -0
  10. package/dist/ExtensionSlot.js +97 -0
  11. package/dist/OpenmrsContext.d.ts +20 -0
  12. package/dist/OpenmrsContext.js +17 -0
  13. package/dist/RenderIfValueIsTruthy.d.ts +19 -0
  14. package/dist/RenderIfValueIsTruthy.js +20 -0
  15. package/dist/UserHasAccess.d.ts +35 -0
  16. package/dist/UserHasAccess.js +43 -0
  17. package/dist/getLifecycle.d.ts +13 -0
  18. package/dist/getLifecycle.js +20 -0
  19. package/dist/index.d.ts +48 -0
  20. package/dist/index.js +48 -0
  21. package/dist/openmrsComponentDecorator.d.ts +19 -0
  22. package/dist/openmrsComponentDecorator.js +102 -0
  23. package/dist/public.d.ts +44 -0
  24. package/dist/public.js +43 -0
  25. package/dist/useAbortController.d.ts +23 -0
  26. package/dist/useAbortController.js +33 -0
  27. package/dist/useAppContext.d.ts +21 -0
  28. package/dist/useAppContext.js +45 -0
  29. package/dist/useAssignedExtensionIds.d.ts +8 -0
  30. package/dist/useAssignedExtensionIds.js +21 -0
  31. package/dist/useAssignedExtensions.d.ts +5 -0
  32. package/dist/useAssignedExtensions.js +8 -0
  33. package/dist/useAttachments.d.ts +11 -0
  34. package/dist/useAttachments.js +21 -0
  35. package/dist/useBodyScrollLock.d.ts +1 -0
  36. package/dist/useBodyScrollLock.js +14 -0
  37. package/dist/useConfig.d.ts +11 -0
  38. package/dist/useConfig.js +136 -0
  39. package/dist/useConnectedExtensions.d.ts +8 -0
  40. package/dist/useConnectedExtensions.js +6 -0
  41. package/dist/useConnectivity.d.ts +1 -0
  42. package/dist/useConnectivity.js +8 -0
  43. package/dist/useDebounce.d.ts +29 -0
  44. package/dist/useDebounce.js +43 -0
  45. package/dist/useDefineAppContext.d.ts +32 -0
  46. package/dist/useDefineAppContext.js +56 -0
  47. package/dist/useEmrConfiguration.d.ts +97 -0
  48. package/dist/useEmrConfiguration.js +236 -0
  49. package/dist/useExtensionInternalStore.d.ts +9 -0
  50. package/dist/useExtensionInternalStore.js +5 -0
  51. package/dist/useExtensionSlot.d.ts +6 -0
  52. package/dist/useExtensionSlot.js +19 -0
  53. package/dist/useExtensionSlotMeta.d.ts +9 -0
  54. package/dist/useExtensionSlotMeta.js +14 -0
  55. package/dist/useExtensionSlotStore.d.ts +3 -0
  56. package/dist/useExtensionSlotStore.js +3 -0
  57. package/dist/useExtensionStore.d.ts +7 -0
  58. package/dist/useExtensionStore.js +3 -0
  59. package/dist/useFeatureFlag.d.ts +14 -0
  60. package/dist/useFeatureFlag.js +19 -0
  61. package/dist/useFhirFetchAll.d.ts +18 -0
  62. package/dist/useFhirFetchAll.js +18 -0
  63. package/dist/useFhirInfinite.d.ts +19 -0
  64. package/dist/useFhirInfinite.js +20 -0
  65. package/dist/useFhirPagination.d.ts +43 -0
  66. package/dist/useFhirPagination.js +51 -0
  67. package/dist/useForceUpdate.d.ts +1 -0
  68. package/dist/useForceUpdate.js +8 -0
  69. package/dist/useLayoutType.d.ts +3 -0
  70. package/dist/useLayoutType.js +30 -0
  71. package/dist/useLocations.d.ts +2 -0
  72. package/dist/useLocations.js +17 -0
  73. package/dist/useOnClickOutside.d.ts +2 -0
  74. package/dist/useOnClickOutside.js +22 -0
  75. package/dist/useOnVisible.d.ts +14 -0
  76. package/dist/useOnVisible.js +40 -0
  77. package/dist/useOpenmrsFetchAll.d.ts +29 -0
  78. package/dist/useOpenmrsFetchAll.js +42 -0
  79. package/dist/useOpenmrsInfinite.d.ts +85 -0
  80. package/dist/useOpenmrsInfinite.js +68 -0
  81. package/dist/useOpenmrsPagination.d.ts +99 -0
  82. package/dist/useOpenmrsPagination.js +129 -0
  83. package/dist/useOpenmrsSWR.d.ts +50 -0
  84. package/dist/useOpenmrsSWR.js +72 -0
  85. package/dist/usePagination.d.ts +20 -0
  86. package/dist/usePagination.js +70 -0
  87. package/dist/usePatient.d.ts +14 -0
  88. package/dist/usePatient.js +42 -0
  89. package/dist/usePrimaryIdentifierResource.d.ts +8 -0
  90. package/dist/usePrimaryIdentifierResource.js +17 -0
  91. package/dist/useRenderableExtensions.d.ts +30 -0
  92. package/dist/useRenderableExtensions.js +43 -0
  93. package/dist/useSession.d.ts +16 -0
  94. package/dist/useSession.js +108 -0
  95. package/dist/useStore.d.ts +30 -0
  96. package/dist/useStore.js +59 -0
  97. package/dist/useVisit.d.ts +31 -0
  98. package/dist/useVisit.js +83 -0
  99. package/dist/useVisitContextStore.d.ts +12 -0
  100. package/dist/useVisitContextStore.js +55 -0
  101. package/dist/useVisitTypes.d.ts +3 -0
  102. package/dist/useVisitTypes.js +12 -0
  103. package/mock-jest.tsx +153 -0
  104. package/mock.tsx +55 -53
  105. package/package.json +44 -19
  106. package/setup-tests.ts +19 -0
  107. package/src/ConfigurableLink.test.tsx +7 -4
  108. package/src/ConfigurableLink.tsx +1 -2
  109. package/src/extensions.test.tsx +11 -16
  110. package/src/openmrsComponentDecorator.test.tsx +5 -4
  111. package/src/useAbortController.test.tsx +2 -1
  112. package/src/useAttachments.ts +2 -1
  113. package/src/useConfig.test.tsx +14 -1
  114. package/src/useConfig.ts +2 -2
  115. package/src/useEmrConfiguration.ts +1 -1
  116. package/src/useLocations.tsx +1 -2
  117. package/src/useOnClickOutside.test.tsx +3 -2
  118. package/src/useOpenmrsFetchAll.test.tsx +1 -1
  119. package/src/useOpenmrsInfinite.test.tsx +1 -1
  120. package/src/useOpenmrsInfinite.ts +0 -1
  121. package/src/useOpenmrsPagination.test.tsx +1 -1
  122. package/src/usePatient.ts +1 -1
  123. package/src/useSession.test.tsx +5 -3
  124. package/src/useStore.test.ts +2 -1
  125. package/src/useVisit.ts +4 -4
  126. package/src/useVisitContextStore.ts +2 -2
  127. package/src/useVisitTypes.ts +1 -2
  128. package/tsconfig.build.json +9 -0
  129. package/tsconfig.json +3 -24
  130. package/vitest.config.ts +9 -0
  131. package/dist/openmrs-esm-react-utils.js +0 -3
  132. package/dist/openmrs-esm-react-utils.js.LICENSE.txt +0 -9
  133. package/dist/openmrs-esm-react-utils.js.map +0 -1
  134. package/jest.config.js +0 -18
  135. package/src/setup-tests.js +0 -11
  136. package/webpack.config.js +0 -42
package/.swcrc ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://swc.rs/schema.json",
3
+ "exclude": [".*\\.test\\..*", "setup-tests\\..*"],
4
+ "module": {
5
+ "type": "es6",
6
+ "resolveFully": true
7
+ },
8
+ "jsc": {
9
+ "parser": {
10
+ "syntax": "typescript",
11
+ "tsx": false
12
+ },
13
+ "target": "es2020",
14
+ "baseUrl": "src"
15
+ }
16
+ }
@@ -1,14 +1,3 @@
1
- asset openmrs-esm-react-utils.js 92.6 KiB [emitted] [minimized] (name: main) 2 related assets
2
- orphan modules 848 KiB [orphan] 693 modules
3
- runtime modules 937 bytes 4 modules
4
- built modules 310 KiB [built]
5
- modules by path external "@openmrs/ 336 bytes
6
- external "@openmrs/esm-navigation" 42 bytes [built] [code generated]
7
- external "@openmrs/esm-extensions" 42 bytes [built] [code generated]
8
- + 6 modules
9
- cacheable modules 309 KiB
10
- modules by path ../../../node_modules/ 3.11 KiB 4 modules
11
- ./src/index.ts + 141 modules 298 KiB [built] [code generated]
12
- ../esm-state/dist/openmrs-esm-state.js 8.12 KiB [built] [code generated]
13
- + 5 modules
14
- webpack 5.88.0 compiled successfully in 10351 ms
1
+ [0] Successfully compiled: 50 files with swc (174.78ms)
2
+ [0] swc --strip-leading-paths src -d dist exited with code 0
3
+ [1] tsc --project tsconfig.build.json exited with code 0
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ export interface ExtensionData {
3
+ extensionSlotName: string;
4
+ extensionSlotModuleName: string;
5
+ extensionId: string;
6
+ }
7
+ export interface ComponentConfig {
8
+ moduleName: string;
9
+ featureName: string;
10
+ extension?: ExtensionData;
11
+ }
12
+ /**
13
+ * Available to all components. Provided by `openmrsComponentDecorator`.
14
+ */
15
+ export declare const ComponentContext: React.Context<ComponentConfig>;
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ /**
3
+ * Available to all components. Provided by `openmrsComponentDecorator`.
4
+ */ export const ComponentContext = React.createContext({
5
+ moduleName: '',
6
+ featureName: ''
7
+ });
@@ -0,0 +1,21 @@
1
+ /** @module @category Navigation */
2
+ import React, { type MouseEvent, type AnchorHTMLAttributes, type PropsWithChildren } from 'react';
3
+ import { type TemplateParams } from '@openmrs/esm-navigation';
4
+ /**
5
+ * @noInheritDoc
6
+ */
7
+ export interface ConfigurableLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
8
+ to: string;
9
+ templateParams?: TemplateParams;
10
+ onBeforeNavigate?: (event: MouseEvent) => void;
11
+ }
12
+ /**
13
+ * A React link component which calls [[navigate]] when clicked
14
+ *
15
+ * @param to The target path or URL. Supports interpolation. See [[navigate]]
16
+ * @param templateParams: A dictionary of values to interpolate into the URL, in addition to the default keys `openmrsBase` and `openmrsSpaBase`.
17
+ * @param onBeforeNavigate A callback to be called just before navigation occurs
18
+ * @param children Inline elements within the link
19
+ * @param otherProps Any other valid props for an <a> tag except `href` and `onClick`
20
+ */
21
+ export declare function ConfigurableLink({ to, templateParams, onBeforeNavigate, children, ...otherProps }: PropsWithChildren<ConfigurableLinkProps>): React.JSX.Element;
@@ -0,0 +1,48 @@
1
+ /** @module @category Navigation */ import React, { useEffect } from "react";
2
+ import { navigate, interpolateUrl } from "@openmrs/esm-navigation";
3
+ function handleClick(event, to, templateParams, onBeforeNavigate) {
4
+ // Left click without modifiers (normal navigation)
5
+ if (event.button === 0 && !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) {
6
+ event.preventDefault();
7
+ onBeforeNavigate?.(event);
8
+ navigate({
9
+ to,
10
+ templateParams
11
+ });
12
+ }
13
+ // Left click with Ctrl key (or Cmd key on Mac) - Open in new tab
14
+ if (event.button === 0 && (event.ctrlKey || event.metaKey)) {
15
+ onBeforeNavigate?.(event);
16
+ }
17
+ // Left click with Shift key - Open in new window
18
+ if (event.button === 0 && event.shiftKey) {
19
+ onBeforeNavigate?.(event);
20
+ }
21
+ // Middle click - Open in new background tab
22
+ if (event.button === 1) {
23
+ onBeforeNavigate?.(event);
24
+ }
25
+ }
26
+ /**
27
+ * A React link component which calls [[navigate]] when clicked
28
+ *
29
+ * @param to The target path or URL. Supports interpolation. See [[navigate]]
30
+ * @param templateParams: A dictionary of values to interpolate into the URL, in addition to the default keys `openmrsBase` and `openmrsSpaBase`.
31
+ * @param onBeforeNavigate A callback to be called just before navigation occurs
32
+ * @param children Inline elements within the link
33
+ * @param otherProps Any other valid props for an <a> tag except `href` and `onClick`
34
+ */ export function ConfigurableLink({ to, templateParams, onBeforeNavigate, children, ...otherProps }) {
35
+ useEffect(()=>{
36
+ if (otherProps.href) {
37
+ console.warn(`ConfigurableLink does not support the href prop. Use the 'to' prop instead. The provided href value is '${otherProps.href}'`);
38
+ }
39
+ if (otherProps.onClick) {
40
+ console.warn(`ConfigurableLink does not support the onClick prop. Use the 'onBeforeNavigate' prop instead. The 'to' prop of the offending link is ${to}`);
41
+ }
42
+ }, []);
43
+ return /*#__PURE__*/ React.createElement("a", {
44
+ onClick: (event)=>handleClick(event, to, templateParams, onBeforeNavigate),
45
+ href: interpolateUrl(to, templateParams),
46
+ ...otherProps
47
+ }, children);
48
+ }
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ export type ExtensionProps = React.HTMLAttributes<HTMLDivElement> & {
3
+ state?: Record<string, unknown>;
4
+ };
5
+ /**
6
+ * Represents the position in the DOM where each extension within
7
+ * an extension slot is rendered.
8
+ *
9
+ * Renders once for each extension attached to that extension slot.
10
+ *
11
+ * Usage of this component *must* have an ancestor `<ExtensionSlot>`,
12
+ * and *must* only be used once within that `<ExtensionSlot>`.
13
+ */
14
+ export declare const Extension: React.FC<ExtensionProps>;
@@ -0,0 +1,83 @@
1
+ /** @module @category Extension */ import { renderExtension } from "@openmrs/esm-extensions";
2
+ import React, { useCallback, useContext, useEffect, useRef } from "react";
3
+ import { ComponentContext } from "./index.js";
4
+ /**
5
+ * Represents the position in the DOM where each extension within
6
+ * an extension slot is rendered.
7
+ *
8
+ * Renders once for each extension attached to that extension slot.
9
+ *
10
+ * Usage of this component *must* have an ancestor `<ExtensionSlot>`,
11
+ * and *must* only be used once within that `<ExtensionSlot>`.
12
+ */ export const Extension = ({ state, children, ...divProps })=>{
13
+ const { extension } = useContext(ComponentContext);
14
+ const parcel = useRef(null);
15
+ const updatePromise = useRef(Promise.resolve());
16
+ 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
+ });
21
+ }
22
+ }, []);
23
+ useEffect(()=>{
24
+ 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
+ }
48
+ };
49
+ }, []);
50
+ 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
+ });
68
+ }
69
+ }, [
70
+ state
71
+ ]);
72
+ // The extension is rendered into the `<div>`. The `<div>` has relative
73
+ // positioning in order to allow the UI Editor to absolutely position
74
+ // elements within it.
75
+ return extension ? /*#__PURE__*/ React.createElement("div", {
76
+ ref: ref,
77
+ "data-extension-id": extension?.extensionId,
78
+ style: {
79
+ position: 'relative'
80
+ },
81
+ ...divProps
82
+ }) : null;
83
+ };
@@ -0,0 +1,69 @@
1
+ /** @module @category Extension */
2
+ import React from 'react';
3
+ import { type AssignedExtension } from '@openmrs/esm-extensions';
4
+ export interface ExtensionSlotBaseProps {
5
+ name: string;
6
+ /** @deprecated Use `name` */
7
+ extensionSlotName?: string;
8
+ select?: (extensions: Array<AssignedExtension>) => Array<AssignedExtension>;
9
+ state?: Record<string, unknown>;
10
+ }
11
+ export interface OldExtensionSlotBaseProps {
12
+ name?: string;
13
+ /** @deprecated Use `name` */
14
+ extensionSlotName: string;
15
+ select?: (extensions: Array<AssignedExtension>) => Array<AssignedExtension>;
16
+ state?: Record<string, unknown>;
17
+ }
18
+ export type ExtensionSlotProps = (OldExtensionSlotBaseProps | ExtensionSlotBaseProps) & Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> & {
19
+ children?: React.ReactNode | ((extension: AssignedExtension, state?: Record<string, unknown>) => React.ReactNode);
20
+ };
21
+ /**
22
+ * An [extension slot](https://o3-docs.openmrs.org/docs/extension-system).
23
+ * A place with a name. Extensions that get connected to that name
24
+ * will be rendered into this.
25
+ *
26
+ * @param props.name The name of the extension slot
27
+ * @param props.select An optional function for filtering or otherwise modifying
28
+ * the list of extensions that will be rendered.
29
+ * @param props.state *Only works if no children are provided*. Passes data
30
+ * through as props to the extensions that are mounted here. If `ExtensionSlot`
31
+ * has children, you must pass the state through the `state` param of the
32
+ * `Extension` component.
33
+ * @param props.children There are two different ways to use `ExtensionSlot`
34
+ * children.
35
+ * - Passing a `ReactNode`, the "normal" way. The child must contain the component
36
+ * `Extension`. Whatever is passed as the child will be rendered once per extension.
37
+ * See the first example below.
38
+ * - Passing a function, the "render props" way. The child must be a function
39
+ * which takes a [[ConnectedExtension]] as argument and returns a `ReactNode`.
40
+ * the resulting react node must contain the component `Extension`. It will
41
+ * be run for each extension. See the second example below.
42
+ *
43
+ * @example
44
+ * Passing a react node as children
45
+ *
46
+ * ```tsx
47
+ * <ExtensionSlot name="Foo">
48
+ * <div style={{ width: 10rem }}>
49
+ * <Extension />
50
+ * </div>
51
+ * </ExtensionSlot>
52
+ * ```
53
+ *
54
+ * @example
55
+ * Passing a function as children
56
+ *
57
+ * ```tsx
58
+ * <ExtensionSlot name="Bar">
59
+ * {(extension) => (
60
+ * <h1>{extension.name}</h1>
61
+ * <div style={{ color: extension.meta.color }}>
62
+ * <Extension />
63
+ * </div>
64
+ * )}
65
+ * </ExtensionSlot>
66
+ * ```
67
+ *
68
+ */
69
+ export declare function ExtensionSlot({ name: extensionSlotName, extensionSlotName: legacyExtensionSlotName, select, children, state, style, ...divProps }: ExtensionSlotProps): React.JSX.Element;
@@ -0,0 +1,97 @@
1
+ /** @module @category Extension */ import React, { useRef, useMemo } from "react";
2
+ import { ComponentContext } from "./ComponentContext.js";
3
+ import { Extension } from "./Extension.js";
4
+ import { useExtensionSlot } from "./useExtensionSlot.js";
5
+ function defaultSelect(extensions) {
6
+ return extensions;
7
+ }
8
+ /**
9
+ * An [extension slot](https://o3-docs.openmrs.org/docs/extension-system).
10
+ * A place with a name. Extensions that get connected to that name
11
+ * will be rendered into this.
12
+ *
13
+ * @param props.name The name of the extension slot
14
+ * @param props.select An optional function for filtering or otherwise modifying
15
+ * the list of extensions that will be rendered.
16
+ * @param props.state *Only works if no children are provided*. Passes data
17
+ * through as props to the extensions that are mounted here. If `ExtensionSlot`
18
+ * has children, you must pass the state through the `state` param of the
19
+ * `Extension` component.
20
+ * @param props.children There are two different ways to use `ExtensionSlot`
21
+ * children.
22
+ * - Passing a `ReactNode`, the "normal" way. The child must contain the component
23
+ * `Extension`. Whatever is passed as the child will be rendered once per extension.
24
+ * See the first example below.
25
+ * - Passing a function, the "render props" way. The child must be a function
26
+ * which takes a [[ConnectedExtension]] as argument and returns a `ReactNode`.
27
+ * the resulting react node must contain the component `Extension`. It will
28
+ * be run for each extension. See the second example below.
29
+ *
30
+ * @example
31
+ * Passing a react node as children
32
+ *
33
+ * ```tsx
34
+ * <ExtensionSlot name="Foo">
35
+ * <div style={{ width: 10rem }}>
36
+ * <Extension />
37
+ * </div>
38
+ * </ExtensionSlot>
39
+ * ```
40
+ *
41
+ * @example
42
+ * Passing a function as children
43
+ *
44
+ * ```tsx
45
+ * <ExtensionSlot name="Bar">
46
+ * {(extension) => (
47
+ * <h1>{extension.name}</h1>
48
+ * <div style={{ color: extension.meta.color }}>
49
+ * <Extension />
50
+ * </div>
51
+ * )}
52
+ * </ExtensionSlot>
53
+ * ```
54
+ *
55
+ */ export function ExtensionSlot({ name: extensionSlotName, extensionSlotName: legacyExtensionSlotName, select = defaultSelect, children, state, style, ...divProps }) {
56
+ if (children && state) {
57
+ throw new Error('Both children and state have been provided. If children are provided, the state must be passed as a prop to the `Extension` component.');
58
+ }
59
+ const name = extensionSlotName ?? legacyExtensionSlotName;
60
+ const slotRef = useRef(null);
61
+ const { extensions, extensionSlotModuleName } = useExtensionSlot(name);
62
+ const extensionsToRender = useMemo(()=>select(extensions), [
63
+ select,
64
+ extensions
65
+ ]);
66
+ const extensionsFromChildrenFunction = useMemo(()=>{
67
+ if (typeof children == 'function' && !/*#__PURE__*/ React.isValidElement(children)) {
68
+ return extensionsToRender.map((extension)=>children(extension, state));
69
+ }
70
+ }, [
71
+ children,
72
+ extensionsToRender
73
+ ]);
74
+ return /*#__PURE__*/ React.createElement("div", {
75
+ ref: slotRef,
76
+ "data-extension-slot-name": name,
77
+ "data-extension-slot-module-name": extensionSlotModuleName,
78
+ style: {
79
+ ...style,
80
+ position: 'relative'
81
+ },
82
+ ...divProps
83
+ }, name && extensionsToRender?.map((extension, i)=>/*#__PURE__*/ React.createElement(ComponentContext.Provider, {
84
+ key: extension.id,
85
+ value: {
86
+ moduleName: extensionSlotModuleName,
87
+ featureName: '',
88
+ extension: {
89
+ extensionId: extension.id,
90
+ extensionSlotName: name,
91
+ extensionSlotModuleName
92
+ }
93
+ }
94
+ }, extensionsFromChildrenFunction?.[i] ?? (typeof children !== 'function' ? children : null) ?? /*#__PURE__*/ React.createElement(Extension, {
95
+ state: state
96
+ }))));
97
+ }
@@ -0,0 +1,20 @@
1
+ export interface OpenmrsAppContextProps<T = unknown> {
2
+ /** the namespace that this component defines */
3
+ namespace: string;
4
+ /** used to control the value associated with the namespace */
5
+ value?: T;
6
+ }
7
+ /**
8
+ * OpenmrsAppContext is a simple React component meant to function similarly to React's Context,
9
+ * but built on top of the OpenmrsAppContext.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * <OpenmrsAppContext namespace="something" value={{ key: "1234" }} />
14
+ * ```
15
+ *
16
+ * **Notes on usage:** Unlike a proper React context where the value is limited to the subtree under the
17
+ * context component, the `OpenmrsAppContext` is inherently global in scope. That means that _all applications_
18
+ * will see the values that you set for the namespace if they load the value of the namespace.
19
+ */
20
+ export declare function OpenmrsAppContext<T extends {}>({ namespace, value }: OpenmrsAppContextProps<T>): null;
@@ -0,0 +1,17 @@
1
+ /** @module @category Context */ import { useDefineAppContext } from "./useDefineAppContext.js";
2
+ /**
3
+ * OpenmrsAppContext is a simple React component meant to function similarly to React's Context,
4
+ * but built on top of the OpenmrsAppContext.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * <OpenmrsAppContext namespace="something" value={{ key: "1234" }} />
9
+ * ```
10
+ *
11
+ * **Notes on usage:** Unlike a proper React context where the value is limited to the subtree under the
12
+ * context component, the `OpenmrsAppContext` is inherently global in scope. That means that _all applications_
13
+ * will see the values that you set for the namespace if they load the value of the namespace.
14
+ */ export function OpenmrsAppContext({ namespace, value }) {
15
+ useDefineAppContext(namespace, value);
16
+ return null;
17
+ }
@@ -0,0 +1,19 @@
1
+ import React, { type PropsWithChildren } from 'react';
2
+ /**
3
+ * A really simple component that renders its children if the prop named `value` has a truthy value
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * <RenderIfValueIsTruthy value={variable}>
8
+ * <Component value={variable} />
9
+ * </RenderIfValueIsTruthy>
10
+ * ````
11
+ *
12
+ * @param props.value The value to check whether or not its truthy
13
+ * @param props.fallback What to render if the value is not truthy. If not specified, nothing will be rendered
14
+ * @param props.children The components to render if the `value` is truthy
15
+ */
16
+ export declare const RenderIfValueIsTruthy: React.FC<PropsWithChildren<{
17
+ value: unknown;
18
+ fallback?: React.ReactNode;
19
+ }>>;
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ /**
3
+ * A really simple component that renders its children if the prop named `value` has a truthy value
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * <RenderIfValueIsTruthy value={variable}>
8
+ * <Component value={variable} />
9
+ * </RenderIfValueIsTruthy>
10
+ * ````
11
+ *
12
+ * @param props.value The value to check whether or not its truthy
13
+ * @param props.fallback What to render if the value is not truthy. If not specified, nothing will be rendered
14
+ * @param props.children The components to render if the `value` is truthy
15
+ */ export const RenderIfValueIsTruthy = ({ children, value, fallback })=>{
16
+ if (Boolean(value)) {
17
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, children);
18
+ }
19
+ return fallback ? /*#__PURE__*/ React.createElement(React.Fragment, null, fallback) : null;
20
+ };
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ export interface UserHasAccessProps {
3
+ privilege: string | string[];
4
+ fallback?: React.ReactNode;
5
+ children?: React.ReactNode;
6
+ }
7
+ /**
8
+ * A React component that renders its children only if the current user exists and has the privilege(s)
9
+ * specified by the `privilege` prop. This can be used not to render certain components when the user
10
+ * doesn't have the permission to use this.
11
+ *
12
+ * Note that for top-level extensions (i.e., the component that's the root of the extension), you don't
13
+ * need to use this component. Instead, when registering the extension, declare the required privileges
14
+ * as part of the extension registration. This is for use deeper in extensions or other components where
15
+ * a separate permission check might be needed.
16
+ *
17
+ * This can also be used to hide components when the current user is not logged in.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * <Form>
22
+ * <UserHasAccess privilege='Form Finallizer'>
23
+ * <Checkbox id="finalize-form" value={formFinalized} onChange={handleChange} />
24
+ * </UserHasAccess>
25
+ * </Form>
26
+ * ````
27
+ *
28
+ * @param props.privilege Either a string for a single required privilege or an array of strings for a
29
+ * set of required privileges. Note that sets of required privileges must all be matched.
30
+ * @param props.fallback What to render if the user does not have access or if the user is not currently
31
+ * logged in. If not provided, nothing will be rendered
32
+ * @param props.children The children to be rendered only if the user is logged in and has the required
33
+ * privileges.
34
+ */
35
+ export declare const UserHasAccess: React.FC<UserHasAccessProps>;
@@ -0,0 +1,43 @@
1
+ /** @module @category API */ import { getCurrentUser, userHasAccess } from "@openmrs/esm-api";
2
+ import React, { useEffect, useState } from "react";
3
+ /**
4
+ * A React component that renders its children only if the current user exists and has the privilege(s)
5
+ * specified by the `privilege` prop. This can be used not to render certain components when the user
6
+ * doesn't have the permission to use this.
7
+ *
8
+ * Note that for top-level extensions (i.e., the component that's the root of the extension), you don't
9
+ * need to use this component. Instead, when registering the extension, declare the required privileges
10
+ * as part of the extension registration. This is for use deeper in extensions or other components where
11
+ * a separate permission check might be needed.
12
+ *
13
+ * This can also be used to hide components when the current user is not logged in.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * <Form>
18
+ * <UserHasAccess privilege='Form Finallizer'>
19
+ * <Checkbox id="finalize-form" value={formFinalized} onChange={handleChange} />
20
+ * </UserHasAccess>
21
+ * </Form>
22
+ * ````
23
+ *
24
+ * @param props.privilege Either a string for a single required privilege or an array of strings for a
25
+ * set of required privileges. Note that sets of required privileges must all be matched.
26
+ * @param props.fallback What to render if the user does not have access or if the user is not currently
27
+ * logged in. If not provided, nothing will be rendered
28
+ * @param props.children The children to be rendered only if the user is logged in and has the required
29
+ * privileges.
30
+ */ export const UserHasAccess = ({ privilege, fallback, children })=>{
31
+ const [user, setUser] = useState(null);
32
+ useEffect(()=>{
33
+ const subscription = getCurrentUser({
34
+ includeAuthStatus: false
35
+ }).subscribe(setUser);
36
+ return ()=>subscription.unsubscribe();
37
+ }, []);
38
+ if (user && userHasAccess(privilege, user)) {
39
+ return /*#__PURE__*/ React.createElement(React.Fragment, null, children);
40
+ } else {
41
+ return fallback ? /*#__PURE__*/ React.createElement(React.Fragment, null, fallback) : null;
42
+ }
43
+ };
@@ -0,0 +1,13 @@
1
+ /** @module @category Framework */
2
+ import type { ComponentType } from 'react';
3
+ import singleSpaReact from 'single-spa-react';
4
+ import type { ComponentDecoratorOptions } from './openmrsComponentDecorator';
5
+ export declare function getLifecycle<T>(Component: ComponentType<T>, options: ComponentDecoratorOptions): singleSpaReact.ReactAppOrParcel<T>;
6
+ export declare function getAsyncLifecycle<T>(lazy: () => Promise<{
7
+ default: ComponentType<T>;
8
+ }>, options: ComponentDecoratorOptions): () => Promise<singleSpaReact.ReactAppOrParcel<T>>;
9
+ export declare function getSyncLifecycle<T>(Component: ComponentType<T>, options: ComponentDecoratorOptions): () => Promise<singleSpaReact.ReactAppOrParcel<T>>;
10
+ /**
11
+ * @deprecated Use getAsyncLifecycle instead.
12
+ */
13
+ export declare const getAsyncExtensionLifecycle: typeof getAsyncLifecycle;
@@ -0,0 +1,20 @@
1
+ /** @module @category Framework */ import React from "react";
2
+ import ReactDOMClient from "react-dom/client";
3
+ import singleSpaReact from "single-spa-react";
4
+ import { openmrsComponentDecorator } from "./openmrsComponentDecorator.js";
5
+ export function getLifecycle(Component, options) {
6
+ return singleSpaReact({
7
+ React,
8
+ ReactDOMClient,
9
+ rootComponent: openmrsComponentDecorator(options)(Component)
10
+ });
11
+ }
12
+ export function getAsyncLifecycle(lazy, options) {
13
+ return ()=>lazy().then(({ default: Component })=>getLifecycle(Component, options));
14
+ }
15
+ export function getSyncLifecycle(Component, options) {
16
+ return ()=>Promise.resolve(getLifecycle(Component, options));
17
+ }
18
+ /**
19
+ * @deprecated Use getAsyncLifecycle instead.
20
+ */ export const getAsyncExtensionLifecycle = getAsyncLifecycle;
@@ -0,0 +1,48 @@
1
+ export * from './ComponentContext';
2
+ export * from './ConfigurableLink';
3
+ export * from './Extension';
4
+ export * from './ExtensionSlot';
5
+ export * from './OpenmrsContext';
6
+ export * from './RenderIfValueIsTruthy';
7
+ export * from './UserHasAccess';
8
+ export * from './getLifecycle';
9
+ export * from './openmrsComponentDecorator';
10
+ export * from './useAbortController';
11
+ export * from './useAppContext';
12
+ export * from './useAssignedExtensionIds';
13
+ export * from './useAssignedExtensions';
14
+ export * from './useAttachments';
15
+ export * from './useBodyScrollLock';
16
+ export * from './useConfig';
17
+ export * from './useConnectedExtensions';
18
+ export * from './useConnectivity';
19
+ export * from './useDebounce';
20
+ export * from './useDefineAppContext';
21
+ export * from './useEmrConfiguration';
22
+ export * from './useExtensionInternalStore';
23
+ export * from './useExtensionSlot';
24
+ export * from './useExtensionSlotMeta';
25
+ export * from './useExtensionSlotStore';
26
+ export * from './useExtensionStore';
27
+ export * from './useFeatureFlag';
28
+ export * from './useForceUpdate';
29
+ export * from './useFhirFetchAll';
30
+ export * from './useFhirInfinite';
31
+ export * from './useFhirPagination';
32
+ export * from './useLayoutType';
33
+ export * from './useLocations';
34
+ export * from './useOnClickOutside';
35
+ export * from './useOnVisible';
36
+ export * from './useOpenmrsSWR';
37
+ export * from './usePagination';
38
+ export * from './usePatient';
39
+ export * from './usePrimaryIdentifierResource';
40
+ export * from './useRenderableExtensions';
41
+ export * from './useStore';
42
+ export * from './useVisit';
43
+ export * from './useVisitContextStore';
44
+ export * from './useVisitTypes';
45
+ export { useOpenmrsFetchAll, type UseServerFetchAllOptions } from './useOpenmrsFetchAll';
46
+ export { useOpenmrsInfinite, type UseServerInfiniteOptions } from './useOpenmrsInfinite';
47
+ export { useOpenmrsPagination, type UseServerPaginationOptions } from './useOpenmrsPagination';
48
+ export { useSession } from './useSession';