Skip to content

Commit a5bafd3

Browse files
authored
Merge pull request #2277 from dxc-technology/PelayoFelgueroso-pagination-responsive
Fix paginator component responsiveness
2 parents 00ffe16 + 8116e80 commit a5bafd3

File tree

10 files changed

+113
-61
lines changed

10 files changed

+113
-61
lines changed

packages/lib/src/breadcrumbs/Breadcrumbs.accessibility.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import { axe, formatRules } from "../../test/accessibility/axe-helper";
33
import DxcBreadcrumbs from "./Breadcrumbs";
44
import { disabledRules as rules } from "../../test/accessibility/rules/specific/breadcrumbs/disabledRules";
55

6+
(global as any).ResizeObserver = class ResizeObserver {
7+
observe() {}
8+
9+
unobserve() {}
10+
11+
disconnect() {}
12+
};
13+
614
const disabledRules = {
715
rules: formatRules(rules),
816
};

packages/lib/src/dropdown/Dropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ const DxcDropdown = ({
134134

135135
const triggerRef = useRef<HTMLButtonElement | null>(null);
136136
const menuRef = useRef<HTMLUListElement | null>(null);
137-
const width = useWidth(triggerRef.current);
137+
const width = useWidth(triggerRef);
138138

139139
const handleOnOpenMenu = () => {
140140
changeIsOpen(true);

packages/lib/src/header/Header.accessibility.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ import DxcFlex from "../flex/Flex";
55
import DxcLink from "../link/Link";
66
import DxcHeader from "./Header";
77

8+
(global as any).ResizeObserver = class ResizeObserver {
9+
observe() {}
10+
11+
unobserve() {}
12+
13+
disconnect() {}
14+
};
15+
816
const disabledRules = {
917
rules: formatRules(rules),
1018
};

packages/lib/src/paginator/Paginator.stories.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ export default {
88
component: DxcPaginator,
99
} as Meta<typeof DxcPaginator>;
1010

11+
const customViewports = {
12+
resizedScreen: {
13+
name: "Custom viewport",
14+
styles: {
15+
width: "400px",
16+
height: "1600px",
17+
},
18+
},
19+
};
20+
1121
const Paginator = () => (
1222
<>
1323
<ExampleContainer>
@@ -67,3 +77,11 @@ type Story = StoryObj<typeof DxcPaginator>;
6777
export const Chromatic: Story = {
6878
render: Paginator,
6979
};
80+
81+
export const ResponsivePaginator: Story = {
82+
render: Paginator,
83+
parameters: {
84+
viewport: { viewports: customViewports, defaultViewport: "resizedScreen" },
85+
chromatic: { viewports: [400] },
86+
},
87+
};

packages/lib/src/paginator/Paginator.tsx

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,65 @@
1-
import { useContext } from "react";
1+
import { useContext, useRef } from "react";
22
import styled from "@emotion/styled";
33
import DxcButton from "../button/Button";
44
import DxcSelect from "../select/Select";
55
import PaginatorPropsType from "./types";
66
import { HalstackLanguageContext } from "../HalstackContext";
7+
import { responsiveSizes } from "../common/variables";
8+
import useWidth from "../utils/useWidth";
9+
import { isResponsive } from "./utils";
10+
11+
const DxcPaginatorContainer = styled.div<{ width: number }>`
12+
display: flex;
13+
justify-content: ${({ width }) => (isResponsive(width) ? "center" : "flex-end")};
14+
flex-wrap: ${({ width }) => (isResponsive(width) ? "wrap" : "nowrap")};
15+
gap: ${({ width }) => (isResponsive(width) ? "var(--spacing-gap-s)" : "0")};
16+
align-items: center;
17+
width: 100%;
18+
min-height: 48px;
19+
box-sizing: border-box;
20+
font-family: var(--typography-font-family);
21+
font-size: var(--typography-label-m);
22+
font-weight: var(--typography-label-regular);
23+
background-color: var(--color-bg-neutral-lighter);
24+
color: var(--color-fg-neutral-dark);
25+
padding: var(--spacing-padding-xs) var(--spacing-padding-xl);
26+
`;
27+
28+
const ItemsPerPageContainer = styled.span<{ width: number }>`
29+
display: flex;
30+
align-items: center;
31+
gap: var(--spacing-gap-s);
32+
margin-right: ${({ width }) => (isResponsive(width) ? "0" : "var(--spacing-gap-ml)")};
33+
`;
34+
35+
const SelectContainer = styled.div`
36+
min-width: 6.25rem;
37+
`;
38+
39+
const TotalItemsContainer = styled.span<{ width: number }>`
40+
margin-right: ${({ width }) => (isResponsive(width) ? "0" : "var(--spacing-gap-xxl)")};
41+
`;
42+
43+
const GoToPageContainer = styled.div`
44+
display: flex;
45+
align-items: center;
46+
gap: var(--spacing-gap-ml);
47+
`;
48+
49+
const ButtonsContainer = styled.div`
50+
display: flex;
51+
align-items: center;
52+
gap: var(--spacing-gap-s);
53+
flex-shrink: 0;
54+
`;
55+
56+
const PageToSelectContainer = styled.span<{ width: number }>`
57+
display: flex;
58+
align-items: center;
59+
gap: var(--spacing-gap-s);
60+
flex-shrink: 0;
61+
flex-wrap: wrap;
62+
`;
763

864
const DxcPaginator = ({
965
currentPage = 1,
@@ -26,58 +82,13 @@ const DxcPaginator = ({
2682

2783
const translatedLabels = useContext(HalstackLanguageContext);
2884

29-
const DxcPaginatorContainer = styled.div`
30-
display: flex;
31-
justify-content: flex-end;
32-
align-items: center;
33-
width: 100%;
34-
min-height: 48px;
35-
box-sizing: border-box;
36-
font-family: var(--typography-font-family);
37-
font-size: var(--typography-label-m);
38-
font-weight: var(--typography-label-regular);
39-
background-color: var(--color-bg-neutral-lighter);
40-
color: var(--color-fg-neutral-dark);
41-
padding: var(--spacing-padding-xs) var(--spacing-padding-xl);
42-
`;
43-
44-
const ItemsPerPageContainer = styled.span`
45-
display: flex;
46-
align-items: center;
47-
gap: var(--spacing-gap-s);
48-
margin-right: var(--spacing-gap-ml);
49-
`;
50-
51-
const SelectContainer = styled.div`
52-
min-width: 6.25rem;
53-
`;
54-
55-
const TotalItemsContainer = styled.span`
56-
margin-right: var(--spacing-gap-xxl);
57-
`;
58-
59-
const GoToPageContainer = styled.div`
60-
display: flex;
61-
align-items: center;
62-
gap: var(--spacing-gap-ml);
63-
`;
64-
65-
const ButtonsContainer = styled.div`
66-
display: flex;
67-
align-items: center;
68-
gap: var(--spacing-gap-s);
69-
`;
70-
71-
const PageToSelectContainer = styled.span`
72-
display: flex;
73-
align-items: center;
74-
gap: var(--spacing-gap-s);
75-
`;
85+
const containerRef = useRef<HTMLDivElement | null>(null);
86+
const width = useWidth(containerRef);
7687

7788
return (
78-
<DxcPaginatorContainer>
89+
<DxcPaginatorContainer ref={containerRef} width={width}>
7990
{itemsPerPageOptions && (
80-
<ItemsPerPageContainer>
91+
<ItemsPerPageContainer width={width}>
8192
<span>{translatedLabels.paginator.itemsPerPageText}</span>
8293
<SelectContainer>
8394
<DxcSelect
@@ -95,7 +106,7 @@ const DxcPaginator = ({
95106
</SelectContainer>
96107
</ItemsPerPageContainer>
97108
)}
98-
<TotalItemsContainer>
109+
<TotalItemsContainer width={width}>
99110
{translatedLabels.paginator.minToMaxOfText(minItemsPerPage, maxItemsPerPage, totalItems)}
100111
</TotalItemsContainer>
101112
<GoToPageContainer>
@@ -127,8 +138,10 @@ const DxcPaginator = ({
127138
</ButtonsContainer>
128139
)}
129140
{showGoToPage ? (
130-
<PageToSelectContainer>
131-
<span>{translatedLabels.paginator.goToPageText} </span>
141+
<PageToSelectContainer width={width}>
142+
{(width >= Number(responsiveSizes.small) * 16 || !onPageChange) && (
143+
<span>{translatedLabels.paginator.goToPageText}</span>
144+
)}
132145
<SelectContainer>
133146
<DxcSelect
134147
options={Array.from(Array(totalPages), (e, num) => ({
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { responsiveSizes } from "../common/variables";
2+
3+
export const isResponsive = (width: number) => width && width <= Number(responsiveSizes.medium) * 16;

packages/lib/src/select/Select.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ const DxcSelect = forwardRef<RefType, SelectPropsType>(
211211
const selectRef = useRef<HTMLDivElement | null>(null);
212212
const selectSearchInputRef = useRef<HTMLInputElement | null>(null);
213213

214-
const width = useWidth(selectRef.current);
214+
const width = useWidth(selectRef);
215215
const translatedLabels = useContext(HalstackLanguageContext);
216216

217217
const optionalItem = useMemo(() => ({ label: placeholder, value: "" }), [placeholder]);

packages/lib/src/tabs/Tabs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ const DxcTabs = ({ children, iconPosition = "left", margin, tabIndex = 0 }: Tabs
112112
const refTabListContainer = useRef<HTMLDivElement | null>(null);
113113
const refTabList = useRef<HTMLDivElement | null>(null);
114114
const translatedLabels = useContext(HalstackLanguageContext);
115-
const viewWidth = useWidth(refTabList.current);
115+
const viewWidth = useWidth(refTabList);
116116
const contextValue = useMemo(() => {
117117
const focusedChild = innerFocusIndex != null ? childrenArray[innerFocusIndex] : null;
118118
return {

packages/lib/src/text-input/TextInput.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ const DxcTextInput = forwardRef<RefType, TextInputPropsType>(
151151
const [isAutosuggestError, changeIsAutosuggestError] = useState(false);
152152
const [filteredSuggestions, changeFilteredSuggestions] = useState<string[]>([]);
153153
const [visualFocusIndex, changeVisualFocusIndex] = useState(-1);
154-
const width = useWidth(inputContainerRef.current);
154+
const width = useWidth(inputContainerRef);
155155

156156
const getNumberErrorMessage = (checkedValue: number) =>
157157
numberInputContext?.minNumber != null && checkedValue < numberInputContext?.minNumber

packages/lib/src/utils/useWidth.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { useLayoutEffect, useState } from "react";
22

33
/**
44
* Custom hook to get the width of an element and keep it updated when it changes.
5-
* @param target
6-
* @returns
5+
* @param target
6+
* @returns
77
*/
8-
const useWidth = <T extends Element>(target: T | null) => {
8+
const useWidth = <T extends Element>(ref: React.RefObject<T>) => {
99
const [width, setWidth] = useState(0);
1010

1111
useLayoutEffect(() => {
12+
const target = ref?.current;
13+
1214
if (target != null) {
1315
setWidth(target.getBoundingClientRect().width);
1416

@@ -23,7 +25,7 @@ const useWidth = <T extends Element>(target: T | null) => {
2325
triggerObserver.unobserve(target);
2426
};
2527
}
26-
}, [target]);
28+
}, []);
2729

2830
return width;
2931
};

0 commit comments

Comments
 (0)