@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.
- package/.turbo/turbo-build.log +4 -7
- package/dist/cards/card-header.component.d.ts +11 -0
- package/dist/cards/index.d.ts +1 -0
- package/dist/dashboard-extension/index.d.ts +5 -2
- package/dist/empty-card/empty-card-registration.d.ts +1 -0
- package/dist/empty-card/empty-card.component.d.ts +17 -0
- package/dist/empty-card/index.d.ts +1 -0
- package/dist/error-state/error-state.component.d.ts +4 -0
- package/dist/icons/icons.d.ts +1 -1
- package/dist/internal.d.ts +3 -0
- package/dist/openmrs-esm-styleguide.css +1 -1
- package/dist/openmrs-esm-styleguide.css.map +1 -1
- package/dist/openmrs-esm-styleguide.js +2 -2
- package/dist/openmrs-esm-styleguide.js.map +1 -1
- package/dist/pagination/index.d.ts +1 -0
- package/dist/pagination/pagination.component.d.ts +22 -0
- package/dist/public.d.ts +19 -18
- package/dist/snackbars/index.d.ts +1 -0
- package/dist/toasts/index.d.ts +1 -0
- package/package.json +12 -12
- package/src/cards/card-header.component.tsx +30 -0
- package/src/cards/card-header.module.scss +45 -0
- package/src/cards/index.ts +1 -0
- package/src/dashboard-extension/index.tsx +13 -3
- package/src/declarations.d.ts +14 -2
- package/src/empty-card/empty-card-registration.ts +6 -0
- package/src/empty-card/empty-card.component.tsx +55 -0
- package/src/empty-card/empty-card.module.scss +27 -0
- package/src/empty-card/empty-card.test.tsx +58 -0
- package/src/empty-card/empty-data-illustration.svg +32 -0
- package/src/empty-card/index.ts +1 -0
- package/src/error-state/error-state.component.tsx +7 -6
- package/src/error-state/error-state.module.scss +0 -29
- package/src/error-state/error-state.test.tsx +2 -2
- package/src/icons/icons.tsx +3 -3
- package/src/index.ts +5 -3
- package/src/internal.ts +3 -0
- package/src/pagination/index.ts +1 -0
- package/src/pagination/pagination.component.tsx +77 -0
- package/src/pagination/pagination.module.scss +66 -0
- package/src/pagination/pagination.test.tsx +72 -0
- package/src/public.ts +19 -18
- package/src/snackbars/index.tsx +2 -0
- package/src/toasts/index.tsx +2 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { Pagination as CarbonPagination, type PaginationProps as CarbonPaginationProps } from '@carbon/react';
|
|
4
|
+
import { ConfigurableLink, useLayoutType, usePaginationInfo } from '@openmrs/esm-react-utils';
|
|
5
|
+
import { getCoreTranslation } from '@openmrs/esm-translations';
|
|
6
|
+
import styles from './pagination.module.scss';
|
|
7
|
+
|
|
8
|
+
export interface PaginationProps {
|
|
9
|
+
/** The count of current items displayed */
|
|
10
|
+
currentItems: number;
|
|
11
|
+
/** The count of total items displayed */
|
|
12
|
+
totalItems: number;
|
|
13
|
+
/** The current page number */
|
|
14
|
+
pageNumber: number;
|
|
15
|
+
/** The size of each page */
|
|
16
|
+
pageSize: number;
|
|
17
|
+
/** A callback to be called when the page changes */
|
|
18
|
+
onPageNumberChange?: CarbonPaginationProps['onChange'];
|
|
19
|
+
/** An optional URL the user should be directed to if they click on the link to see all results */
|
|
20
|
+
dashboardLinkUrl?: string;
|
|
21
|
+
/** Optional text to display instead of the default "See all" */
|
|
22
|
+
dashboardLinkLabel?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Re-usable pagination bar
|
|
27
|
+
*/
|
|
28
|
+
export const Pagination: React.FC<PaginationProps> = ({
|
|
29
|
+
totalItems,
|
|
30
|
+
pageSize,
|
|
31
|
+
onPageNumberChange,
|
|
32
|
+
pageNumber,
|
|
33
|
+
dashboardLinkUrl,
|
|
34
|
+
currentItems,
|
|
35
|
+
dashboardLinkLabel: urlLabel,
|
|
36
|
+
}) => {
|
|
37
|
+
const { pageSizes, pageItemsCount } = usePaginationInfo(pageSize, totalItems, pageNumber, currentItems);
|
|
38
|
+
const isTablet = useLayoutType() === 'tablet';
|
|
39
|
+
const itemsDisplayed = getCoreTranslation('paginationItemsCount', '{{pageItemsCount}} / {{totalItems}} items', {
|
|
40
|
+
totalItems,
|
|
41
|
+
pageItemsCount,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
{totalItems > 0 && (
|
|
47
|
+
<div
|
|
48
|
+
className={classNames({
|
|
49
|
+
[styles.tablet]: isTablet,
|
|
50
|
+
[styles.desktop]: !isTablet,
|
|
51
|
+
})}
|
|
52
|
+
>
|
|
53
|
+
<div>
|
|
54
|
+
{itemsDisplayed}
|
|
55
|
+
{dashboardLinkUrl && (
|
|
56
|
+
<ConfigurableLink to={dashboardLinkUrl} className={styles.configurableLink}>
|
|
57
|
+
{urlLabel ?? getCoreTranslation('seeAll', 'See all')}
|
|
58
|
+
</ConfigurableLink>
|
|
59
|
+
)}
|
|
60
|
+
</div>
|
|
61
|
+
<CarbonPagination
|
|
62
|
+
className={styles.pagination}
|
|
63
|
+
page={pageNumber}
|
|
64
|
+
pageSize={pageSize}
|
|
65
|
+
pageSizes={pageSizes}
|
|
66
|
+
totalItems={totalItems}
|
|
67
|
+
onChange={onPageNumberChange}
|
|
68
|
+
pageRangeText={(_, total) =>
|
|
69
|
+
getCoreTranslation('paginationOfPages', 'of {{count}} pages', { count: total })
|
|
70
|
+
}
|
|
71
|
+
size={isTablet ? 'lg' : 'sm'}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
75
|
+
</>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
@use '../vars' as *;
|
|
4
|
+
|
|
5
|
+
.bodyShort01 {
|
|
6
|
+
@include type.type-style('body-compact-01');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.desktop,
|
|
10
|
+
.tablet {
|
|
11
|
+
@include type.type-style('body-compact-01');
|
|
12
|
+
display: flex;
|
|
13
|
+
justify-content: space-between;
|
|
14
|
+
color: $text-02;
|
|
15
|
+
background-color: $ui-02;
|
|
16
|
+
padding-left: layout.$spacing-05;
|
|
17
|
+
align-items: center;
|
|
18
|
+
border-top: 1px solid $ui-03;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.desktop :global(.cds--pagination) {
|
|
22
|
+
min-height: 0;
|
|
23
|
+
height: layout.$spacing-07;
|
|
24
|
+
width: auto;
|
|
25
|
+
border: none;
|
|
26
|
+
|
|
27
|
+
& :global(.cds--select-input),
|
|
28
|
+
:global(.cds--btn),
|
|
29
|
+
:global(.cds--pagination__right) {
|
|
30
|
+
min-height: 0;
|
|
31
|
+
height: layout.$spacing-07;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.tablet :global(.cds--pagination) {
|
|
36
|
+
min-height: 0;
|
|
37
|
+
height: layout.$spacing-09;
|
|
38
|
+
width: auto;
|
|
39
|
+
border: none;
|
|
40
|
+
|
|
41
|
+
& :global(.cds--select-input),
|
|
42
|
+
:global(.cds--btn),
|
|
43
|
+
:global(.cds--pagination__right) {
|
|
44
|
+
min-height: 0;
|
|
45
|
+
height: layout.$spacing-09;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.configurableLink {
|
|
50
|
+
text-decoration: none;
|
|
51
|
+
@extend .bodyShort01;
|
|
52
|
+
padding: 0 layout.$spacing-03;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.pagination {
|
|
56
|
+
@include type.type-style('body-compact-01');
|
|
57
|
+
background-color: $ui-02;
|
|
58
|
+
color: $text-02;
|
|
59
|
+
display: flex;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
div.pagination {
|
|
63
|
+
& > :global(.cds--pagination__left) {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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 { Pagination } from './pagination.component';
|
|
6
|
+
|
|
7
|
+
describe('Pagination', () => {
|
|
8
|
+
const defaultProps = {
|
|
9
|
+
currentItems: 10,
|
|
10
|
+
totalItems: 100,
|
|
11
|
+
pageNumber: 1,
|
|
12
|
+
pageSize: 10,
|
|
13
|
+
onPageNumberChange: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
it('renders nothing when totalItems is 0', () => {
|
|
17
|
+
const { container } = render(<Pagination {...defaultProps} totalItems={0} />);
|
|
18
|
+
expect(container).toBeEmptyDOMElement();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('renders pagination when totalItems is greater than 0', () => {
|
|
22
|
+
render(<Pagination {...defaultProps} />);
|
|
23
|
+
expect(screen.getByText(/10 \/ 100 items/i)).toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('displays correct items count for the first page', () => {
|
|
27
|
+
render(<Pagination {...defaultProps} pageNumber={1} currentItems={10} />);
|
|
28
|
+
expect(screen.getByText(/10 \/ 100 items/i)).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('displays correct items count for a middle page', () => {
|
|
32
|
+
render(<Pagination {...defaultProps} pageNumber={5} currentItems={10} />);
|
|
33
|
+
expect(screen.getByText(/50 \/ 100 items/i)).toBeInTheDocument();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('displays correct items count for the last page with fewer items', () => {
|
|
37
|
+
render(<Pagination {...defaultProps} totalItems={95} pageNumber={10} currentItems={5} />);
|
|
38
|
+
expect(screen.getByText(/95 \/ 95 items/i)).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders ConfigurableLink when dashboardLinkUrl is provided', () => {
|
|
42
|
+
render(<Pagination {...defaultProps} dashboardLinkUrl="/dashboard" />);
|
|
43
|
+
expect(screen.getByRole('link', { name: /see all/i })).toBeInTheDocument();
|
|
44
|
+
expect(screen.getByRole('link', { name: /see all/i })).toHaveAttribute('href', '/dashboard');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('uses custom label when dashboardLinkLabel is provided', () => {
|
|
48
|
+
render(<Pagination {...defaultProps} dashboardLinkUrl="/dashboard" dashboardLinkLabel="View all items" />);
|
|
49
|
+
expect(screen.getByRole('link', { name: /view all items/i })).toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('does not render ConfigurableLink when dashboardLinkUrl is not provided', () => {
|
|
53
|
+
render(<Pagination {...defaultProps} />);
|
|
54
|
+
expect(screen.queryByRole('link')).not.toBeInTheDocument();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('calls onPageNumberChange when page changes', async () => {
|
|
58
|
+
const user = userEvent.setup();
|
|
59
|
+
const onPageNumberChange = vi.fn();
|
|
60
|
+
render(<Pagination {...defaultProps} onPageNumberChange={onPageNumberChange} />);
|
|
61
|
+
|
|
62
|
+
const nextButton = screen.getByRole('button', { name: /next/i });
|
|
63
|
+
await user.click(nextButton);
|
|
64
|
+
|
|
65
|
+
expect(onPageNumberChange).toHaveBeenCalled();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('handles case when pageSize is greater than totalItems', () => {
|
|
69
|
+
render(<Pagination {...defaultProps} pageSize={50} totalItems={30} currentItems={30} />);
|
|
70
|
+
expect(screen.getByText(/30 \/ 30 items/i)).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
});
|
package/src/public.ts
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
+
export { type StyleguideConfigObject } from './config-schema';
|
|
2
|
+
export * from './cards';
|
|
3
|
+
export * from './custom-overflow-menu';
|
|
4
|
+
export * from './dashboard-extension';
|
|
5
|
+
export * from './datepicker';
|
|
6
|
+
export * from './diagnosis-tags';
|
|
7
|
+
export * from './empty-card';
|
|
8
|
+
export * from './error-state';
|
|
9
|
+
export * from './icons/icons';
|
|
10
|
+
export * from './left-nav';
|
|
11
|
+
export * from './location-picker';
|
|
12
|
+
export { showModal } from './modals';
|
|
1
13
|
export { showNotification, showActionableNotification } from './notifications';
|
|
2
|
-
export { type NotificationDescriptor, type InlineNotificationType } from './notifications/notification.component';
|
|
3
14
|
export {
|
|
4
15
|
type ActionableNotificationDescriptor,
|
|
5
16
|
type ActionableNotificationType,
|
|
6
17
|
} from './notifications/actionable-notification.component';
|
|
7
|
-
export {
|
|
8
|
-
export
|
|
9
|
-
export * from './
|
|
10
|
-
export { type ToastDescriptor, type ToastType, type ToastNotificationMeta } from './toasts/toast.component';
|
|
11
|
-
export { showSnackbar } from './snackbars';
|
|
12
|
-
export { type SnackbarDescriptor, type SnackbarType, type SnackbarMeta } from './snackbars/snackbar.component';
|
|
13
|
-
export * from './left-nav';
|
|
14
|
-
export * from './dashboard-extension';
|
|
15
|
-
export * from './error-state';
|
|
16
|
-
export * from './datepicker';
|
|
17
|
-
export * from './responsive-wrapper';
|
|
18
|
+
export { type NotificationDescriptor, type InlineNotificationType } from './notifications/notification.component';
|
|
19
|
+
export * from './page-header';
|
|
20
|
+
export * from './pagination';
|
|
18
21
|
export * from './patient-banner';
|
|
19
22
|
export * from './patient-photo';
|
|
20
|
-
export * from './custom-overflow-menu';
|
|
21
|
-
export * from './icons/icons';
|
|
22
|
-
export * from './page-header';
|
|
23
23
|
export * from './pictograms/pictograms';
|
|
24
|
-
export
|
|
25
|
-
export
|
|
26
|
-
export
|
|
24
|
+
export * from './responsive-wrapper';
|
|
25
|
+
export { showSnackbar, type SnackbarDescriptor, type SnackbarType, type SnackbarMeta } from './snackbars';
|
|
26
|
+
export { showToast, type ToastDescriptor, type ToastType, type ToastNotificationMeta } from './toasts';
|
|
27
|
+
export * from './workspaces/public';
|
|
27
28
|
export {
|
|
28
29
|
launchWorkspace2,
|
|
29
30
|
launchWorkspaceGroup2,
|
package/src/snackbars/index.tsx
CHANGED
|
@@ -6,6 +6,8 @@ import { Subject } from 'rxjs';
|
|
|
6
6
|
import type { SnackbarDescriptor, SnackbarMeta } from './snackbar.component';
|
|
7
7
|
import ActiveSnackbars from './active-snackbar.component';
|
|
8
8
|
|
|
9
|
+
export { type SnackbarDescriptor, type SnackbarType, type SnackbarMeta } from './snackbar.component';
|
|
10
|
+
|
|
9
11
|
const snackbarsSubject = new Subject<SnackbarMeta>();
|
|
10
12
|
let snackbarId = 0;
|
|
11
13
|
|
package/src/toasts/index.tsx
CHANGED
|
@@ -6,6 +6,8 @@ import type { ToastDescriptor, ToastNotificationMeta } from './toast.component';
|
|
|
6
6
|
import ActiveToasts from './active-toasts.component';
|
|
7
7
|
import isEmpty from 'lodash-es/isEmpty';
|
|
8
8
|
|
|
9
|
+
export { type ToastDescriptor, type ToastType, type ToastNotificationMeta } from './toast.component';
|
|
10
|
+
|
|
9
11
|
const toastsSubject = new Subject<ToastNotificationMeta>();
|
|
10
12
|
let toastId = 0;
|
|
11
13
|
|