@purpurds/pagination 5.19.1
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/dist/LICENSE.txt +73 -0
- package/dist/navigation.d.ts +2 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/pagination-page-selector.d.ts +17 -0
- package/dist/pagination-page-selector.d.ts.map +1 -0
- package/dist/pagination-page-size-selector.d.ts +13 -0
- package/dist/pagination-page-size-selector.d.ts.map +1 -0
- package/dist/pagination-page-trigger.d.ts +14 -0
- package/dist/pagination-page-trigger.d.ts.map +1 -0
- package/dist/pagination-pages.d.ts +13 -0
- package/dist/pagination-pages.d.ts.map +1 -0
- package/dist/pagination-step-trigger.d.ts +14 -0
- package/dist/pagination-step-trigger.d.ts.map +1 -0
- package/dist/pagination-truncation-separator.d.ts +11 -0
- package/dist/pagination-truncation-separator.d.ts.map +1 -0
- package/dist/pagination.cjs.js +134 -0
- package/dist/pagination.cjs.js.map +1 -0
- package/dist/pagination.d.ts +24 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.es.js +4041 -0
- package/dist/pagination.es.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/use-page-options.hook.d.ts +8 -0
- package/dist/use-page-options.hook.d.ts.map +1 -0
- package/dist/use-page-size-options.hook.d.ts +8 -0
- package/dist/use-page-size-options.hook.d.ts.map +1 -0
- package/dist/use-pagination-page-selector-events.hook.d.ts +10 -0
- package/dist/use-pagination-page-selector-events.hook.d.ts.map +1 -0
- package/dist/use-pagination-pages.hook.d.ts +7 -0
- package/dist/use-pagination-pages.hook.d.ts.map +1 -0
- package/package.json +69 -0
- package/src/global.d.ts +4 -0
- package/src/navigation.ts +3 -0
- package/src/pagination-page-selector.module.scss +26 -0
- package/src/pagination-page-selector.test.tsx +78 -0
- package/src/pagination-page-selector.tsx +105 -0
- package/src/pagination-page-size-selector.module.scss +34 -0
- package/src/pagination-page-size-selector.test.tsx +73 -0
- package/src/pagination-page-size-selector.tsx +78 -0
- package/src/pagination-page-trigger.module.scss +41 -0
- package/src/pagination-page-trigger.test.tsx +172 -0
- package/src/pagination-page-trigger.tsx +93 -0
- package/src/pagination-pages.module.scss +8 -0
- package/src/pagination-pages.test.tsx +95 -0
- package/src/pagination-pages.tsx +72 -0
- package/src/pagination-step-trigger.module.scss +27 -0
- package/src/pagination-step-trigger.test.tsx +106 -0
- package/src/pagination-step-trigger.tsx +92 -0
- package/src/pagination-truncation-separator.module.scss +8 -0
- package/src/pagination-truncation-separator.test.tsx +25 -0
- package/src/pagination-truncation-separator.tsx +29 -0
- package/src/pagination.module.scss +105 -0
- package/src/pagination.stories.tsx +197 -0
- package/src/pagination.test.tsx +76 -0
- package/src/pagination.tsx +177 -0
- package/src/types.ts +43 -0
- package/src/use-page-options.hook.ts +21 -0
- package/src/use-page-size-options.hook.ts +21 -0
- package/src/use-pagination-page-selector-events.hook.ts +59 -0
- package/src/use-pagination-pages.hook.ts +41 -0
package/dist/styles.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._purpur-pagination_9shz4_1{align-items:center;display:flex;flex-direction:column-reverse;gap:var(--purpur-spacing-300)}@media screen and (min-width: 1024px){._purpur-pagination_9shz4_1{align-items:center;display:grid;gap:var(--purpur-spacing-100);grid-template-areas:"pagesize pagination empty";grid-template-columns:1fr 3fr 1fr}}._purpur-pagination__page-size-select-container_9shz4_16{flex:0 0 auto;width:100%}@media screen and (min-width: 1024px){._purpur-pagination__page-size-select-container_9shz4_16{grid-area:pagesize;width:auto}}._purpur-pagination__pagination-container_9shz4_26{align-items:center;display:inline-flex;gap:var(--purpur-spacing-200);margin:0 auto;max-width:calc(3 * var(--purpur-spacing-1200));width:100%}@media screen and (min-width: 600px){._purpur-pagination__pagination-container_9shz4_26{gap:var(--purpur-spacing-400);max-width:none;width:auto}}@media screen and (min-width: 1024px){._purpur-pagination__pagination-container_9shz4_26{grid-area:pagination;justify-self:center}}._purpur-pagination__step-trigger-label_9shz4_47{border:0;clip:rect(0,0,0,0);display:block;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}@media screen and (min-width: 1024px){._purpur-pagination__step-trigger-label_9shz4_47{clip:auto;display:inline;height:auto;margin:0;overflow:visible;position:static;white-space:normal;width:auto}}._purpur-pagination__step-trigger_9shz4_47{flex:0 0 auto}._purpur-pagination__page-trigger-container_9shz4_74{display:flex;flex:1 1 auto;justify-content:center}._purpur-pagination_9shz4_1 ._purpur-pagination__pages_9shz4_79{display:none}._purpur-pagination_9shz4_1 ._purpur-pagination__pages--visible_9shz4_82{display:flex}@media screen and (min-width: 600px){._purpur-pagination_9shz4_1 ._purpur-pagination__pages_9shz4_79{display:flex}}._purpur-pagination_9shz4_1 ._purpur-pagination__page-selector_9shz4_90{display:none}._purpur-pagination_9shz4_1 ._purpur-pagination__page-selector--visible_9shz4_93{display:flex}@media screen and (min-width: 600px){._purpur-pagination_9shz4_1 ._purpur-pagination__page-selector_9shz4_90{display:none}}._purpur-pagination-page-selector_1ca14_1{align-items:center;display:flex;gap:var(--purpur-spacing-150)}._purpur-pagination-page-selector__autocomplete_1ca14_6{max-width:var(--purpur-spacing-1000);width:100%}._purpur-pagination-page-selector__input_1ca14_10 input[type=number]{-moz-appearance:textfield}._purpur-pagination-page-selector__input_1ca14_10 input[type=number]::-webkit-outer-spin-button,._purpur-pagination-page-selector__input_1ca14_10 input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}._purpur-pagination-page-selector__of-total-pages-label_1ca14_18{flex:0 0 auto}._purpur-pagination-page-size-selector_l9us8_1{align-items:center;display:flex;gap:var(--purpur-spacing-150);justify-content:center}@media screen and (min-width: 1024px){._purpur-pagination-page-size-selector_l9us8_1{justify-content:flex-start}}._purpur-pagination-page-size-selector__select_l9us8_12{flex:1 0 var(--purpur-spacing-1000);max-width:var(--purpur-spacing-1000);width:100%}._purpur-pagination-page-size-selector_l9us8_1 ._purpur-pagination-page-size-selector__items-per-page-label_l9us8_17{flex:0 1 auto;display:block;font-weight:var(--purpur-typography-weight-normal);-webkit-hyphens:none;hyphens:none;line-height:var(--purpur-typography-line-height-loose);margin:0;overflow:hidden;text-overflow:ellipsis}._purpur-pagination-page-size-selector_l9us8_1 ._purpur-pagination-page-size-selector__items-per-page-label-text_l9us8_27{white-space:nowrap}._purpur-pagination-page-trigger_1gni9_1{display:block}._purpur-pagination-page-trigger__trigger-item_1gni9_4{align-items:center;border-radius:var(--purpur-border-radius-full);border-width:0;cursor:pointer;display:inline-flex;font-size:var(--purpur-typography-scale-100);font-family:var(--purpur-typography-family-default);font-weight:var(--purpur-typography-weight-medium);gap:var(--purpur-spacing-100);justify-content:center;line-height:var(--purpur-spacing-300);outline:0;position:relative;text-decoration:none;transition:all var(--purpur-motion-duration-100) ease;width:auto}._purpur-pagination-page-trigger__trigger-item_1gni9_4:focus:before{border-radius:var(--purpur-border-radius-full);box-shadow:0 0 0 var(--purpur-border-width-sm) var(--purpur-color-border-interactive-focus);content:"";display:block;inset:calc(var(--purpur-spacing-25) * -1);position:absolute}._purpur-pagination-page-trigger__trigger-item_1gni9_4:focus:not(:focus-visible):before{box-shadow:none}._purpur-pagination-page-trigger__trigger-item_1gni9_4 svg{display:block}._purpur-pagination-page-trigger__trigger-item--sm_1gni9_36{padding:var(--purpur-spacing-100) var(--purpur-spacing-250)}._purpur-pagination-page-trigger__trigger-item--sm_1gni9_36._purpur-pagination-page-trigger__trigger-item--icon-only_1gni9_39{padding:var(--purpur-spacing-100)}._purpur-pagination-page-trigger__trigger-item--md_1gni9_42{padding:var(--purpur-spacing-150) var(--purpur-spacing-300)}._purpur-pagination-page-trigger__trigger-item--md_1gni9_42._purpur-pagination-page-trigger__trigger-item--icon-only_1gni9_39{padding:var(--purpur-spacing-150)}._purpur-pagination-page-trigger__trigger-item--lg_1gni9_48{padding:var(--purpur-spacing-200) var(--purpur-spacing-400)}._purpur-pagination-page-trigger__trigger-item--lg_1gni9_48._purpur-pagination-page-trigger__trigger-item--icon-only_1gni9_39{padding:var(--purpur-spacing-200)}._purpur-pagination-page-trigger__trigger-item--full-width_1gni9_54{width:100%}._purpur-pagination-page-trigger__trigger-item--primary_1gni9_57{background-color:var(--purpur-color-background-interactive-primary);color:var(--purpur-color-text-interactive-on-primary)}._purpur-pagination-page-trigger__trigger-item--primary_1gni9_57:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-primary-hover)}._purpur-pagination-page-trigger__trigger-item--primary_1gni9_57:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-primary-active)}._purpur-pagination-page-trigger__trigger-item--primary-negative_1gni9_67{background-color:var(--purpur-color-background-interactive-primary-negative);color:var(--purpur-color-text-interactive-on-primary-negative)}._purpur-pagination-page-trigger__trigger-item--primary-negative_1gni9_67:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-primary-negative-hover);border-color:var(--purpur-color-background-interactive-primary-negative-hover)}._purpur-pagination-page-trigger__trigger-item--primary-negative_1gni9_67:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-primary-negative-active);border-color:var(--purpur-color-background-interactive-primary-negative-active)}._purpur-pagination-page-trigger__trigger-item--secondary_1gni9_79{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:inset 0 0 0 var(--purpur-border-width-xs) var(--purpur-color-border-interactive-primary);color:var(--purpur-color-text-interactive-primary)}._purpur-pagination-page-trigger__trigger-item--secondary_1gni9_79:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-pagination-page-trigger__trigger-item--secondary_1gni9_79:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-pagination-page-trigger__trigger-item--secondary-negative_1gni9_90{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:inset 0 0 0 var(--purpur-border-width-xs) var(--purpur-color-border-interactive-primary-negative);color:var(--purpur-color-text-interactive-primary-negative)}._purpur-pagination-page-trigger__trigger-item--secondary-negative_1gni9_90:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-transparent-negative-hover)}._purpur-pagination-page-trigger__trigger-item--secondary-negative_1gni9_90:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-transparent-negative-active)}._purpur-pagination-page-trigger__trigger-item--expressive_1gni9_101{background-color:var(--purpur-color-background-interactive-expressive);color:var(--purpur-color-text-interactive-on-expressive)}._purpur-pagination-page-trigger__trigger-item--expressive_1gni9_101:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-expressive-hover)}._purpur-pagination-page-trigger__trigger-item--expressive_1gni9_101:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-expressive-active)}._purpur-pagination-page-trigger__trigger-item--expressive-negative_1gni9_111{background-color:var(--purpur-color-background-interactive-expressive-negative);color:var(--purpur-color-text-interactive-on-expressive-negative)}._purpur-pagination-page-trigger__trigger-item--expressive-negative_1gni9_111:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-expressive-negative-hover);color:var(--purpur-color-text-interactive-on-expressive-negative-hover)}._purpur-pagination-page-trigger__trigger-item--expressive-negative_1gni9_111:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-expressive-negative-active);color:var(--purpur-color-text-interactive-on-expressive-negative-active)}._purpur-pagination-page-trigger__trigger-item--page-trigger_1gni9_123{background-color:var(--purpur-color-background-interactive-transparent);box-sizing:border-box;color:var(--purpur-color-text-interactive-primary);height:calc(var(--purpur-spacing-150) + var(--purpur-spacing-400));padding:var(--purpur-spacing-150);transition:background-color var(--purpur-duration-100) var(--purpur-timing-standard),color var(--purpur-duration-100) var(--purpur-timing-standard);width:calc(var(--purpur-spacing-150) + var(--purpur-spacing-400))}._purpur-pagination-page-trigger__trigger-item_1gni9_4:hover:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61):not(._purpur-pagination-page-trigger__trigger-item--selected_1gni9_132){background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-pagination-page-trigger__trigger-item_1gni9_4:active:not(._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61){background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-pagination-page-trigger__trigger-item--selected_1gni9_132{background-color:var(--purpur-color-background-interactive-primary);color:var(--purpur-color-text-interactive-on-primary)}._purpur-pagination-page-trigger__trigger-item--disabled_1gni9_61{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:none;color:var(--purpur-color-text-weak);cursor:not-allowed}._purpur-pagination-pages_2g8is_1{display:flex;gap:var(--purpur-spacing-100);justify-content:center;list-style-type:none;margin:0;padding:0}._purpur-pagination-truncation-separator_b9cij_1{box-sizing:border-box;display:block;height:calc(2 * var(--purpur-spacing-250));padding:var(--purpur-spacing-150) 0;text-align:center;width:var(--purpur-spacing-250)}._purpur-pagination-step-trigger__trigger-item_104ss_1{align-items:center;border-radius:var(--purpur-border-radius-full);border-width:0;cursor:pointer;display:inline-flex;font-size:var(--purpur-typography-scale-100);font-family:var(--purpur-typography-family-default);font-weight:var(--purpur-typography-weight-medium);gap:var(--purpur-spacing-100);justify-content:center;line-height:var(--purpur-spacing-300);outline:0;position:relative;text-decoration:none;transition:all var(--purpur-motion-duration-100) ease;width:auto}._purpur-pagination-step-trigger__trigger-item_104ss_1:focus:before{border-radius:var(--purpur-border-radius-full);box-shadow:0 0 0 var(--purpur-border-width-sm) var(--purpur-color-border-interactive-focus);content:"";display:block;inset:calc(var(--purpur-spacing-25) * -1);position:absolute}._purpur-pagination-step-trigger__trigger-item_104ss_1:focus:not(:focus-visible):before{box-shadow:none}._purpur-pagination-step-trigger__trigger-item_104ss_1 svg{display:block}._purpur-pagination-step-trigger__trigger-item--sm_104ss_33{padding:var(--purpur-spacing-100) var(--purpur-spacing-250)}._purpur-pagination-step-trigger__trigger-item--sm_104ss_33._purpur-pagination-step-trigger__trigger-item--icon-only_104ss_36{padding:var(--purpur-spacing-100)}._purpur-pagination-step-trigger__trigger-item--md_104ss_39{padding:var(--purpur-spacing-150) var(--purpur-spacing-300)}._purpur-pagination-step-trigger__trigger-item--md_104ss_39._purpur-pagination-step-trigger__trigger-item--icon-only_104ss_36{padding:var(--purpur-spacing-150)}._purpur-pagination-step-trigger__trigger-item--lg_104ss_45{padding:var(--purpur-spacing-200) var(--purpur-spacing-400)}._purpur-pagination-step-trigger__trigger-item--lg_104ss_45._purpur-pagination-step-trigger__trigger-item--icon-only_104ss_36{padding:var(--purpur-spacing-200)}._purpur-pagination-step-trigger__trigger-item--full-width_104ss_51{width:100%}._purpur-pagination-step-trigger__trigger-item--primary_104ss_54{background-color:var(--purpur-color-background-interactive-primary);color:var(--purpur-color-text-interactive-on-primary)}._purpur-pagination-step-trigger__trigger-item--primary_104ss_54:hover:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-primary-hover)}._purpur-pagination-step-trigger__trigger-item--primary_104ss_54:active:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-primary-active)}._purpur-pagination-step-trigger__trigger-item--primary-negative_104ss_64{background-color:var(--purpur-color-background-interactive-primary-negative);color:var(--purpur-color-text-interactive-on-primary-negative)}._purpur-pagination-step-trigger__trigger-item--primary-negative_104ss_64:hover:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-primary-negative-hover);border-color:var(--purpur-color-background-interactive-primary-negative-hover)}._purpur-pagination-step-trigger__trigger-item--primary-negative_104ss_64:active:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-primary-negative-active);border-color:var(--purpur-color-background-interactive-primary-negative-active)}._purpur-pagination-step-trigger__trigger-item--secondary_104ss_76{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:inset 0 0 0 var(--purpur-border-width-xs) var(--purpur-color-border-interactive-primary);color:var(--purpur-color-text-interactive-primary)}._purpur-pagination-step-trigger__trigger-item--secondary_104ss_76:hover:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-transparent-hover)}._purpur-pagination-step-trigger__trigger-item--secondary_104ss_76:active:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-transparent-active)}._purpur-pagination-step-trigger__trigger-item--secondary-negative_104ss_87{background-color:var(--purpur-color-background-interactive-transparent);box-shadow:inset 0 0 0 var(--purpur-border-width-xs) var(--purpur-color-border-interactive-primary-negative);color:var(--purpur-color-text-interactive-primary-negative)}._purpur-pagination-step-trigger__trigger-item--secondary-negative_104ss_87:hover:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-transparent-negative-hover)}._purpur-pagination-step-trigger__trigger-item--secondary-negative_104ss_87:active:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-transparent-negative-active)}._purpur-pagination-step-trigger__trigger-item--expressive_104ss_98{background-color:var(--purpur-color-background-interactive-expressive);color:var(--purpur-color-text-interactive-on-expressive)}._purpur-pagination-step-trigger__trigger-item--expressive_104ss_98:hover:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-expressive-hover)}._purpur-pagination-step-trigger__trigger-item--expressive_104ss_98:active:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-expressive-active)}._purpur-pagination-step-trigger__trigger-item--expressive-negative_104ss_108{background-color:var(--purpur-color-background-interactive-expressive-negative);color:var(--purpur-color-text-interactive-on-expressive-negative)}._purpur-pagination-step-trigger__trigger-item--expressive-negative_104ss_108:hover:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-expressive-negative-hover);color:var(--purpur-color-text-interactive-on-expressive-negative-hover)}._purpur-pagination-step-trigger__trigger-item--expressive-negative_104ss_108:active:not(._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58){background-color:var(--purpur-color-background-interactive-expressive-negative-active);color:var(--purpur-color-text-interactive-on-expressive-negative-active)}._purpur-pagination-step-trigger__trigger-item--step-trigger_104ss_120{box-sizing:border-box;height:calc(var(--purpur-spacing-150) + var(--purpur-spacing-400));padding:var(--purpur-spacing-100);width:calc(var(--purpur-spacing-150) + var(--purpur-spacing-400))}@media screen and (min-width: 1024px){._purpur-pagination-step-trigger__trigger-item--step-trigger_104ss_120{padding:var(--purpur-spacing-100) var(--purpur-spacing-250);width:auto}}._purpur-pagination-step-trigger__trigger-item--disabled_104ss_58{background-color:var(--purpur-color-background-interactive-disabled);box-shadow:none;color:var(--purpur-color-text-weak);cursor:not-allowed}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type PaginationInformation = {
|
|
2
|
+
pageSize: number;
|
|
3
|
+
currentPage: number;
|
|
4
|
+
};
|
|
5
|
+
export type NavigationInformation = PaginationInformation & {
|
|
6
|
+
url: string;
|
|
7
|
+
};
|
|
8
|
+
export type HrefInformation = {
|
|
9
|
+
pageSize: number;
|
|
10
|
+
page: number;
|
|
11
|
+
};
|
|
12
|
+
export type LinkProps = {
|
|
13
|
+
anchorTagElement?: Link;
|
|
14
|
+
asLink: true;
|
|
15
|
+
hrefGetter: (hrefInformation: HrefInformation) => string;
|
|
16
|
+
navigationFunction?: (navigationInformation: NavigationInformation) => void;
|
|
17
|
+
onPageChange?: (paginationChangeInformation: PaginationInformation) => void;
|
|
18
|
+
};
|
|
19
|
+
export type NoLinkProps = {
|
|
20
|
+
anchorTagElement?: never;
|
|
21
|
+
asLink?: never;
|
|
22
|
+
hrefGetter?: never;
|
|
23
|
+
navigationFunction?: never;
|
|
24
|
+
onPageChange: (paginationChangeInformation: PaginationInformation) => void;
|
|
25
|
+
};
|
|
26
|
+
export type InternalLinkProps = {
|
|
27
|
+
asLink: true;
|
|
28
|
+
hrefGetter: (page: number) => string;
|
|
29
|
+
};
|
|
30
|
+
export type InternalNoLinkProps = {
|
|
31
|
+
asLink?: never;
|
|
32
|
+
hrefGetter?: never;
|
|
33
|
+
};
|
|
34
|
+
export type Link = React.ForwardRefExoticComponent<React.AnchorHTMLAttributes<HTMLAnchorElement>> | "a";
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,GAAG;IAC1D,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,gBAAgB,CAAC,EAAE,IAAI,CAAC;IACxB,MAAM,EAAE,IAAI,CAAC;IACb,UAAU,EAAE,CAAC,eAAe,EAAE,eAAe,KAAK,MAAM,CAAC;IACzD,kBAAkB,CAAC,EAAE,CAAC,qBAAqB,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC5E,YAAY,CAAC,EAAE,CAAC,2BAA2B,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC7E,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,gBAAgB,CAAC,EAAE,KAAK,CAAC;IACzB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,kBAAkB,CAAC,EAAE,KAAK,CAAC;IAC3B,YAAY,EAAE,CAAC,2BAA2B,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5E,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,IAAI,CAAC;IACb,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,UAAU,CAAC,EAAE,KAAK,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,IAAI,GACZ,KAAK,CAAC,yBAAyB,CAAC,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,CAAC,GAC9E,GAAG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-page-options.hook.d.ts","sourceRoot":"","sources":["../src/use-page-options.hook.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,KAAK,kBAAkB,GAAG;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,cAAc,kBAAmB,MAAM,KAAG,kBAatD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SelectOption } from '@purpurds/select';
|
|
2
|
+
|
|
3
|
+
type UsePageSizeOptionsHook = {
|
|
4
|
+
options: SelectOption[];
|
|
5
|
+
};
|
|
6
|
+
export declare const usePageSizeOptions: (availablePageSizes: number[]) => UsePageSizeOptionsHook;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=use-page-size-options.hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-page-size-options.hook.d.ts","sourceRoot":"","sources":["../src/use-page-size-options.hook.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,KAAK,sBAAsB,GAAG;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,kBAAkB,uBAAwB,MAAM,EAAE,KAAG,sBAajE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Option } from '@purpurds/autocomplete';
|
|
2
|
+
|
|
3
|
+
type UsePaginationPageSelectorEvents = {
|
|
4
|
+
onKeyUp: (event: React.KeyboardEvent<HTMLInputElement>) => void;
|
|
5
|
+
onSelectionChange: (option?: Option) => void;
|
|
6
|
+
resetSelection: () => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const usePaginationPageSelectorEvents: (currentPage: number, navigationFunction: (page: number, url: string) => void, numberOfPages: number, onPageChange: (page: number) => void, options: Option[], setValue: React.Dispatch<React.SetStateAction<string | number>>, asLink?: boolean, hrefGetter?: (page: number) => string) => UsePaginationPageSelectorEvents;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=use-pagination-page-selector-events.hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-pagination-page-selector-events.hook.d.ts","sourceRoot":"","sources":["../src/use-pagination-page-selector-events.hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAEhD,KAAK,+BAA+B,GAAG;IACrC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAChE,iBAAiB,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC;AAEF,eAAO,MAAM,+BAA+B,gBAC7B,MAAM,sBACC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,iBACxC,MAAM,gBACP,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,WAC3B,MAAM,EAAE,YACP,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,WACtD,OAAO,eACH,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,KACpC,+BAyCF,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
type UsePaginationPagesHook = {
|
|
2
|
+
pages: number[];
|
|
3
|
+
numberOfPages: number;
|
|
4
|
+
};
|
|
5
|
+
export declare const usePaginationPages: (totalItems: number, pageSize: number, currentPage: number) => UsePaginationPagesHook;
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=use-pagination-pages.hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-pagination-pages.hook.d.ts","sourceRoot":"","sources":["../src/use-pagination-pages.hook.ts"],"names":[],"mappings":"AAEA,KAAK,sBAAsB,GAAG;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,kBAAkB,eACjB,MAAM,YACR,MAAM,eACH,MAAM,KAClB,sBAcF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@purpurds/pagination",
|
|
3
|
+
"version": "5.19.1",
|
|
4
|
+
"license": "AGPL-3.0-only",
|
|
5
|
+
"main": "./dist/pagination.cjs.js",
|
|
6
|
+
"types": "./dist/pagination.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/pagination.cjs.js",
|
|
10
|
+
"types": "./dist/pagination.d.ts",
|
|
11
|
+
"default": "./dist/pagination.es.js"
|
|
12
|
+
},
|
|
13
|
+
"./styles": "./dist/styles.css"
|
|
14
|
+
},
|
|
15
|
+
"source": "src/pagination.tsx",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"classnames": "~2.5.0",
|
|
18
|
+
"@purpurds/action": "5.19.1",
|
|
19
|
+
"@purpurds/label": "5.19.1",
|
|
20
|
+
"@purpurds/autocomplete": "5.19.1",
|
|
21
|
+
"@purpurds/select": "5.19.1",
|
|
22
|
+
"@purpurds/tokens": "5.19.1",
|
|
23
|
+
"@purpurds/paragraph": "5.19.1",
|
|
24
|
+
"@purpurds/text-field": "5.19.1",
|
|
25
|
+
"@purpurds/icon": "5.19.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@rushstack/eslint-patch": "~1.10.0",
|
|
29
|
+
"@storybook/blocks": "^8.2.6",
|
|
30
|
+
"@storybook/react": "^8.2.6",
|
|
31
|
+
"@telia/base-rig": "~8.2.0",
|
|
32
|
+
"@telia/react-rig": "~3.2.0",
|
|
33
|
+
"@testing-library/dom": "~9.3.3",
|
|
34
|
+
"@testing-library/jest-dom": "~6.4.0",
|
|
35
|
+
"@testing-library/react": "~14.3.0",
|
|
36
|
+
"@testing-library/user-event": "~14.5.1",
|
|
37
|
+
"@types/node": "20.12.12",
|
|
38
|
+
"@types/react-dom": "^18.3.0",
|
|
39
|
+
"@types/react": "^18.3.3",
|
|
40
|
+
"eslint-plugin-testing-library": "~6.2.0",
|
|
41
|
+
"eslint": "^8.57.0",
|
|
42
|
+
"jsdom": "~22.1.0",
|
|
43
|
+
"lint-staged": "~10.5.3",
|
|
44
|
+
"prettier": "~2.8.8",
|
|
45
|
+
"react-dom": "^18.3.1",
|
|
46
|
+
"react": "^18.3.1",
|
|
47
|
+
"storybook": "^8.2.6",
|
|
48
|
+
"typescript": "^5.5.4",
|
|
49
|
+
"vite": "5.3.4",
|
|
50
|
+
"vitest": "~1.5.0",
|
|
51
|
+
"@purpurds/component-rig": "1.0.0",
|
|
52
|
+
"@purpurds/skeleton": "5.19.1",
|
|
53
|
+
"@purpurds/listbox": "5.19.1"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build:dev": "vite",
|
|
57
|
+
"build:watch": "vite build --watch",
|
|
58
|
+
"build": "vite build",
|
|
59
|
+
"ci:build": "rushx build",
|
|
60
|
+
"coverage": "vitest run --coverage",
|
|
61
|
+
"lint:fix": "eslint . --fix",
|
|
62
|
+
"lint": "lint-staged --no-stash 2>&1",
|
|
63
|
+
"sbdev": "rush sbdev",
|
|
64
|
+
"test:unit": "vitest run --passWithNoTests",
|
|
65
|
+
"test:watch": "vitest --watch",
|
|
66
|
+
"test": "rushx test:unit",
|
|
67
|
+
"typecheck": "tsc -p ./tsconfig.json"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/global.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
.purpur-pagination-page-selector {
|
|
2
|
+
align-items: center;
|
|
3
|
+
display: flex;
|
|
4
|
+
gap: var(--purpur-spacing-150);
|
|
5
|
+
|
|
6
|
+
&__autocomplete {
|
|
7
|
+
max-width: var(--purpur-spacing-1000);
|
|
8
|
+
width: 100%;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
&__input {
|
|
12
|
+
input[type="number"] {
|
|
13
|
+
-moz-appearance: textfield;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
input[type="number"]::-webkit-outer-spin-button,
|
|
17
|
+
input[type="number"]::-webkit-inner-spin-button {
|
|
18
|
+
-webkit-appearance: none;
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
&__of-total-pages-label {
|
|
24
|
+
flex: 0 0 auto;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import * as matchers from "@testing-library/jest-dom/matchers";
|
|
3
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { PaginationPageSelector } from "./pagination-page-selector";
|
|
8
|
+
|
|
9
|
+
expect.extend(matchers);
|
|
10
|
+
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.clearAllMocks();
|
|
13
|
+
cleanup();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("PaginationPageSelector", () => {
|
|
17
|
+
const defaultProps = {
|
|
18
|
+
currentPage: 1,
|
|
19
|
+
navigationFunction: vi.fn(),
|
|
20
|
+
numberOfPages: 5,
|
|
21
|
+
onPageChange: vi.fn(),
|
|
22
|
+
outOfLabel: "of",
|
|
23
|
+
pageSelectorListBoxLabel: "Select a page",
|
|
24
|
+
pageSelectorNoOptionsText: "Page does not exist",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
it("renders without crashing", () => {
|
|
28
|
+
render(<PaginationPageSelector {...defaultProps} />);
|
|
29
|
+
expect(screen.getByTestId("purpur-pagination-page-selector")).toBeInTheDocument();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("displays the correct number of total pages", () => {
|
|
33
|
+
render(<PaginationPageSelector {...defaultProps} />);
|
|
34
|
+
expect(screen.getByTestId(Selectors.OF_TOTAL_PAGES).textContent).toContain("of 5");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("displays the correct page number in the autocomplete input", () => {
|
|
38
|
+
render(<PaginationPageSelector {...defaultProps} />);
|
|
39
|
+
expect(screen.getByTestId(Selectors.AUTO_COMPLETE_INPUT)).toHaveValue(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("calls onPageChange when a page is clicked", async () => {
|
|
43
|
+
const onPageChange = vi.fn();
|
|
44
|
+
render(<PaginationPageSelector {...defaultProps} onPageChange={onPageChange} />);
|
|
45
|
+
|
|
46
|
+
await userEvent.click(screen.getByTestId(Selectors.AUTO_COMPLETE_INPUT));
|
|
47
|
+
await userEvent.click(screen.getByText("2"));
|
|
48
|
+
expect(onPageChange).toHaveBeenCalledWith(2);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("calls navigationFunction when a page is clicked and link mode is set", async () => {
|
|
52
|
+
const onPageChange = vi.fn();
|
|
53
|
+
const navigationFunction = vi.fn();
|
|
54
|
+
const hrefGetter = vi.fn().mockReturnValue("#page-2");
|
|
55
|
+
render(
|
|
56
|
+
<PaginationPageSelector
|
|
57
|
+
{...defaultProps}
|
|
58
|
+
asLink
|
|
59
|
+
hrefGetter={hrefGetter}
|
|
60
|
+
onPageChange={onPageChange}
|
|
61
|
+
navigationFunction={navigationFunction}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
await userEvent.click(screen.getByTestId(Selectors.AUTO_COMPLETE_INPUT));
|
|
66
|
+
await userEvent.click(screen.getByText("2"));
|
|
67
|
+
expect(onPageChange).toHaveBeenCalledWith(2);
|
|
68
|
+
expect(hrefGetter).toHaveBeenCalledWith(2);
|
|
69
|
+
expect(navigationFunction).toHaveBeenCalledWith(2, "#page-2");
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const Selectors = {
|
|
74
|
+
PAGE_SELECTOR: "purpur-pagination-page-selector",
|
|
75
|
+
OF_TOTAL_PAGES: "purpur-pagination-page-selector-of-total-pages",
|
|
76
|
+
AUTO_COMPLETE: "purpur-pagination-page-selector-autocomplete",
|
|
77
|
+
AUTO_COMPLETE_INPUT: "purpur-pagination-page-selector-autocomplete-input-input",
|
|
78
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import React, { FormEvent, ForwardedRef, forwardRef, useId } from "react";
|
|
2
|
+
import { Autocomplete } from "@purpurds/autocomplete";
|
|
3
|
+
import { Paragraph } from "@purpurds/paragraph";
|
|
4
|
+
import { TextField } from "@purpurds/text-field";
|
|
5
|
+
import c from "classnames/bind";
|
|
6
|
+
|
|
7
|
+
import styles from "./pagination-page-selector.module.scss";
|
|
8
|
+
import { InternalLinkProps, InternalNoLinkProps } from "./types";
|
|
9
|
+
import { usePageOptions } from "./use-page-options.hook";
|
|
10
|
+
import { usePaginationPageSelectorEvents } from "./use-pagination-page-selector-events.hook";
|
|
11
|
+
const cx = c.bind(styles);
|
|
12
|
+
|
|
13
|
+
export type PaginationPageSelectorProps = {
|
|
14
|
+
["data-testid"]?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
currentPage: number;
|
|
17
|
+
navigationFunction: (page: number, url: string) => void;
|
|
18
|
+
numberOfPages: number;
|
|
19
|
+
onPageChange: (page: number) => void;
|
|
20
|
+
outOfLabel: string;
|
|
21
|
+
pageSelectorAutocompleteId?: string;
|
|
22
|
+
pageSelectorListBoxLabel: string;
|
|
23
|
+
pageSelectorNoOptionsText: string;
|
|
24
|
+
} & (InternalLinkProps | InternalNoLinkProps);
|
|
25
|
+
|
|
26
|
+
const rootClassName = "purpur-pagination-page-selector";
|
|
27
|
+
|
|
28
|
+
export const PaginationPageSelector = forwardRef(
|
|
29
|
+
(
|
|
30
|
+
{
|
|
31
|
+
["data-testid"]: dataTestId = "purpur-pagination-page-selector",
|
|
32
|
+
asLink,
|
|
33
|
+
className,
|
|
34
|
+
currentPage,
|
|
35
|
+
hrefGetter,
|
|
36
|
+
navigationFunction,
|
|
37
|
+
numberOfPages,
|
|
38
|
+
onPageChange,
|
|
39
|
+
outOfLabel,
|
|
40
|
+
pageSelectorAutocompleteId,
|
|
41
|
+
pageSelectorListBoxLabel,
|
|
42
|
+
pageSelectorNoOptionsText,
|
|
43
|
+
...props
|
|
44
|
+
}: PaginationPageSelectorProps,
|
|
45
|
+
ref: ForwardedRef<HTMLDivElement>
|
|
46
|
+
) => {
|
|
47
|
+
const id = useId();
|
|
48
|
+
const classes = cx([className, rootClassName]);
|
|
49
|
+
const [value, setValue] = React.useState<string | number>(currentPage);
|
|
50
|
+
const { options } = usePageOptions(numberOfPages);
|
|
51
|
+
const { onSelectionChange, onKeyUp, resetSelection } = usePaginationPageSelectorEvents(
|
|
52
|
+
currentPage,
|
|
53
|
+
navigationFunction,
|
|
54
|
+
numberOfPages,
|
|
55
|
+
onPageChange,
|
|
56
|
+
options,
|
|
57
|
+
setValue,
|
|
58
|
+
asLink,
|
|
59
|
+
hrefGetter
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
React.useEffect(() => {
|
|
63
|
+
setValue(currentPage);
|
|
64
|
+
}, [currentPage]);
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className={classes} data-testid={dataTestId} ref={ref} {...props}>
|
|
68
|
+
<Autocomplete
|
|
69
|
+
className={cx(`${rootClassName}__autocomplete`)}
|
|
70
|
+
combobox
|
|
71
|
+
data-testid={`${dataTestId}-autocomplete`}
|
|
72
|
+
id={pageSelectorAutocompleteId ?? id}
|
|
73
|
+
listboxLabel={pageSelectorListBoxLabel}
|
|
74
|
+
noOptionsText={pageSelectorNoOptionsText}
|
|
75
|
+
onSelect={onSelectionChange}
|
|
76
|
+
options={options}
|
|
77
|
+
renderInput={(props) => (
|
|
78
|
+
<TextField
|
|
79
|
+
{...props}
|
|
80
|
+
className={cx(`${rootClassName}__input`)}
|
|
81
|
+
min={1}
|
|
82
|
+
max={numberOfPages}
|
|
83
|
+
onBlur={resetSelection}
|
|
84
|
+
onInput={(event: FormEvent<HTMLInputElement>) => {
|
|
85
|
+
setValue((event.target as HTMLInputElement).value);
|
|
86
|
+
}}
|
|
87
|
+
onKeyUp={onKeyUp}
|
|
88
|
+
type="number"
|
|
89
|
+
value={value}
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
92
|
+
selectedOption={options[currentPage - 1]}
|
|
93
|
+
/>
|
|
94
|
+
<Paragraph
|
|
95
|
+
className={cx(`${rootClassName}__of-total-pages-label`)}
|
|
96
|
+
data-testid={`${dataTestId}-of-total-pages`}
|
|
97
|
+
>
|
|
98
|
+
{`${outOfLabel} ${numberOfPages}`}
|
|
99
|
+
</Paragraph>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
PaginationPageSelector.displayName = "PaginationPageSelector";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
@import "@purpurds/tokens/breakpoint/variables";
|
|
2
|
+
|
|
3
|
+
.purpur-pagination-page-size-selector {
|
|
4
|
+
$root: &;
|
|
5
|
+
align-items: center;
|
|
6
|
+
display: flex;
|
|
7
|
+
gap: var(--purpur-spacing-150);
|
|
8
|
+
justify-content: center;
|
|
9
|
+
|
|
10
|
+
@media screen and (min-width: $purpur-breakpoint-lg) {
|
|
11
|
+
justify-content: flex-start;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&__select {
|
|
15
|
+
flex: 1 0 var(--purpur-spacing-1000);
|
|
16
|
+
max-width: var(--purpur-spacing-1000);
|
|
17
|
+
width: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#{$root}__items-per-page-label {
|
|
21
|
+
flex: 0 1 auto;
|
|
22
|
+
display: block;
|
|
23
|
+
font-weight: var(--purpur-typography-weight-normal);
|
|
24
|
+
hyphens: none;
|
|
25
|
+
line-height: var(--purpur-typography-line-height-loose);
|
|
26
|
+
margin: 0;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
text-overflow: ellipsis;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#{$root}__items-per-page-label-text {
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import * as matchers from "@testing-library/jest-dom/matchers";
|
|
3
|
+
import { cleanup, render, screen } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { PaginationPageSizeSelector } from "./pagination-page-size-selector";
|
|
8
|
+
|
|
9
|
+
expect.extend(matchers);
|
|
10
|
+
|
|
11
|
+
vi.mock("./navigation");
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
vi.clearAllMocks();
|
|
15
|
+
cleanup();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("PaginationPageSizeSelector", () => {
|
|
19
|
+
const defaultProps = {
|
|
20
|
+
availablePageSizes: [10, 20, 30],
|
|
21
|
+
pageSizeLabel: "Items per page",
|
|
22
|
+
onPageSizeChange: vi.fn(),
|
|
23
|
+
pageSize: 10,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
it("renders correctly with default props", () => {
|
|
27
|
+
render(<PaginationPageSizeSelector {...defaultProps} />);
|
|
28
|
+
|
|
29
|
+
expect(screen.getByTestId(Selectors.PAGINATION_PAGE_SIZE_SELECTOR)).toBeInTheDocument();
|
|
30
|
+
expect(screen.getByTestId(Selectors.ITEMS_PER_PAGE_LABEL)).toHaveTextContent("Items per page");
|
|
31
|
+
expect(screen.getByTestId(Selectors.PAGE_SIZE_SELECT)).toHaveValue("10");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("calls onPageSizeChange when a new page size is selected", async () => {
|
|
35
|
+
render(<PaginationPageSizeSelector {...defaultProps} />);
|
|
36
|
+
|
|
37
|
+
const select = screen.getByTestId(Selectors.PAGE_SIZE_SELECT);
|
|
38
|
+
await userEvent.selectOptions(select, "20");
|
|
39
|
+
|
|
40
|
+
expect(defaultProps.onPageSizeChange).toHaveBeenCalledWith(20);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("navigates to the correct page when asLink is true", async () => {
|
|
44
|
+
const hrefGetter = vi.fn().mockReturnValue("/page/1?pageSize=20");
|
|
45
|
+
const navigationFunction = vi.fn().mockReturnValue("/page/1?pageSize=20");
|
|
46
|
+
|
|
47
|
+
render(
|
|
48
|
+
<PaginationPageSizeSelector
|
|
49
|
+
{...defaultProps}
|
|
50
|
+
asLink
|
|
51
|
+
hrefGetter={hrefGetter}
|
|
52
|
+
navigationFunction={navigationFunction}
|
|
53
|
+
/>
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const select = screen.getByTestId(Selectors.PAGE_SIZE_SELECT);
|
|
57
|
+
await userEvent.selectOptions(select, "20");
|
|
58
|
+
|
|
59
|
+
expect(hrefGetter).toHaveBeenCalledWith({ page: 1, pageSize: 20 });
|
|
60
|
+
expect(defaultProps.onPageSizeChange).toHaveBeenCalledWith(20);
|
|
61
|
+
expect(navigationFunction).toHaveBeenCalledWith({
|
|
62
|
+
currentPage: 1,
|
|
63
|
+
pageSize: 20,
|
|
64
|
+
url: "/page/1?pageSize=20",
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const Selectors = {
|
|
70
|
+
PAGINATION_PAGE_SIZE_SELECTOR: "purpur-pagination-page-size-selector",
|
|
71
|
+
ITEMS_PER_PAGE_LABEL: "purpur-pagination-page-size-selector-item-per-page-label",
|
|
72
|
+
PAGE_SIZE_SELECT: "purpur-pagination-page-size-selector-select-select",
|
|
73
|
+
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React, { ForwardedRef, forwardRef, useId } from "react";
|
|
2
|
+
import { Label } from "@purpurds/label";
|
|
3
|
+
import { Select } from "@purpurds/select";
|
|
4
|
+
import c from "classnames/bind";
|
|
5
|
+
|
|
6
|
+
import { navigateToPage } from "./navigation";
|
|
7
|
+
import styles from "./pagination-page-size-selector.module.scss";
|
|
8
|
+
import { LinkProps, NoLinkProps } from "./types";
|
|
9
|
+
import { usePageSizeOptions } from "./use-page-size-options.hook";
|
|
10
|
+
const cx = c.bind(styles);
|
|
11
|
+
|
|
12
|
+
export type PaginationPageSizeSelectorProps = {
|
|
13
|
+
["data-testid"]?: string;
|
|
14
|
+
availablePageSizes: number[];
|
|
15
|
+
className?: string;
|
|
16
|
+
onPageSizeChange: (itemsPerPage: number) => void;
|
|
17
|
+
pageSize: number;
|
|
18
|
+
pageSizeLabel: string;
|
|
19
|
+
} & (LinkProps | NoLinkProps);
|
|
20
|
+
|
|
21
|
+
const rootClassName = "purpur-pagination-page-size-selector";
|
|
22
|
+
|
|
23
|
+
export const PaginationPageSizeSelector = forwardRef(
|
|
24
|
+
(
|
|
25
|
+
{
|
|
26
|
+
["data-testid"]: dataTestId = "purpur-pagination-page-size-selector",
|
|
27
|
+
asLink,
|
|
28
|
+
availablePageSizes,
|
|
29
|
+
className,
|
|
30
|
+
hrefGetter,
|
|
31
|
+
navigationFunction,
|
|
32
|
+
onPageSizeChange,
|
|
33
|
+
pageSize,
|
|
34
|
+
pageSizeLabel,
|
|
35
|
+
...props
|
|
36
|
+
}: PaginationPageSizeSelectorProps,
|
|
37
|
+
ref: ForwardedRef<HTMLDivElement>
|
|
38
|
+
) => {
|
|
39
|
+
const selectId = useId();
|
|
40
|
+
const classes = cx([className, rootClassName]);
|
|
41
|
+
const { options } = usePageSizeOptions(availablePageSizes);
|
|
42
|
+
|
|
43
|
+
const onSelectionChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
44
|
+
const selectedPageSize = Number(event.target.value);
|
|
45
|
+
onPageSizeChange(selectedPageSize);
|
|
46
|
+
if (asLink) {
|
|
47
|
+
const url = hrefGetter({ page: 1, pageSize: selectedPageSize });
|
|
48
|
+
if (navigationFunction) {
|
|
49
|
+
navigationFunction({ currentPage: 1, pageSize: selectedPageSize, url });
|
|
50
|
+
} else {
|
|
51
|
+
navigateToPage(url);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className={classes} data-testid={dataTestId} ref={ref} {...props}>
|
|
58
|
+
<Label
|
|
59
|
+
className={cx(`${rootClassName}__items-per-page-label`)}
|
|
60
|
+
data-testid={`${dataTestId}-item-per-page-label`}
|
|
61
|
+
htmlFor={selectId}
|
|
62
|
+
>
|
|
63
|
+
<span className={cx(`${rootClassName}__items-per-page-label-text`)}>{pageSizeLabel}</span>
|
|
64
|
+
</Label>
|
|
65
|
+
<Select
|
|
66
|
+
className={cx(`${rootClassName}__select`)}
|
|
67
|
+
data-testid={`${dataTestId}-select`}
|
|
68
|
+
id={selectId}
|
|
69
|
+
onChange={onSelectionChange}
|
|
70
|
+
options={options}
|
|
71
|
+
value={pageSize}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
PaginationPageSizeSelector.displayName = "PaginationPageSizeSelector";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
@import "@purpurds/action/src/action.scss";
|
|
2
|
+
|
|
3
|
+
.purpur-pagination-page-trigger {
|
|
4
|
+
display: block;
|
|
5
|
+
|
|
6
|
+
&__trigger-item {
|
|
7
|
+
$trigger-item: &;
|
|
8
|
+
@include action();
|
|
9
|
+
|
|
10
|
+
&--page-trigger {
|
|
11
|
+
background-color: var(--purpur-color-background-interactive-transparent);
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
color: var(--purpur-color-text-interactive-primary);
|
|
14
|
+
height: calc(var(--purpur-spacing-150) + var(--purpur-spacing-400));
|
|
15
|
+
padding: var(--purpur-spacing-150);
|
|
16
|
+
transition: background-color var(--purpur-duration-100) var(--purpur-timing-standard),
|
|
17
|
+
color var(--purpur-duration-100) var(--purpur-timing-standard);
|
|
18
|
+
width: calc(var(--purpur-spacing-150) + var(--purpur-spacing-400));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&:hover:not(#{$trigger-item}--disabled):not(#{$trigger-item}--selected) {
|
|
22
|
+
background-color: var(--purpur-color-background-interactive-transparent-hover);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&:active:not(#{$trigger-item}--disabled) {
|
|
26
|
+
background-color: var(--purpur-color-background-interactive-transparent-active);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&--selected {
|
|
30
|
+
background-color: var(--purpur-color-background-interactive-primary);
|
|
31
|
+
color: var(--purpur-color-text-interactive-on-primary);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
&--disabled {
|
|
35
|
+
background-color: var(--purpur-color-background-interactive-transparent);
|
|
36
|
+
box-shadow: none;
|
|
37
|
+
color: var(--purpur-color-text-weak);
|
|
38
|
+
cursor: not-allowed;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|