@openmrs/esm-styleguide 8.0.1-pre.3585 → 8.0.1-pre.3600

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 (44) hide show
  1. package/.turbo/turbo-build.log +4 -7
  2. package/dist/cards/card-header.component.d.ts +11 -0
  3. package/dist/cards/index.d.ts +1 -0
  4. package/dist/dashboard-extension/index.d.ts +5 -2
  5. package/dist/empty-card/empty-card-registration.d.ts +1 -0
  6. package/dist/empty-card/empty-card.component.d.ts +17 -0
  7. package/dist/empty-card/index.d.ts +1 -0
  8. package/dist/error-state/error-state.component.d.ts +4 -0
  9. package/dist/icons/icons.d.ts +1 -1
  10. package/dist/internal.d.ts +3 -0
  11. package/dist/openmrs-esm-styleguide.css +1 -1
  12. package/dist/openmrs-esm-styleguide.css.map +1 -1
  13. package/dist/openmrs-esm-styleguide.js +2 -2
  14. package/dist/openmrs-esm-styleguide.js.map +1 -1
  15. package/dist/pagination/index.d.ts +1 -0
  16. package/dist/pagination/pagination.component.d.ts +22 -0
  17. package/dist/public.d.ts +19 -18
  18. package/dist/snackbars/index.d.ts +1 -0
  19. package/dist/toasts/index.d.ts +1 -0
  20. package/package.json +12 -12
  21. package/src/cards/card-header.component.tsx +30 -0
  22. package/src/cards/card-header.module.scss +45 -0
  23. package/src/cards/index.ts +1 -0
  24. package/src/dashboard-extension/index.tsx +13 -3
  25. package/src/declarations.d.ts +14 -2
  26. package/src/empty-card/empty-card-registration.ts +6 -0
  27. package/src/empty-card/empty-card.component.tsx +55 -0
  28. package/src/empty-card/empty-card.module.scss +27 -0
  29. package/src/empty-card/empty-card.test.tsx +58 -0
  30. package/src/empty-card/empty-data-illustration.svg +32 -0
  31. package/src/empty-card/index.ts +1 -0
  32. package/src/error-state/error-state.component.tsx +7 -6
  33. package/src/error-state/error-state.module.scss +0 -29
  34. package/src/error-state/error-state.test.tsx +2 -2
  35. package/src/icons/icons.tsx +3 -3
  36. package/src/index.ts +5 -3
  37. package/src/internal.ts +3 -0
  38. package/src/pagination/index.ts +1 -0
  39. package/src/pagination/pagination.component.tsx +77 -0
  40. package/src/pagination/pagination.module.scss +66 -0
  41. package/src/pagination/pagination.test.tsx +72 -0
  42. package/src/public.ts +19 -18
  43. package/src/snackbars/index.tsx +2 -0
  44. package/src/toasts/index.tsx +2 -0
@@ -0,0 +1 @@
1
+ export * from './pagination.component';
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import { type PaginationProps as CarbonPaginationProps } from '@carbon/react';
3
+ export interface PaginationProps {
4
+ /** The count of current items displayed */
5
+ currentItems: number;
6
+ /** The count of total items displayed */
7
+ totalItems: number;
8
+ /** The current page number */
9
+ pageNumber: number;
10
+ /** The size of each page */
11
+ pageSize: number;
12
+ /** A callback to be called when the page changes */
13
+ onPageNumberChange?: CarbonPaginationProps['onChange'];
14
+ /** An optional URL the user should be directed to if they click on the link to see all results */
15
+ dashboardLinkUrl?: string;
16
+ /** Optional text to display instead of the default "See all" */
17
+ dashboardLinkLabel?: string;
18
+ }
19
+ /**
20
+ * Re-usable pagination bar
21
+ */
22
+ export declare const Pagination: React.FC<PaginationProps>;
package/dist/public.d.ts CHANGED
@@ -1,24 +1,25 @@
1
- export { showNotification, showActionableNotification } from './notifications';
2
- export { type NotificationDescriptor, type InlineNotificationType } from './notifications/notification.component';
3
- export { type ActionableNotificationDescriptor, type ActionableNotificationType, } from './notifications/actionable-notification.component';
4
- export { showToast } from './toasts';
5
- export { showModal } from './modals';
6
- export * from './workspaces/public';
7
- export { type ToastDescriptor, type ToastType, type ToastNotificationMeta } from './toasts/toast.component';
8
- export { showSnackbar } from './snackbars';
9
- export { type SnackbarDescriptor, type SnackbarType, type SnackbarMeta } from './snackbars/snackbar.component';
10
- export * from './left-nav';
1
+ export { type StyleguideConfigObject } from './config-schema';
2
+ export * from './cards';
3
+ export * from './custom-overflow-menu';
11
4
  export * from './dashboard-extension';
