Skip to content

Commit cfb0e29

Browse files
authored
Merge pull request #6 from kubit-ui/feature/solve-bugs-and-improvements
Comprehensive Accessibility and Usability Enhancements
2 parents 95a0600 + c5cf256 commit cfb0e29

File tree

46 files changed

+386
-344
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+386
-344
lines changed

.storybook/provider/themeProvider.tsx

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -28,71 +28,6 @@ import {
2828
transformDate,
2929
} from '../../src/utils/date';
3030

31-
const orderDate = (
32-
date: string,
33-
format: string,
34-
isRange?: boolean
35-
): { formatSeparator: string | undefined; formattedDate: string } => {
36-
const formatRegex = /[^\p{L}]+/gu;
37-
const dateRegex = /[^\d]+/g;
38-
39-
const formatValueDate = (value: string): string =>
40-
value.replace(/[a-zA-Z,]+/, '').replace(/\s/g, '');
41-
42-
const formattedValue = formatValueDate(date);
43-
44-
// we want always this YYYY-MM-DD format
45-
const formatToOrderDate = 'YYYY-MM-DD';
46-
47-
const correctOrder = formatToOrderDate.split('-');
48-
49-
const newFormat =
50-
format.length > 8
51-
? format
52-
: `${format.slice(0, 2)}-${format.slice(2, 4)}-${format.slice(4)}`;
53-
54-
// to get separator
55-
const formatSeparator = newFormat.match(formatRegex)?.[0];
56-
57-
const formatSplit = newFormat.split(formatRegex);
58-
59-
let dateToCheck: string[] = [];
60-
61-
let formattedDate = '';
62-
63-
// Transform date into YYYY-MM-DD format
64-
const splitDate = (date) => {
65-
return correctOrder.map((element: string) => {
66-
if (element.includes('Y')) {
67-
return date[formatSplit.findIndex((x: string) => x.includes('Y'))];
68-
} else if (element.includes('M')) {
69-
return date[formatSplit.findIndex((x: string) => x.includes('M'))];
70-
} else if (element.includes('D')) {
71-
return date[formatSplit.findIndex((x: string) => x.includes('D'))];
72-
}
73-
});
74-
};
75-
76-
if (formattedValue.length === newFormat.length) {
77-
const dateSplit = formattedValue.split(dateRegex);
78-
79-
dateToCheck = splitDate(dateSplit);
80-
81-
formattedDate = dateToCheck.join('-');
82-
} else if (isRange && date.length > newFormat.length) {
83-
const dateRangeSplit = date.split(dateRegex);
84-
//just take the second date to check
85-
const secondDate = dateRangeSplit.splice(3, 5);
86-
dateToCheck = splitDate(secondDate);
87-
formattedDate = dateToCheck.join('-');
88-
}
89-
90-
return {
91-
formatSeparator,
92-
formattedDate,
93-
};
94-
};
95-
9631
const link = React.forwardRef((props: IGenericLink, ref: unknown) => {
9732
return (
9833
<a
@@ -136,10 +71,7 @@ export const ThemeProvider = ({ children, theme, themeName = 'kubit' }) => {
13671
isBefore: (date1: Date, date2: Date) => {
13772
return isBefore(date1, date2);
13873
},
139-
isDatesEqual: (
140-
firsDate: string | number | Date,
141-
secondDate: string | number | Date
142-
) => {
74+
isDatesEqual: (firsDate: string | number | Date, secondDate: string | number | Date) => {
14375
return isDatesEqual(firsDate, secondDate);
14476
},
14577
getAddDays: (date: Date, days: number) => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@kubit-ui-web/react-components",
3-
"version": "1.1.4",
3+
"version": "1.1.5",
44
"description": "Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience",
55
"author": {
66
"name": "Kubit",

src/components/accordion/accordionStandAlone.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ const AccordionStandAloneComponent = (
149149
<AccordionHeaderTitleHeadlineStyled as={props.triggerComponent}>
150150
{renderTitle()}
151151
</AccordionHeaderTitleHeadlineStyled>
152+
{props.headerRightContent && (
153+
<AccordionHeaderRightContentStyled
154+
data-testid={`${props.dataTestId}RightContent`}
155+
styles={props.styles.headerRightContentContainer}
156+
>
157+
{props.headerRightContent}
158+
</AccordionHeaderRightContentStyled>
159+
)}
152160
</AccordionHeaderMainContainerStyled>
153161
{props.subHeaderContent && (
154162
<AccordionSubHeaderContainerStyled
@@ -159,14 +167,6 @@ const AccordionStandAloneComponent = (
159167
</AccordionSubHeaderContainerStyled>
160168
)}
161169
</AccordionHeaderInternalContainerStyled>
162-
{props.headerRightContent && (
163-
<AccordionHeaderRightContentStyled
164-
data-testid={`${props.dataTestId}RightContent`}
165-
styles={props.styles.headerRightContentContainer}
166-
>
167-
{props.headerRightContent}
168-
</AccordionHeaderRightContentStyled>
169-
)}
170170
</AccordionHeaderExternalContainerStyled>
171171
<AccordionContentStyled
172172
aria-labelledby={TRIGGER_ID}

src/components/button/button.styled.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export const ButtonStyled = styled.button<IButtonStyled>`
5454
flex-direction: ${props =>
5555
props.$iconPosition === IconPositionType.LEFT ? 'row' : 'row-reverse'};
5656
position: relative;
57+
white-space: nowrap;
5758
5859
${({ $state, $styles, $sizeStyles }) => setTokens($state, $styles, $sizeStyles)}
5960

src/components/carousel/__tests__/carousel.test.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ const mockProps: ICarouselUnControlled = {
5757
pageControlArrowsControlVariant: 'DEFAULT',
5858
};
5959

60+
const numPages = Math.ceil(mockProps.elements.length / (mockProps.numElementsPerPage as number));
61+
6062
describe('Carousel component', () => {
6163
it('Carousel', async () => {
6264
const { container, getByTestId } = renderProvider(<CarouselUnControlled {...mockProps} />);
@@ -390,7 +392,7 @@ describe('Carousel component', () => {
390392
allowShift: {
391393
current: true,
392394
},
393-
numPages: Math.ceil(mockProps.elements.length / (mockProps.numElementsPerPage as number)),
395+
numPages,
394396
innerCurrentPage: { current: 0 },
395397
});
396398
jest.spyOn(CarouselHooks, 'useCarousel').mockImplementation(mockMockUseCarousel);
@@ -434,7 +436,7 @@ describe('Carousel component', () => {
434436
allowShift: {
435437
current: true,
436438
},
437-
numPages: Math.ceil(mockProps.elements.length / (mockProps.numElementsPerPage as number)),
439+
numPages,
438440
innerCurrentPage: { current: 0 },
439441
});
440442
jest.spyOn(CarouselHooks, 'useCarousel').mockImplementation(mockMockUseCarousel);
@@ -449,11 +451,14 @@ describe('Carousel component', () => {
449451

450452
const rightArrow = getByLabelText(pageControlAutomateConfig.rightArrow.icon.altText);
451453
const leftArrow = getByLabelText(pageControlAutomateConfig.leftArrow.icon.altText);
454+
const indicator1 = getByLabelText(`Bar 1 of ${numPages}`);
452455

453456
fireEvent.click(rightArrow);
454457
expect(mockHandlePageChange).toHaveBeenCalledWith(1);
455458

456459
fireEvent.click(leftArrow);
457460
expect(mockHandlePageChange).toHaveBeenCalledWith(-1);
461+
462+
expect(indicator1).toBeInTheDocument();
458463
});
459464
});

src/components/carousel/carousel.styled.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getStyles } from '@/utils/getStyles/getStyles';
44

55
import { CarouselArrowStateType, CarouselPropsStylesType } from './types';
66

7-
export const RootStyled = styled.div<{
7+
export const RootStyled = styled.section<{
88
styles: CarouselPropsStylesType;
99
allowModifySliceWidth?: boolean;
1010
}>`

src/components/carousel/carouselStandAlone.tsx

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import * as React from 'react';
44
import { ElementOrIcon } from '@/components/elementOrIcon';
55
import { PageControl } from '@/components/pageControl';
66
import { useId } from '@/hooks';
7+
import { AriaLiveOptionType } from '@/types';
78

89
import { PageControlArrowControlType } from '../pageControl/types';
910
import { PageControlAutomate } from '../pageControlAutomate';
11+
import { ScreenReaderOnly } from '../screenReaderOnly';
1012
import {
1113
ArrowAndCarouselWrapperStyled,
1214
ArrowLeftIconContainer,
@@ -19,6 +21,7 @@ import {
1921
} from './carousel.styled';
2022
import { ExtraPaddingArrowStandAlone } from './components';
2123
import { ICarouselStandAlone } from './types';
24+
import { buildScreenReaderText } from './utils';
2225

2326
const CarouselStandAloneComponent = (
2427
{
@@ -47,6 +50,7 @@ const CarouselStandAloneComponent = (
4750
onMouseOut,
4851
onMouseOver,
4952
playing,
53+
screenReaderText,
5054
...props
5155
}: ICarouselStandAlone,
5256
ref: React.ForwardedRef<HTMLDivElement> | undefined | null
@@ -78,6 +82,7 @@ const CarouselStandAloneComponent = (
7882
ref={ref}
7983
allowModifySliceWidth={allowModifySliceWidth}
8084
aria-labelledby={props['aria-labelledby']}
85+
aria-roledescription="carousel"
8186
data-testid={`${dataTestId}Wrapper`}
8287
styles={styles}
8388
onKeyDown={onKeyDown}
@@ -107,6 +112,7 @@ const CarouselStandAloneComponent = (
107112
>
108113
<CarouselContentStyled
109114
ref={carouselContentRef}
115+
aria-live={playing ? AriaLiveOptionType.OFF : AriaLiveOptionType.POLITE}
110116
centerMode={centerMode}
111117
data-testid={`${dataTestId}Content`}
112118
disableSwipe={disableSwipe}
@@ -135,7 +141,6 @@ const CarouselStandAloneComponent = (
135141
onClick={onRightArrowClick}
136142
/>
137143
</CarouselContainerStyled>
138-
139144
{displayArrowsOnCarousel && numPages > 1 && (
140145
<ArrowRightIconContainer data-disabled={rightArrowDisabled} styles={styles}>
141146
<ElementOrIcon
@@ -151,7 +156,7 @@ const CarouselStandAloneComponent = (
151156
</ArrowRightIconContainer>
152157
)}
153158
</ArrowAndCarouselWrapperStyled>
154-
{hasPagination && numPages > 1 && (
159+
{hasPagination && pageControlArrowsControlVariant && pageControlVariant && numPages > 1 && (
155160
<PageControlContainerStyled styles={styles}>
156161
<PageControl
157162
arrowsControlVariant={pageControlArrowsControlVariant}
@@ -180,6 +185,12 @@ const CarouselStandAloneComponent = (
180185
/>
181186
</PageControlAutomateContainerStyled>
182187
)}
188+
<ScreenReaderOnly
189+
ariaLive={playing ? AriaLiveOptionType.OFF : AriaLiveOptionType.POLITE}
190+
dataTestId={`${dataTestId}CarouselScreenReader`}
191+
>
192+
{buildScreenReaderText(currentPage, numPages, screenReaderText)}
193+
</ScreenReaderOnly>
183194
</RootStyled>
184195
);
185196
};

src/components/carousel/stories/argtypes.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ export const argtypes = (variants: IThemeObjectVariants, themeSelected: string):
190190
},
191191
pageControlVariant: {
192192
description: 'PageControl variant',
193-
type: { name: 'string', required: true },
193+
type: { name: 'string' },
194194
control: { type: 'select' },
195195
options: Object.keys(variants[themeSelected].PageControlVariant || {}),
196196
table: {
@@ -202,9 +202,9 @@ export const argtypes = (variants: IThemeObjectVariants, themeSelected: string):
202202
},
203203
pageControlArrowsControlVariant: {
204204
description: 'PageControl arrows control variant',
205-
type: { name: 'string', required: true },
205+
type: { name: 'string' },
206206
control: { type: 'select' },
207-
options: Object.keys(variants[themeSelected].PageControlAutomateVariant || {}),
207+
options: Object.keys(variants[themeSelected].ArrowsControlVariant || {}),
208208
table: {
209209
type: {
210210
summary: 'string',
@@ -302,6 +302,18 @@ export const argtypes = (variants: IThemeObjectVariants, themeSelected: string):
302302
category: CATEGORY_CONTROL.MODIFIERS,
303303
},
304304
},
305+
screenReaderText: {
306+
description:
307+
'Screen reader carousel text. Can be build using the current bar and the bars length using the keywords "{{currentPage}}" and "{{numPages}}"',
308+
type: { name: 'string' },
309+
control: { type: 'text' },
310+
table: {
311+
type: {
312+
summary: 'string',
313+
},
314+
category: CATEGORY_CONTROL.ACCESIBILITY,
315+
},
316+
},
305317
dataTestId: {
306318
description: 'String used for testing',
307319
control: { type: 'text' },

0 commit comments

Comments
 (0)