Skip to content

Commit 8bc1977

Browse files
authored
Merge pull request #32 from kubit-ui/feature/improve-components-and-utilities
Feature/improve components and utilities
2 parents 5e8e0f1 + 1ddd0de commit 8bc1977

File tree

274 files changed

+2585
-1576
lines changed

Some content is hidden

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

274 files changed

+2585
-1576
lines changed

package.json

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@kubit-ui-web/react-components",
3-
"version": "1.14.0",
3+
"version": "1.15.0",
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",
@@ -86,60 +86,60 @@
8686
"sideEffects": false,
8787
"license": "Apache-2.0",
8888
"devDependencies": {
89-
"@babel/core": "^7.25.8",
90-
"@babel/preset-env": "^7.25.8",
91-
"@babel/preset-react": "^7.25.7",
92-
"@babel/preset-typescript": "^7.25.7",
93-
"@eslint/compat": "^1.2.0",
89+
"@babel/core": "^7.26.0",
90+
"@babel/preset-env": "^7.26.0",
91+
"@babel/preset-react": "^7.25.9",
92+
"@babel/preset-typescript": "^7.26.0",
93+
"@eslint/compat": "^1.2.2",
9494
"@eslint/eslintrc": "^3.1.0",
95-
"@eslint/js": "^9.12.0",
96-
"@storybook/addon-a11y": "^8.3.5",
97-
"@storybook/addon-controls": "^8.3.5",
95+
"@eslint/js": "^9.14.0",
96+
"@storybook/addon-a11y": "^8.4.1",
97+
"@storybook/addon-controls": "^8.4.1",
9898
"@storybook/addon-coverage": "^1.0.4",
99-
"@storybook/addon-essentials": "^8.3.5",
100-
"@storybook/addon-interactions": "^8.3.5",
101-
"@storybook/addon-links": "^8.3.5",
102-
"@storybook/addon-themes": "^8.3.5",
103-
"@storybook/blocks": "^8.3.5",
104-
"@storybook/react": "^8.3.5",
105-
"@storybook/react-vite": "^8.3.5",
106-
"@testing-library/jest-dom": "^6.5.0",
99+
"@storybook/addon-essentials": "^8.4.1",
100+
"@storybook/addon-interactions": "^8.4.1",
101+
"@storybook/addon-links": "^8.4.1",
102+
"@storybook/addon-themes": "^8.4.1",
103+
"@storybook/blocks": "^8.4.1",
104+
"@storybook/react": "^8.4.1",
105+
"@storybook/react-vite": "^8.4.1",
106+
"@testing-library/jest-dom": "^6.6.3",
107107
"@testing-library/react": "^16.0.1",
108108
"@testing-library/react-hooks": "^8.0.1",
109109
"@testing-library/user-event": "^14.5.2",
110110
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
111-
"@types/jest": "^29.5.13",
111+
"@types/jest": "^29.5.14",
112112
"@types/jest-axe": "^3.5.9",
113113
"@types/mocha": "^10.0.9",
114-
"@types/react": "^18.3.11",
115-
"@types/react-dom": "^18.3.0",
114+
"@types/react": "^18.3.12",
115+
"@types/react-dom": "^18.3.1",
116116
"@types/styled-components": "^5.1.34",
117117
"@types/ungap__structured-clone": "^1.2.0",
118-
"@typescript-eslint/eslint-plugin": "^8.8.1",
119-
"@typescript-eslint/parser": "^8.8.1",
118+
"@typescript-eslint/eslint-plugin": "^8.12.2",
119+
"@typescript-eslint/parser": "^8.12.2",
120120
"@ungap/structured-clone": "^1.2.0",
121-
"@vitejs/plugin-react": "^4.3.2",
121+
"@vitejs/plugin-react": "^4.3.3",
122122
"babel-jest": "^29.7.0",
123123
"cpy-cli": "^5.0.0",
124-
"eslint": "^9.12.0",
124+
"eslint": "^9.14.0",
125125
"eslint-config-prettier": "^9.1.0",
126126
"eslint-config-standard-with-typescript": "^43.0.1",
127127
"eslint-import-resolver-typescript": "^3.6.3",
128128
"eslint-plugin-import": "^2.31.0",
129129
"eslint-plugin-jest": "^28.8.3",
130-
"eslint-plugin-jsx-a11y": "^6.10.0",
131-
"eslint-plugin-n": "^17.11.1",
130+
"eslint-plugin-jsx-a11y": "^6.10.2",
131+
"eslint-plugin-n": "^17.12.0",
132132
"eslint-plugin-node": "^11.1.0",
133133
"eslint-plugin-prettier": "5.2.1",
134134
"eslint-plugin-promise": "^7.1.0",
135-
"eslint-plugin-react": "^7.37.1",
136-
"eslint-plugin-react-hooks": "^4.6.2",
137-
"eslint-plugin-react-refresh": "^0.4.12",
138-
"eslint-plugin-storybook": "^0.9.0",
135+
"eslint-plugin-react": "^7.37.2",
136+
"eslint-plugin-react-hooks": "^5.0.0",
137+
"eslint-plugin-react-refresh": "^0.4.14",
138+
"eslint-plugin-storybook": "^0.10.2",
139139
"eslint-plugin-unused-imports": "^4.1.4",
140140
"globals": "^15.11.0",
141-
"gts": "^5.3.1",
142-
"html-validate": "^8.24.1",
141+
"gts": "^6.0.2",
142+
"html-validate": "^8.24.2",
143143
"jest": "^29.7.0",
144144
"jest-axe": "^9.0.0",
145145
"jest-canvas-mock": "^2.5.2",
@@ -151,12 +151,12 @@
151151
"prettier": "^3.3.3",
152152
"react-transition-group": "^4.4.5",
153153
"sort-imports": "^1.1.0",
154-
"storybook": "^8.3.5",
154+
"storybook": "^8.4.1",
155155
"ts-jest": "^29.2.5",
156156
"tsc-alias": "1.8.10",
157-
"typedoc": "^0.26.8",
157+
"typedoc": "^0.26.11",
158158
"typescript": "^5.6.3",
159-
"vite": "^5.4.8",
159+
"vite": "^5.4.10",
160160
"vite-tsconfig-paths": "^4.3.2",
161161
"yarn-deduplicate": "^6.0.2"
162162
},