12
- export * from './error-state';
13
5
  export * from './datepicker';
14
- export * from './responsive-wrapper';
15
- export * from './patient-banner';
16
- export * from './patient-photo';
17
- export * from './custom-overflow-menu';
6
+ export * from './diagnosis-tags';
7
+ export * from './empty-card';
8
+ export * from './error-state';
18
9
  export * from './icons/icons';
10
+ export * from './left-nav';
11
+ export * from './location-picker';
12
+ export { showModal } from './modals';
13
+ export { showNotification, showActionableNotification } from './notifications';
14
+ export { type ActionableNotificationDescriptor, type ActionableNotificationType, } from './notifications/actionable-notification.component';
15
+ export { type NotificationDescriptor, type InlineNotificationType } from './notifications/notification.component';
19
16
  export * from './page-header';
17
+ export * from './pagination';
18
+ export * from './patient-banner';
19
+ export * from './patient-photo';
20
20
  export * from './pictograms/pictograms';
21
- export { type StyleguideConfigObject } from './config-schema';
22
- export * from './location-picker';
23
- export * from './diagnosis-tags';
21
+ export * from './responsive-wrapper';
22
+ export { showSnackbar, type SnackbarDescriptor, type SnackbarType, type SnackbarMeta } from './snackbars';
23
+ export { showToast, type ToastDescriptor, type ToastType, type ToastNotificationMeta } from './toasts';
24
+ export * from './workspaces/public';
24
25
  export { launchWorkspace2, launchWorkspaceGroup2, closeWorkspaceGroup2, getRegisteredWorkspace2Names, useWorkspace2Context, ActionMenuButton2, Workspace2, type Workspace2Definition, type Workspace2DefinitionProps, } from './workspaces2';
@@ -1,4 +1,5 @@
1
1
  import type { SnackbarDescriptor } from './snackbar.component';
