@openmrs/esm-styleguide 11.0.1-pre.5825 → 11.0.1-pre.5830

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.
@@ -1,3 +1,3 @@
1
- [0] Successfully compiled: 117 files, copied 171 files with swc (257.79ms)
1
+ [0] Successfully compiled: 117 files, copied 171 files with swc (326.45ms)
2
2
  [0] swc --strip-leading-paths --copy-files src -d dist && svgo -rf dist --quiet exited with code 0
3
3
  [1] tsc --project tsconfig.build.json exited with code 0
@@ -1,5 +1,6 @@
1
1
  /** @module @category Workspace */
2
2
  import React from 'react';
3
+ import { type OpenedWindow } from '@openmrs/esm-extensions';
3
4
  export interface ActionMenuButtonProps2 {
4
5
  icon: (props: object) => JSX.Element;
5
6
  label: string;
@@ -18,6 +19,20 @@ export interface ActionMenuButtonProps2 {
18
19
  *
19
20
  */
20
21
  onBeforeWorkspaceLaunch?: () => Promise<boolean>;
22
+ /**
23
+ * An optional callback function to determine whether the action menu button
24
+ * should be disabled based on the openedWindows state of the workspace group
25
+ * @param openedWindows
26
+ * @returns true if the action menu button should be disabled and false if it should be enabled
27
+ */
28
+ disabled?: (openedWindows: Array<OpenedWindow>) => boolean;
29
+ /**
30
+ * An optional callback function to determine whether the action menu button
31
+ * should be hidden based on the openedWindows state of the workspace group
32
+ * @param openedWindows
33
+ * @returns true if the action menu button should be hidden and false if it should be shown
34
+ */
35
+ hidden?: (openedWindows: Array<OpenedWindow>) => boolean;
21
36
  }
22
37
  /**
23
38
  * The ActionMenuButton2 component is used to render a button in the action menu of a workspace group.
@@ -1 +1 @@
1
- {"version":3,"file":"action-menu-button2.component.d.ts","sourceRoot":"","sources":["../../../src/workspaces2/action-menu2/action-menu-button2.component.tsx"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,OAAO,KAAqB,MAAM,OAAO,CAAC;AA6B1C,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACtC,iBAAiB,EAAE;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACrC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACnC,CAAC;IAEF;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CA6E9D,CAAC"}
1
+ {"version":3,"file":"action-menu-button2.component.d.ts","sourceRoot":"","sources":["../../../src/workspaces2/action-menu2/action-menu-button2.component.tsx"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,OAAO,KAAqB,MAAM,OAAO,CAAC;AAK1C,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAwB5D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,GAAG,CAAC,OAAO,CAAC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;IACtC,iBAAiB,EAAE;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACrC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KACnC,CAAC;IAEF;;;;;;;OAOG;IACH,uBAAuB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjD;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC;IAE3D;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC;CAC1D;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAqF9D,CAAC"}
@@ -34,7 +34,7 @@ function Tags({ getIcon, hasUnsavedChanges, tagContent }) {
34
34
  * 2. restores the workspace window if it is opened and unfocused; or
35
35
  * 3. launches a workspace from within that window, if the window is not opened.
36
36
  *
37
- */ export const ActionMenuButton2 = ({ icon: getIcon, label, tagContent, workspaceToLaunch, onBeforeWorkspaceLaunch })=>{
37
+ */ export const ActionMenuButton2 = ({ icon: getIcon, label, tagContent, workspaceToLaunch, onBeforeWorkspaceLaunch, hidden, disabled })=>{
38
38
  const layout = useLayoutType();
39
39
  const { openedWindows, restoreWindow, hideWindow, isMostRecentlyOpenedWindowHidden } = useWorkspace2Store();
40
40
  const { extension } = useContext(ComponentContext);
@@ -60,6 +60,9 @@ function Tags({ getIcon, hasUnsavedChanges, tagContent }) {
60
60
  }
61
61
  }
62
62
  };
63
+ if (hidden?.(openedWindows)) {
64
+ return null;
65
+ }
63
66
  if (layout === 'tablet' || layout === 'phone') {
64
67
  return /*#__PURE__*/ _jsxs(Button, {
65
68
  className: classNames(styles.container, {
@@ -72,6 +75,7 @@ function Tags({ getIcon, hasUnsavedChanges, tagContent }) {
72
75
  role: "button",
73
76
  tabIndex: 0,
74
77
  size: "md",
78
+ disabled: disabled?.(openedWindows),
75
79
  children: [
76
80
  /*#__PURE__*/ _jsx("span", {
77
81
  className: styles.elementContainer,
@@ -99,6 +103,7 @@ function Tags({ getIcon, hasUnsavedChanges, tagContent }) {
99
103
  label: label,
100
104
  onClick: onClick,
101
105
  size: "md",
106
+ disabled: disabled?.(openedWindows),
102
107
  children: /*#__PURE__*/ _jsx("div", {
103
108
  className: styles.elementContainer,
104
109
  children: /*#__PURE__*/ _jsx(Tags, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-styleguide",
3
- "version": "11.0.1-pre.5825",
3
+ "version": "11.0.1-pre.5830",
4
4
  "license": "MPL-2.0",
5
5
  "description": "The styleguide for OpenMRS SPA",
6
6
  "module": "dist/internal.js",
@@ -79,18 +79,18 @@
79
79
  "uuid": "^11.1.1"
80
80
  },
81
81
  "peerDependencies": {
82
- "@openmrs/esm-api": "^11.0.1-pre.5825",
83
- "@openmrs/esm-config": "^11.0.1-pre.5825",
84
- "@openmrs/esm-emr-api": "^11.0.1-pre.5825",
85
- "@openmrs/esm-error-handling": "^11.0.1-pre.5825",
86
- "@openmrs/esm-extensions": "^11.0.1-pre.5825",
87
- "@openmrs/esm-globals": "^11.0.1-pre.5825",
88
- "@openmrs/esm-navigation": "^11.0.1-pre.5825",
89
- "@openmrs/esm-react-utils": "^11.0.1-pre.5825",
90
- "@openmrs/esm-routes": "^11.0.1-pre.5825",
91
- "@openmrs/esm-state": "^11.0.1-pre.5825",
92
- "@openmrs/esm-translations": "^11.0.1-pre.5825",
93
- "@openmrs/esm-utils": "^11.0.1-pre.5825",
82
+ "@openmrs/esm-api": "^11.0.1-pre.5830",
83
+ "@openmrs/esm-config": "^11.0.1-pre.5830",
84
+ "@openmrs/esm-emr-api": "^11.0.1-pre.5830",
85
+ "@openmrs/esm-error-handling": "^11.0.1-pre.5830",
86
+ "@openmrs/esm-extensions": "^11.0.1-pre.5830",
87
+ "@openmrs/esm-globals": "^11.0.1-pre.5830",
88
+ "@openmrs/esm-navigation": "^11.0.1-pre.5830",
89
+ "@openmrs/esm-react-utils": "^11.0.1-pre.5830",
90
+ "@openmrs/esm-routes": "^11.0.1-pre.5830",
91
+ "@openmrs/esm-state": "^11.0.1-pre.5830",
92
+ "@openmrs/esm-translations": "^11.0.1-pre.5830",
93
+ "@openmrs/esm-utils": "^11.0.1-pre.5830",
94
94
  "dayjs": "1.x",
95
95
  "i18next": "25.x",
96
96
  "react": "18.x",
@@ -99,18 +99,18 @@
99
99
  "swr": "2.x"
100
100
  },
101
101
  "devDependencies": {
102
- "@openmrs/esm-api": "11.0.1-pre.5825",
103
- "@openmrs/esm-config": "11.0.1-pre.5825",
104
- "@openmrs/esm-emr-api": "11.0.1-pre.5825",
105
- "@openmrs/esm-error-handling": "11.0.1-pre.5825",
106
- "@openmrs/esm-extensions": "11.0.1-pre.5825",
107
- "@openmrs/esm-globals": "11.0.1-pre.5825",
108
- "@openmrs/esm-navigation": "11.0.1-pre.5825",
109
- "@openmrs/esm-react-utils": "11.0.1-pre.5825",
110
- "@openmrs/esm-routes": "11.0.1-pre.5825",
111
- "@openmrs/esm-state": "11.0.1-pre.5825",
112
- "@openmrs/esm-translations": "11.0.1-pre.5825",
113
- "@openmrs/esm-utils": "11.0.1-pre.5825",
102
+ "@openmrs/esm-api": "11.0.1-pre.5830",
103
+ "@openmrs/esm-config": "11.0.1-pre.5830",
104
+ "@openmrs/esm-emr-api": "11.0.1-pre.5830",
105
+ "@openmrs/esm-error-handling": "11.0.1-pre.5830",
106
+ "@openmrs/esm-extensions": "11.0.1-pre.5830",
107
+ "@openmrs/esm-globals": "11.0.1-pre.5830",
108
+ "@openmrs/esm-navigation": "11.0.1-pre.5830",
109
+ "@openmrs/esm-react-utils": "11.0.1-pre.5830",
110
+ "@openmrs/esm-routes": "11.0.1-pre.5830",
111
+ "@openmrs/esm-state": "11.0.1-pre.5830",
112
+ "@openmrs/esm-translations": "11.0.1-pre.5830",
113
+ "@openmrs/esm-utils": "11.0.1-pre.5830",
114
114
  "@swc/cli": "0.8.1",
115
115
  "@swc/core": "1.15.21",
116
116
  "@types/geopattern": "^1.2.9",
@@ -47,6 +47,22 @@ export interface ActionMenuButtonProps2 {
47
47
  *
48
48
  */
49
49
  onBeforeWorkspaceLaunch?: () => Promise<boolean>;
50
+
51
+ /**
52
+ * An optional callback function to determine whether the action menu button
53
+ * should be disabled based on the openedWindows state of the workspace group
54
+ * @param openedWindows
55
+ * @returns true if the action menu button should be disabled and false if it should be enabled
56
+ */
57
+ disabled?: (openedWindows: Array<OpenedWindow>) => boolean;
58
+
59
+ /**
60
+ * An optional callback function to determine whether the action menu button
61
+ * should be hidden based on the openedWindows state of the workspace group
62
+ * @param openedWindows
63
+ * @returns true if the action menu button should be hidden and false if it should be shown
64
+ */
65
+ hidden?: (openedWindows: Array<OpenedWindow>) => boolean;
50
66
  }
51
67
 
52
68
  /**
@@ -69,6 +85,8 @@ export const ActionMenuButton2: React.FC<ActionMenuButtonProps2> = ({
69
85
  tagContent,
70
86
  workspaceToLaunch,
71
87
  onBeforeWorkspaceLaunch,
88
+ hidden,
89
+ disabled,
72
90
  }) => {
73
91
  const layout = useLayoutType();
74
92
  const { openedWindows, restoreWindow, hideWindow, isMostRecentlyOpenedWindowHidden } = useWorkspace2Store();
@@ -99,6 +117,10 @@ export const ActionMenuButton2: React.FC<ActionMenuButtonProps2> = ({
99
117
  }
100
118
  };
101
119
 
120
+ if (hidden?.(openedWindows)) {
121
+ return null;
122
+ }
123
+
102
124
  if (layout === 'tablet' || layout === 'phone') {
103
125
  return (
104
126
  <Button
@@ -112,6 +134,7 @@ export const ActionMenuButton2: React.FC<ActionMenuButtonProps2> = ({
112
134
  role="button"
113
135
  tabIndex={0}
114
136
  size="md"
137
+ disabled={disabled?.(openedWindows)}
115
138
  >
116
139
  <span className={styles.elementContainer}>
117
140
  <Tags hasUnsavedChanges={hasUnsavedChanges} getIcon={getIcon} tagContent={tagContent} />
@@ -134,6 +157,7 @@ export const ActionMenuButton2: React.FC<ActionMenuButtonProps2> = ({
134
157
  label={label}
135
158
  onClick={onClick}
136
159
  size="md"
160
+ disabled={disabled?.(openedWindows)}
137
161
  >
138
162
  <div className={styles.elementContainer}>
139
163
  <Tags hasUnsavedChanges={hasUnsavedChanges} getIcon={getIcon} tagContent={tagContent} />
@@ -0,0 +1,94 @@
1
+ import React from 'react';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { render, screen } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import { ComponentContext, useLayoutType } from '@openmrs/esm-react-utils';
6
+ import { type OpenedWindow } from '@openmrs/esm-extensions';
7
+ import { launchWorkspace2, useWorkspace2Store } from '../workspace2';
8
+ import { ActionMenuButton2 } from './action-menu-button2.component';
9
+
10
+ vi.mock('../workspace2', () => ({
11
+ launchWorkspace2: vi.fn(),
12
+ useWorkspace2Store: vi.fn(),
13
+ }));
14
+
15
+ vi.mock('@openmrs/esm-react-utils', async () => ({
16
+ ...(await vi.importActual<object>('@openmrs/esm-react-utils')),
17
+ useLayoutType: vi.fn(),
18
+ }));
19
+
20
+ const mockUseLayoutType = vi.mocked(useLayoutType);
21
+ const mockUseWorkspace2Store = vi.mocked(useWorkspace2Store);
22
+ const mockLaunchWorkspace2 = vi.mocked(launchWorkspace2);
23
+
24
+ const mockHideWindow = vi.fn();
25
+
26
+ const openedWindows = [{ windowName: 'test-window', openedWorkspaces: [] }] as unknown as Array<OpenedWindow>;
27
+
28
+ function renderButton(props: Partial<React.ComponentProps<typeof ActionMenuButton2>> = {}) {
29
+ return render(
30
+ <ComponentContext.Provider value={{ extension: { extensionId: 'test-window' } } as any}>
31
+ <ActionMenuButton2
32
+ icon={() => <svg data-testid="icon" />}
33
+ label="Test button"
34
+ workspaceToLaunch={{ workspaceName: 'test-workspace' }}
35
+ {...props}
36
+ />
37
+ </ComponentContext.Provider>,
38
+ );
39
+ }
40
+
41
+ describe('ActionMenuButton2 hidden and disabled', () => {
42
+ beforeEach(() => {
43
+ mockUseLayoutType.mockReturnValue('small-desktop');
44
+ mockUseWorkspace2Store.mockReturnValue({
45
+ openedWindows,
46
+ restoreWindow: vi.fn(),
47
+ hideWindow: mockHideWindow,
48
+ isMostRecentlyOpenedWindowHidden: false,
49
+ } as any);
50
+ });
51
+
52
+ it('renders an enabled button by default', () => {
53
+ renderButton();
54
+ expect(screen.getByRole('button')).toBeEnabled();
55
+ });
56
+
57
+ it('renders nothing when hidden returns true, passing openedWindows', () => {
58
+ const hidden = vi.fn().mockReturnValue(true);
59
+ renderButton({ hidden });
60
+ expect(hidden).toHaveBeenCalledWith(openedWindows);
61
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
62
+ });
63
+
64
+ it('renders the button when hidden returns false', () => {
65
+ renderButton({ hidden: () => false });
66
+ expect(screen.getByRole('button')).toBeInTheDocument();
67
+ });
68
+
69
+ it('disables the button when disabled returns true, passing openedWindows', async () => {
70
+ const disabled = vi.fn().mockReturnValue(true);
71
+ renderButton({ disabled });
72
+ expect(disabled).toHaveBeenCalledWith(openedWindows);
73
+ const button = screen.getByRole('button');
74
+ expect(button).toBeDisabled();
75
+ await userEvent.click(button);
76
+ expect(mockLaunchWorkspace2).not.toHaveBeenCalled();
77
+ expect(mockHideWindow).not.toHaveBeenCalled();
78
+ });
79
+
80
+ it('keeps the button enabled when disabled returns false', () => {
81
+ renderButton({ disabled: () => false });
82
+ expect(screen.getByRole('button')).toBeEnabled();
83
+ });
84
+
85
+ it('supports hidden and disabled on tablet layout', () => {
86
+ mockUseLayoutType.mockReturnValue('tablet');
87
+ const { unmount } = renderButton({ disabled: () => true });
88
+ expect(screen.getByRole('button')).toBeDisabled();
89
+ unmount();
90
+
91
+ renderButton({ hidden: () => true });
92
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
93
+ });
94
+ });