src/components/accordion/accordionStandAlone.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const ACCORDION_BASE_ID = 'AccordionComponent';
3030

3131
const AccordionStandAloneComponent = (
3232
{
33+
dataTestId = 'accordion',
3334
hasHeaderLineSeparator = true,
3435
open = false,
3536
...props
@@ -41,19 +42,19 @@ const AccordionStandAloneComponent = (
4142
const HEADER_ID = `${BASE_ID}-header`;
4243
const PANEL_ID = `${BASE_ID}-panel`;
4344

44-
const getDataTestId = (uniqueId = ''): string => `${props.dataTestId}${uniqueId}`;
45+
const getDataTestId = (uniqueId = ''): string => `${dataTestId}-${uniqueId}`;
4546

4647
return (
4748
<AccordionContainerStyled
4849
ref={ref}
49-
data-testid={getDataTestId()}
50+
data-testid={dataTestId}
5051
id={BASE_ID}
5152
styles={props.styles.container}
5253
>
5354
<AccordionDecorativeBackgroundStyled styles={props.styles.decorative} />
5455
<AccordionHeaderExternalContainerStyled styles={props.styles.headerExternalContainer}>
5556
<AccordionHeaderInternalContainerStyled
56-
data-testid={getDataTestId('Header')}
57+
data-testid={getDataTestId('header')}
5758
id={HEADER_ID}
5859
styles={props.styles.headerInternalContainer}
5960
>
@@ -65,20 +66,19 @@ const AccordionStandAloneComponent = (
6566
<AccordionTriggerStyled
6667
aria-controls={PANEL_ID}
6768
aria-expanded={open}
68-
data-testid={getDataTestId('TriggerButton')}
69+
data-testid={getDataTestId('trigger-button')}
6970
id={TRIGGER_ID}
7071
styles={props.styles[typeof props.title?.content !== 'string' ? 'link' : 'trigger']}
7172
type={ButtonType.BUTTON}
7273
{...props.triggerButton}
7374
>
7475
<AccordionTriggerIconContainerStyled
7576
$rotate={open}
76-
data-testid={`${props.dataTestId}TriggerIconWrapper`}
77+
data-testid={`${dataTestId}-trigger-icon-wrapper`}
7778
styles={props.styles.triggerIconContainer}
7879
>
7980
<ElementOrIcon
8081
customIconStyles={props.styles.triggerIcon}
81-
dataTestId={getDataTestId('TriggerIcon')}
8282
{...props.triggerIcon}
8383
/>
8484
</AccordionTriggerIconContainerStyled>
@@ -87,15 +87,13 @@ const AccordionStandAloneComponent = (
8787
<AccordionTitleIconWrapper styles={props.styles.titleIconContainer}>
8888
<ElementOrIcon
8989
customIconStyles={props.styles.titleIcon}
90-
dataTestId={getDataTestId('TitleIcon')}
9190
{...props.titleIcon}
9291
/>
9392
</AccordionTitleIconWrapper>
9493
)}
9594
<Text
9695
component={TextComponentType.SPAN}
9796
customTypography={props.styles.title}
98-
dataTestId={getDataTestId('TriggerText')}
9997
{...props.title}
10098
>
10199
{props.title?.content}
@@ -105,7 +103,7 @@ const AccordionStandAloneComponent = (
105103
</AccordionHeaderTitleHeadlineStyled>
106104
{props.headerRightContent && (
107105
<AccordionHeaderRightContentStyled
108-
data-testid={`${props.dataTestId}RightContent`}
106+
data-testid={`${dataTestId}-right-content`}
109107
styles={props.styles.headerRightContentContainer}
110108
>
111109
{props.headerRightContent}
@@ -114,7 +112,7 @@ const AccordionStandAloneComponent = (
114112
</AccordionHeaderMainContainerStyled>
115113
{props.subHeaderContent && (
116114
<AccordionSubHeaderContainerStyled
117-
data-testid={`${props.dataTestId}SubHeader`}
115+
data-testid={`${dataTestId}-subheader`}
118116
styles={props.styles.subHeader}
119117
>
120118
{props.subHeaderContent}
@@ -134,11 +132,11 @@ const AccordionStandAloneComponent = (
134132
styles={props.styles.lineSeparatorContainer}
135133
/>
136134
)}
137-
<AccordionPanelStyled data-testid={getDataTestId('Panel')} styles={props.styles.panel}>
135+
<AccordionPanelStyled data-testid={getDataTestId('panel')} styles={props.styles.panel}>
138136
{props.children}
139137
</AccordionPanelStyled>
140138
{props.footerContent && (
141-
<AccordionFooterStyled data-testid={getDataTestId('Footer')} styles={props.styles.footer}>
139+
<AccordionFooterStyled data-testid={getDataTestId('footer')} styles={props.styles.footer}>
142140
{props.footerContent}
143141
</AccordionFooterStyled>
144142
)}

src/components/actionBottomSheet/__tests__/actionBottomSheet.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ describe('ActionBottomSheet component', () => {
3535
expect(results).toHaveNoViolations();
3636
});
3737

38+
it('Should render ActionBottomSheet component but closed', async () => {
39+
const { container } = renderProvider(
40+
<ActionBottomSheet variant={'DEFAULT'}>Hello</ActionBottomSheet>
41+
);
42+
43+
const popover = screen.queryByText('Hello');
44+
expect(popover).not.toBeInTheDocument();
45+
46+
const results = await axe(container);
47+
expect(container).toHTMLValidate({
48+
rules: {
49+
'no-inline-style': 'off',
50+
},
51+
});
52+
expect(results).toHaveNoViolations();
53+
});
54+
3855
it('When no title is used, an aria-dialog-name should be provided', async () => {
3956
const { container } = renderProvider(
4057
<ActionBottomSheet

src/components/actionBottomSheet/actionBottomSheet.styled.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,7 @@ export const ActionBottomSheetContentStyled = styled.div<IActionBottomSheetStyle
6464
}
6565
`}
6666
`;
67+
68+
export const DraggableIcon = styled.div<ActionBottomSheetStylesTypes>`
69+
${props => getStyles(props.styles.dragIconContainer)}
70+
`;

src/components/actionBottomSheet/actionBottomSheetControlled.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as React from 'react';
22

33
import { PopoverControlled as Popover, PopoverComponentType } from '@/components/popover';
44
import { STYLES_NAME } from '@/constants';
5-
import { useDeviceHeight, useId, useMediaDevice, useScrollEffect } from '@/hooks';
5+
import { useDeviceHeight, useId, useMediaDevice, useScrollEffect, useSwipeDown } from '@/hooks';
66
import { useStyles } from '@/hooks/useStyles/useStyles';
77
import { ErrorBoundary, FallbackComponent } from '@/provider/errorBoundary';
88
import { DeviceBreakpointsType, ROLES } from '@/types';
@@ -92,13 +92,32 @@ const ActionBottomSheetControlledComponent = React.forwardRef(
9292
props.ctv
9393
);
9494

95+
const innerRef = React.useRef<HTMLDivElement | null>(null);
96+
React.useImperativeHandle(ref, () => {
97+
return innerRef.current as HTMLDivElement;
98+
}, []);
99+
100+
const { setPopoverRef, setDragIconRef } = useSwipeDown(
101+
popover?.animationOptions,
102+
popover?.onCloseInternally
103+
);
104+
105+
const setInnerRef = React.useCallback(node => {
106+
innerRef.current = node;
107+
const dragIcon = innerRef.current?.querySelector('[data-drag-icon]');
108+
if (dragIcon instanceof HTMLElement) {
109+
setDragIconRef(dragIcon);
110+
}
111+
}, []);
112+
95113
return (
96114
<Popover
97115
aria-labelledby={titleId}
98116
aria-modal={true}
99117
clickOverlayClose={!blocked}
100118
component={PopoverComponentType.DIV}
101119
dataTestId={`${props.dataTestId}Popover`}
120+
forwardedRef={setPopoverRef}
102121
hasBackDrop={true}
103122
open={open}
104123
role={ROLES.DIALOG}
@@ -108,7 +127,7 @@ const ActionBottomSheetControlledComponent = React.forwardRef(
108127
>
109128
<ActionBottomSheetControlledStructure
110129
{...props}
111-
ref={ref}
130+
ref={setInnerRef}
112131
title={{ ...title, id: titleId }}
113132
/>
114133
</Popover>

src/components/actionBottomSheet/actionBottomSheetStandAlone.tsx

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as React from 'react';
33
import { ElementOrIcon } from '@/components/elementOrIcon';
44
import { Text } from '@/components/text/text';
55
import { TextComponentType } from '@/components/text/types/component';
6+
import { DeviceBreakpointsType } from '@/types';
67

78
import { Link } from '../link';
89
import {
@@ -14,11 +15,18 @@ import {
1415
ActionBottomSheetIconSyled,
1516
ActionBottomSheetStyled,
1617
ActionBottomSheetTitleSyled,
18+
DraggableIcon,
1719
} from './actionBottomSheet.styled';
1820
import { IActionBottomSheetStandAlone } from './types';
1921

2022
const ActionBottomSheetStandAloneComponent = (
21-
{ hasHeader = true, scrollableRef, shadowRef, ...props }: IActionBottomSheetStandAlone,
23+
{
24+
dataTestId = 'action-bottom-sheet',
25+
hasHeader = true,
26+
scrollableRef,
27+
shadowRef,
28+
...props
29+
}: IActionBottomSheetStandAlone,
2230
ref: React.ForwardedRef<HTMLDivElement> | undefined | null
2331
): JSX.Element => {
2432
// Parent container Ref
@@ -34,33 +42,37 @@ const ActionBottomSheetStandAloneComponent = (
3442
scrollableRef(actionBottomRef.current);
3543
}, []);
3644

45+
const isMobileOrTablet = [DeviceBreakpointsType.MOBILE, DeviceBreakpointsType.TABLET].includes(
46+
props.device
47+
);
48+
3749
return (
3850
<ActionBottomSheetStyled
3951
ref={actionBottomRef}
4052
$height={props.height}
41-
data-testid={`${props.dataTestId}Container`}
53+
data-testid={dataTestId}
4254
styles={props.styles.container}
4355
>
56+
{props.dragIcon && isMobileOrTablet && (
57+
<DraggableIcon ref={props.dragIconRef} data-drag-icon styles={props.styles}>
58+
<ElementOrIcon {...props.dragIcon} />
59+
</DraggableIcon>
60+
)}
4461
{hasHeader && (
4562
<>
4663
<ActionBottomSheetControlStyled ref={shadowRef} styles={props.styles.controlContainer}>
4764
<ActionBottomSheetActionStyled styles={props.styles.actionLinkContainer}>
4865
{props.actionLink && <Link {...props.actionLink} />}
4966
</ActionBottomSheetActionStyled>
5067
<ActionBottomSheetIconSyled styles={props.styles.closeIconContainer}>
51-
<ElementOrIcon
52-
customIconStyles={props.styles.closeIcon}
53-
dataTestId={`${props.dataTestId}Icon`}
54-
{...props.closeIcon}
55-
/>
68+
<ElementOrIcon customIconStyles={props.styles.closeIcon} {...props.closeIcon} />
5669
</ActionBottomSheetIconSyled>
5770
</ActionBottomSheetControlStyled>
5871
<ActionBottomSheetHeaderStyled styles={props.styles.header}>
5972
<ActionBottomSheetTitleSyled styles={props.styles}>
6073
<Text
6174
component={TextComponentType.H5}
6275
customTypography={props.styles.title}
63-
dataTestId={`${props.dataTestId}Title`}
6476
{...props.title}
6577
>
6678
{props.title?.content}

src/components/actionBottomSheet/stories/argtypes.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,17 @@ export const argtypes = (variants: IThemeObjectVariants, themeSelected: string):
133133
category: CATEGORY_CONTROL.MODIFIERS,
134134
},
135135
},
136+
dragIcon: {
137+
description: 'Add drag icon to swipe down gesture',
138+
type: { name: 'object' },
139+
control: { type: 'object' },
140+
table: {
141+
type: {
142+
summary: 'IElementOrIcon',
143+
},
144+
category: CATEGORY_CONTROL.CONTENT,
145+
},
146+
},
136147
dataTestId: {
137148
description: 'String used for testing',
138149
control: { type: 'text' },

0 commit comments

Comments
 (0)