2
+ export { type SnackbarDescriptor, type SnackbarType, type SnackbarMeta } from './snackbar.component';
2
3
  /**
3
4
  * Starts a rendering host for snack bar notifications. Should only be used by the app shell.
4
5
  * Under normal conditions there is no need to use this function.
@@ -1,4 +1,5 @@
1
1
  import type { ToastDescriptor } from './toast.component';
2
+ export { type ToastDescriptor, type ToastType, type ToastNotificationMeta } from './toast.component';
2
3
  /**
3
4
  * Starts a rendering host for toast notifications. Should only be used by the app shell.
4
5
  * Under normal conditions there is no need to use this function.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmrs/esm-styleguide",
3
- "version": "8.0.1-pre.3585",
3
+ "version": "8.0.1-pre.3600",
4
4
  "license": "MPL-2.0",
5
5
  "description": "The styleguide for OpenMRS SPA",
6
6
  "main": "dist/openmrs-esm-styleguide.js",
@@ -98,17 +98,17 @@
98
98
  "swr": "2.x"
99
99
  },
100
100
  "devDependencies": {
101
- "@openmrs/esm-api": "8.0.1-pre.3585",
102
- "@openmrs/esm-config": "8.0.1-pre.3585",
103
- "@openmrs/esm-emr-api": "8.0.1-pre.3585",
104
- "@openmrs/esm-error-handling": "8.0.1-pre.3585",
105
- "@openmrs/esm-extensions": "8.0.1-pre.3585",
106
- "@openmrs/esm-globals": "8.0.1-pre.3585",
107
- "@openmrs/esm-navigation": "8.0.1-pre.3585",
108
- "@openmrs/esm-react-utils": "8.0.1-pre.3585",
109
- "@openmrs/esm-state": "8.0.1-pre.3585",
110
- "@openmrs/esm-translations": "8.0.1-pre.3585",
111
- "@openmrs/esm-utils": "8.0.1-pre.3585",
101
+ "@openmrs/esm-api": "8.0.1-pre.3600",
102
+ "@openmrs/esm-config": "8.0.1-pre.3600",
103
+ "@openmrs/esm-emr-api": "8.0.1-pre.3600",
104
+ "@openmrs/esm-error-handling": "8.0.1-pre.3600",
105
+ "@openmrs/esm-extensions": "8.0.1-pre.3600",
106
+ "@openmrs/esm-globals": "8.0.1-pre.3600",
107
+ "@openmrs/esm-navigation": "8.0.1-pre.3600",
108
+ "@openmrs/esm-react-utils": "8.0.1-pre.3600",
109
+ "@openmrs/esm-state": "8.0.1-pre.3600",
110
+ "@openmrs/esm-translations": "8.0.1-pre.3600",
111
+ "@openmrs/esm-utils": "8.0.1-pre.3600",
112
112
  "@rspack/cli": "^1.3.11",
113
113
  "@rspack/core": "^1.3.11",
114
114
  "@types/geopattern": "^1.2.9",
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import classNames from 'classnames';
3
+ import { useLayoutType } from '@openmrs/esm-react-utils';
4
+ import styles from './card-header.module.scss';
5
+
6
+ export interface CardHeaderProps {
7
+ /** The title for this card. This must be a pre-translated string. */
8
+ title: string;
9
+ /** The contents of the card header to render if any. */
10
+ children?: React.ReactNode;
11
+ }
12
+
13
+ /**
14
+ * Re-usable header component for O3-style cards, like those found on the patient chart
15
+ */
16
+ export function CardHeader({ title, children }: CardHeaderProps) {
17
+ const isTablet = useLayoutType() === 'tablet';
18
+
19
+ return (
20
+ <div
21
+ className={classNames({
22
+ [styles.tabletHeader]: isTablet,
23
+ [styles.desktopHeader]: !isTablet,
24
+ })}
25
+ >
26
+ <h4>{title}</h4>
27
+ {children}
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,45 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '../vars' as *;
4
+
5
+ .desktopHeader,
6
+ .tabletHeader {
7
+ display: flex;
8
+ justify-content: space-between;
9
+ align-items: center;
10
+ padding: layout.$spacing-04 0 layout.$spacing-04 layout.$spacing-05;
11
+ background-color: $ui-background;
12
+
13
+ h4:after {
14
+ content: '';
15
+ display: block;
16
+ width: layout.$spacing-07;
17
+ padding-top: 0.188rem;
18
+ border-bottom: 0.375rem solid var(--brand-03);
19
+ }
20
+ }
21
+
22
+ .desktopHeader {
23
+ height: layout.$spacing-09;
24
+ h4 {
25
+ @include type.type-style('heading-compact-02');
26
+ color: $text-02;
27
+ }
28
+ }
29
+
30
+ .tabletHeader {
31
+ height: 4.5rem;
32
+ h4 {
33
+ @include type.type-style('heading-03');
34
+ color: $text-02;
35
+ }
36
+ }
37
+
38
+ // Overriding styles for RTL support
39
+ html[dir='rtl'] {
40
+ .desktopHeader,
41
+ .tabletHeader {
42
+ text-align: right;
43
+ padding: layout.$spacing-04 layout.$spacing-05 layout.$spacing-04 0;
44
+ }
45
+ }
@@ -0,0 +1 @@
1
+ export { CardHeader, type CardHeaderProps } from './card-header.component';
@@ -1,7 +1,7 @@
1
1
  import React, { useMemo } from 'react';
2
2
  import classNames from 'classnames';
3
3
  import { useTranslation } from 'react-i18next';
4
- import { useLocation } from 'react-router-dom';
4
+ import { BrowserRouter, useLocation } from 'react-router-dom';
5
5
  import { shallowEqual } from '@openmrs/esm-utils';
6
6
  import { ConfigurableLink, MaybeIcon } from '@openmrs/esm-framework';
7
7
  import { type IconId } from '../icons';
@@ -10,8 +10,8 @@ import styles from './dashboard.module.scss';
10
10
  export interface DashboardExtensionProps {
11
11
  path: string;
12
12
  title: string;
13
- basePath: string;
14
- icon: IconId;
13
+ basePath?: string;
14
+ icon?: IconId;
15
15
  }
16
16
 
17
17
  export const DashboardExtension = ({ path, title, basePath, icon }: DashboardExtensionProps) => {
@@ -49,3 +49,13 @@ export const DashboardExtension = ({ path, title, basePath, icon }: DashboardExt
49
49
  </div>
50
50
  );
51
51
  };
52
+
53
+ export function createDashboard(props: Omit<DashboardExtensionProps, 'basePath'>) {
54
+ return function ({ basePath }: { basePath: string }) {
55
+ return (
56
+ <BrowserRouter>
57
+ <DashboardExtension basePath={basePath} {...props} />
58
+ </BrowserRouter>
59
+ );
60
+ };
61
+ }
@@ -1,5 +1,17 @@
1
- declare module '*.css';
2
- declare module '*.scss';
1
+ declare module '*.css' {
2
+ interface Styles {
3
+ [key: string]: string;
4
+ }
5
+ const content: Styles;
6
+ export default content;
7
+ }
8
+ declare module '*.scss' {
9
+ interface Styles {
10
+ [key: string]: string;
11
+ }
12
+ const content: Styles;
13
+ export default content;
14
+ }
3
15
  declare module '*.svg' {
4
16
  const content: string;
5
17
  export default content;
@@ -0,0 +1,6 @@
1
+ import emptyStateIllustration from './empty-data-illustration.svg';
2
+ import { addSvg } from '../svg-utils';
3
+
4
+ export function setupEmptyCard() {
5
+ addSvg('omrs-empty-state-illustration', emptyStateIllustration);
6
+ }
@@ -0,0 +1,55 @@
1
+ import React from 'react';
2
+ import classNames from 'classnames';
3
+ import { Button, Layer, Tile } from '@carbon/react';
4
+ import { useLayoutType } from '@openmrs/esm-react-utils';
5
+ import { getCoreTranslation } from '@openmrs/esm-translations';
6
+ import { CardHeader } from '../cards';
7
+ import styles from './empty-card.module.scss';
8
+
9
+ export interface EmptyCardProps {
10
+ /** The name of the type of item that would be displayed here if not empty. This must be a pre-translated string. */
11
+ displayText: string;
12
+ /** The title to use for this empty component. This must be a pre-translated string. */
13
+ headerTitle: string;
14
+ /** A callback to invoke when the user tries to record a new item. */
15
+ launchForm?(): void;
16
+ }
17
+
18
+ export const EmptyCardIllustration = ({ width = '64', height = '64' }) => {
19
+ return (
20
+ <svg width={width} height={height} viewBox="0 0 64 64">
21
+ <use href={`#omrs-empty-data-illustration`} />
22
+ </svg>
23
+ );
24
+ };
25
+
26
+ /**
27
+ * Re-usable card for displaying an empty state
28
+ */
29
+ export const EmptyCard: React.FC<EmptyCardProps> = (props) => {
30
+ const isTablet = useLayoutType() === 'tablet';
31
+ const launchForm = props.launchForm;
32
+
33
+ return (
34
+ <Layer className={styles.layer}>
35
+ <Tile className={styles.tile}>
36
+ <CardHeader title={props.headerTitle} />
37
+ <EmptyCardIllustration />
38
+ <p className={styles.content}>
39
+ {getCoreTranslation('emptyStateText', 'There are no {{displayText}} to display', {
40
+ displayText: props.displayText,
41
+ })}
42
+ </p>
43
+ <p className={styles.action}>
44
+ {launchForm && (
45
+ <Button onClick={() => launchForm()} kind="ghost" size={isTablet ? 'lg' : 'sm'}>
46
+ {getCoreTranslation('recordNewEntry', 'Record {{ displayText }}', {
47
+ displayText: props.displayText,
48
+ })}
49
+ </Button>
50
+ )}
51
+ </p>
52
+ </Tile>
53
+ </Layer>
54
+ );
55
+ };
@@ -0,0 +1,27 @@
1
+ @use '@carbon/layout';
2
+ @use '@carbon/type';
3
+ @use '../vars' as *;
4
+
5
+ .action {
6
+ margin-bottom: layout.$spacing-03;
7
+ }
8
+
9
+ .content {
10
+ @include type.type-style('heading-compact-01');
11
+ color: $text-02;
12
+ margin-top: layout.$spacing-05;
13
+ margin-bottom: layout.$spacing-03;
14
+ }
15
+
16
+ .heading:after {
17
+ content: '';
18
+ display: block;
19
+ width: layout.$spacing-07;
20
+ padding-top: 0.188rem;
21
+ border-bottom: 0.375rem solid var(--brand-03);
22
+ }
23
+
24
+ .tile {
25
+ text-align: center;
26
+ border: 1px solid $ui-03;
27
+ }
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import { render, screen } from '@testing-library/react';
4
+ import userEvent from '@testing-library/user-event';
5
+ import { EmptyCard } from './empty-card.component';
6
+
7
+ describe('EmptyCard', () => {
8
+ const defaultProps = {
9
+ displayText: 'medications',
10
+ headerTitle: 'Medications',
11
+ };
12
+
13
+ it('renders the header title', () => {
14
+ render(<EmptyCard {...defaultProps} />);
15
+ expect(screen.getByRole('heading', { name: /medications/i })).toBeInTheDocument();
16
+ });
17
+
18
+ it('renders the empty state text with the display text', () => {
19
+ render(<EmptyCard {...defaultProps} />);
20
+ expect(screen.getByText(/there are no medications to display/i)).toBeInTheDocument();
21
+ });
22
+
23
+ it('does not render the action button when launchForm is not provided', () => {
24
+ render(<EmptyCard {...defaultProps} />);
25
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
26
+ });
27
+
28
+ it('renders the action button when launchForm is provided', () => {
29
+ const launchForm = vi.fn();
30
+ render(<EmptyCard {...defaultProps} launchForm={launchForm} />);
31
+ expect(screen.getByRole('button', { name: /record medications/i })).toBeInTheDocument();
32
+ });
33
+
34
+ it('calls launchForm when the action button is clicked', async () => {
35
+ const user = userEvent.setup();
36
+ const launchForm = vi.fn();
37
+ render(<EmptyCard {...defaultProps} launchForm={launchForm} />);
38
+
39
+ const button = screen.getByRole('button', { name: /record medications/i });
40
+ await user.click(button);
41
+
42
+ expect(launchForm).toHaveBeenCalledTimes(1);
43
+ });
44
+
45
+ it('renders with different display text', () => {
46
+ render(<EmptyCard displayText="allergies" headerTitle="Allergies" />);
47
+ expect(screen.getByRole('heading', { name: /allergies/i })).toBeInTheDocument();
48
+ expect(screen.getByText(/there are no allergies to display/i)).toBeInTheDocument();
49
+ });
50
+
51
+ it('renders the empty data illustration', () => {
52
+ render(<EmptyCard {...defaultProps} />);
53
+ // eslint-disable-next-line testing-library/no-node-access
54
+ const svg = document.querySelector('svg');
55
+ expect(svg).toBeInTheDocument();
56
+ expect(svg).toHaveAttribute('viewBox', '0 0 64 64');
57
+ });
58
+ });
@@ -0,0 +1,32 @@
1
+ <svg viewBox="0 0 64 64">
2
+ <g fill="none" fillRule="evenodd">
3
+ <path
4
+ d="M38.133 13.186H21.947c-.768.001-1.39.623-1.39 1.391V50.55l-.186.057-3.97 1.216a.743.743 0 01-.927-.493L3.664 12.751a.742.742 0 01.492-.926l6.118-1.874 17.738-5.43 6.119-1.873a.741.741 0 01.926.492L38.076 13l.057.186z"
5
+ fill="#F4F4F4"
6
+ />
7
+ <path
8
+ d="M41.664 13L38.026 1.117A1.576 1.576 0 0036.056.07l-8.601 2.633-17.737 5.43-8.603 2.634a1.578 1.578 0 00-1.046 1.97l12.436 40.616a1.58 1.58 0 001.969 1.046l5.897-1.805.185-.057v-.194l-.185.057-5.952 1.822a1.393 1.393 0 01-1.737-.923L.247 12.682a1.39 1.39 0 01.923-1.738L9.772 8.31 27.51 2.881 36.112.247a1.393 1.393 0 011.737.923L41.47 13l.057.186h.193l-.057-.185z"
9
+ fill="#8D8D8D"
10
+ />
11
+ <path
12
+ d="M11.378 11.855a.836.836 0 01-.798-.59L9.385 7.361a.835.835 0 01.554-1.042l16.318-4.996a.836.836 0 011.042.554l1.195 3.902a.836.836 0 01-.554 1.043l-16.318 4.995a.831.831 0 01-.244.037z"
13
+ fill="#C6C6C6"
14
+ />
15
+ <circle fill="#C6C6C6" cx="17.636" cy="2.314" r="1.855" />
16
+ <circle fill="#FFF" fillRule="nonzero" cx="17.636" cy="2.314" r="1.175" />
17
+ <path
18
+ d="M55.893 53.995H24.544a.79.79 0 01-.788-.789V15.644a.79.79 0 01.788-.788h31.349a.79.79 0 01.788.788v37.562a.79.79 0 01-.788.789z"
19
+ fill="#F4F4F4"
20
+ />
21
+ <path
22
+ d="M41.47 13H21.948a1.579 1.579 0 00-1.576 1.577V52.4l.185-.057V14.577c.001-.768.623-1.39 1.391-1.39h19.581L41.471 13zm17.02 0H21.947a1.579 1.579 0 00-1.576 1.577v42.478c0 .87.706 1.576 1.576 1.577H58.49a1.579 1.579 0 001.576-1.577V14.577a1.579 1.579 0 00-1.576-1.576zm1.39 44.055c0 .768-.622 1.39-1.39 1.392H21.947c-.768-.001-1.39-.624-1.39-1.392V14.577c0-.768.622-1.39 1.39-1.39H58.49c.768 0 1.39.622 1.39 1.39v42.478z"
23
+ fill="#8D8D8D"
24
+ />
25
+ <path
26
+ d="M48.751 17.082H31.686a.836.836 0 01-.835-.835v-4.081c0-.46.374-.834.835-.835H48.75c.461 0 .834.374.835.835v4.08c0 .462-.374.835-.835.836z"
27
+ fill="#C6C6C6"
28
+ />
29
+ <circle fill="#C6C6C6" cx="40.218" cy="9.755" r="1.855" />
30
+ <circle fill="#FFF" fillRule="nonzero" cx="40.218" cy="9.755" r="1.13" />
31
+ </g>
32
+ </svg>
@@ -0,0 +1 @@
1
+ export { EmptyCard, EmptyCardIllustration, type EmptyCardProps } from './empty-card.component';
@@ -1,23 +1,21 @@
1
1
  import React from 'react';
2
2
  import { Layer, Tile } from '@carbon/react';
3
3
  import { getCoreTranslation } from '@openmrs/esm-translations';
4
- import { useLayoutType } from '@openmrs/esm-react-utils';
5
4
  import styles from './error-state.module.scss';
5
+ import { CardHeader } from '../cards';
6
6
 
7
7
  export interface ErrorStateProps {
8
+ /** The error that caused this error card to be rendered. Expected to be a failed fetch result. */
8
9
  error: any;
10
+ /** The title to use for this empty component. This must be a pre-translated string. */
9
11
  headerTitle: string;
10
12
  }
11
13
 
12
14
  export const ErrorState: React.FC<ErrorStateProps> = ({ error, headerTitle }) => {
13
- const isTablet = useLayoutType() === 'tablet';
14
-
15
15
  return (
16
16
  <Layer>
17
17
  <Tile className={styles.tile}>
18
- <div className={isTablet ? styles.tabletHeading : styles.desktopHeading}>
19
- <h4>{headerTitle}</h4>
20
- </div>
18
+ <CardHeader title={headerTitle} />
21
19
  <p className={styles.errorMessage}>
22
20
  {getCoreTranslation('error', 'Error')} {`${error?.response?.status}: `}
23
21
  {error?.response?.statusText}
@@ -27,3 +25,6 @@ export const ErrorState: React.FC<ErrorStateProps> = ({ error, headerTitle }) =>
27
25
  </Layer>
28
26
  );
29
27
  };
28
+
29
+ export const ErrorCard = ErrorState;
30
+ export type ErrorCardProps = ErrorStateProps;
@@ -15,35 +15,6 @@
15
15
  color: $text-02;
16
16
  }
17
17
 
18
- .desktopHeading {
19
- h4 {
20
- @include type.type-style('heading-compact-02');
21
- color: $text-02;
22
- }
23
- }
24
-
25
- .tabletHeading {
26
- h4 {
27
- @include type.type-style('heading-03');
28
- color: $text-02;
29
- }
30
- }
31
-
32
- .desktopHeading,
33
- .tabletHeading {
34
- text-align: left;
35
- text-transform: capitalize;
36
- margin-bottom: layout.$spacing-05;
37
-
38
- h4:after {
39
- content: '';
40
- display: block;
41
- width: layout.$spacing-07;
42
- padding-top: 0.188rem;
43
- border-bottom: 0.375rem solid var(--brand-03);
44
- }
45
- }
46
-
47
18
  .tile {
48
19
  text-align: center;
49
20
  border: 1px solid $ui-03;
@@ -31,7 +31,7 @@ describe('ErrorState', () => {
31
31
 
32
32
  render(<ErrorState headerTitle="test" error={{}} />);
33
33
  // eslint-disable-next-line testing-library/no-node-access
34
- expect(screen.getByRole('heading').parentElement?.getAttribute('class')).toContain('tabletHeading');
34
+ expect(screen.getByRole('heading').parentElement?.getAttribute('class')).toContain('tabletHeader');
35
35
  });
36
36
 
37
37
  it('should render desktop layout when layout type is not tablet', () => {
@@ -39,7 +39,7 @@ describe('ErrorState', () => {
39
39
 
40
40
  render(<ErrorState headerTitle="test" error={{}} />);
41
41
  // eslint-disable-next-line testing-library/no-node-access
42
- expect(screen.getByRole('heading').parentElement?.getAttribute('class')).toContain('desktopHeading');
42
+ expect(screen.getByRole('heading').parentElement?.getAttribute('class')).toContain('desktopHeader');
43
43
  });
44
44
 
45
45
  it('should handle error with partial response data', () => {
@@ -862,18 +862,18 @@ export const ShoppingCartAddItemIcon = ShoppingCartArrowDownIcon;
862
862
  * ```
863
863
  */
864
864
  export const MaybeIcon = memo(
865
- forwardRef<SVGSVGElement, { icon: string; fallback?: React.ReactNode } & IconProps>(function MaybeIcon(
865
+ forwardRef<SVGSVGElement, { icon: string | undefined; fallback?: React.ReactNode } & IconProps>(function MaybeIcon(
866
866
  { icon, fallback, ...iconProps },
867
867
  ref,
868
868
  ) {
869
- const iconRef = useRef(document.getElementById(icon));
869
+ const iconRef = useRef(icon ? document.getElementById(icon) : undefined);
870
870
 
871
871
  useEffect(() => {
872
872
  const container = document.getElementById('omrs-svgs-container');
873
873
  const callback: MutationCallback = (mutationList) => {
874
874
  for (const mutation of mutationList) {
875
875
  if (mutation.type === 'childList') {
876
- iconRef.current = document.getElementById(icon);
876
+ iconRef.current = icon ? document.getElementById(icon) : undefined;
877
877
  }
878
878
  }
879
879
  };
package/src/index.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { defineConfigSchema } from '@openmrs/esm-config';
2
- import { setupLogo } from './logo';
3
- import { setupIcons } from './icons/icon-registration';
2
+ import { registerModal } from '@openmrs/esm-extensions';
4
3
  import { setupBranding } from './brand';
5
4
  import { esmStyleGuideSchema } from './config-schema';
5
+ import { setupEmptyCard } from './empty-card/empty-card-registration';
6
+ import { setupIcons } from './icons/icon-registration';
7
+ import { setupLogo } from './logo';
6
8
  import { setupPictograms } from './pictograms/pictogram-registration';
7
- import { registerModal } from '@openmrs/esm-extensions';
8
9
  import { getSyncLifecycle } from '@openmrs/esm-react-utils';
9
10
  import Workspace2ClosePromptModal from './workspaces2/workspace2-close-prompt.modal';
10
11
 
@@ -13,6 +14,7 @@ setupBranding();
13
14
  setupLogo();
14
15
  setupIcons();
15
16
  setupPictograms();
17
+ setupEmptyCard();
16
18
 
17
19
  registerModal({
18
20
  name: 'workspace2-close-prompt',
package/src/internal.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  export * from './breakpoints';
2
+ export * from './cards';
2
3
  export * from './config-schema';
3
4
  export * from './custom-overflow-menu';
4
5
  export * from './dashboard-extension';
5
6
  export * from './datepicker';
6
7
  export * from './diagnosis-tags';
8
+ export * from './empty-card';
7
9
  export * from './error-state';
8
10
  export * from './icons/icons';
9
11
  export * from './left-nav';
@@ -13,6 +15,7 @@ export * from './notifications';
13
15
  export * from './notifications/actionable-notification.component';
14
16
  export * from './notifications/notification.component';
15
17
  export * from './page-header';
18
+ export * from './pagination';
16
19
  export * from './patient-banner';
17
20
  export * from './patient-photo';
18
21
  export * from './pictograms/pictograms';
@@ -0,0 +1 @@
1
+ export * from './pagination.component';