uikit-react-public 0.11.24 → 0.14.21
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/components/Badge/Badge.d.ts +6 -0
- package/dist/components/Badge/Badge.stories.d.ts +15 -0
- package/dist/components/Badge/index.d.ts +2 -0
- package/dist/components/Button/Button.d.ts +2 -1
- package/dist/components/CookieNotice/CookieNotice.d.ts +16 -0
- package/dist/components/CookieNotice/index.d.ts +2 -0
- package/dist/components/Dialog/BaseDialog.d.ts +7 -2
- package/dist/components/FileInput/FileInput.d.ts +8 -0
- package/dist/components/FileInput/FileInput.stories.d.ts +16 -0
- package/dist/components/FileInput/__tests__/FileInput.test.d.ts +1 -0
- package/dist/components/FileInput/index.d.ts +2 -0
- package/dist/components/Header/Header.d.ts +4 -1
- package/dist/components/Heading/Heading.d.ts +1 -1
- package/dist/components/Link/BaseLink.d.ts +10 -0
- package/dist/components/Link/Link.d.ts +5 -10
- package/dist/components/Link/Link.stories.d.ts +1 -1
- package/dist/components/Link/index.d.ts +1 -1
- package/dist/components/Menu/MenuContent.d.ts +1 -1
- package/dist/components/Menu/MenuItem.d.ts +2 -0
- package/dist/components/Menu/MenuSection.d.ts +1 -1
- package/dist/components/Search/Search.d.ts +16 -0
- package/dist/components/Search/Search.stories.d.ts +34 -0
- package/dist/components/Search/__tests__/Search.test.d.ts +1 -0
- package/dist/components/Search/index.d.ts +2 -0
- package/dist/components/Select/Select.d.ts +1 -1
- package/dist/components/Select/Select.stories.d.ts +3 -7
- package/dist/components/Select/Select.types.d.ts +19 -14
- package/dist/components/Select/subcomponents/CustomOption.d.ts +1 -1
- package/dist/components/Select/subcomponents/CustomSelect.d.ts +1 -2
- package/dist/components/Select/subcomponents/Panel.d.ts +1 -1
- package/dist/components/Select/subcomponents/VisibleField.d.ts +4 -4
- package/dist/components/StandaloneLink/StandaloneLink.d.ts +12 -0
- package/dist/components/StandaloneLink/StandaloneLink.stories.d.ts +13 -0
- package/dist/components/StandaloneLink/__tests__/StandaloneLink.test.d.ts +1 -0
- package/dist/components/StandaloneLink/index.d.ts +2 -0
- package/dist/components/Table/Table.d.ts +10 -8
- package/dist/components/Table/Table.stories.d.ts +21 -0
- package/dist/components/Table/Table.types.d.ts +11 -0
- package/dist/components/Table/__tests__/Table.test.d.ts +1 -0
- package/dist/components/Table/index.d.ts +2 -1
- package/dist/components/Table/subcomponents/Body.d.ts +4 -0
- package/dist/components/Table/subcomponents/Cell/Cell.d.ts +12 -0
- package/dist/components/Table/subcomponents/Cell/Cell.stories.d.ts +313 -0
- package/dist/components/Table/subcomponents/Cell/CellContent.d.ts +10 -0
- package/dist/components/Table/subcomponents/Cell/__tests__/Cell.test.d.ts +1 -0
- package/dist/components/Table/subcomponents/Head.d.ts +4 -0
- package/dist/components/Table/subcomponents/HeadCell/HeadCell.d.ts +13 -0
- package/dist/components/Table/subcomponents/HeadCell/HeadCell.stories.d.ts +312 -0
- package/dist/components/Table/subcomponents/HeadCell/HeadCellContent.d.ts +10 -0
- package/dist/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.d.ts +1 -0
- package/dist/components/Table/subcomponents/Row.d.ts +5 -0
- package/dist/components/Table/subcomponents/SortIcon.d.ts +7 -0
- package/dist/components/Table/subcomponents/index.d.ts +10 -0
- package/dist/components/Tabs/Tab.d.ts +1 -1
- package/dist/components/Tabs/TabContext.d.ts +1 -0
- package/dist/components/Tabs/Tabs.d.ts +3 -1
- package/dist/components/Tabs/Tabs.stories.d.ts +3 -0
- package/dist/components/Timepicker/Timepicker.d.ts +10 -0
- package/dist/components/Timepicker/Timepicker.stories.d.ts +7 -0
- package/dist/components/Timepicker/__tests__/Timepicker.test.d.ts +1 -0
- package/dist/components/Timepicker/index.d.ts +2 -0
- package/dist/components/Timepicker/utils/convertDateToTimeString.d.ts +2 -0
- package/dist/components/Timepicker/utils/convertDateToTimeString.test.d.ts +1 -0
- package/dist/components/Timepicker/utils/index.d.ts +1 -0
- package/dist/components/WeekPicker/WeekPicker.d.ts +3 -0
- package/dist/components/WeekPicker/index.d.ts +1 -0
- package/dist/components/WeekPicker/subcomponents/CustomDatepicker.d.ts +17 -0
- package/dist/components/WeekPicker/subcomponents/DatepickerInput.d.ts +13 -0
- package/dist/components/WeekPicker/subcomponents/VisibleField.d.ts +15 -0
- package/dist/components/WeekPicker/subcomponents/index.d.ts +3 -0
- package/dist/components/index.d.ts +11 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/useFocusTrap.d.ts +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5703 -4448
- package/dist/theme/defaultTheme.d.ts +7 -0
- package/dist/theme/useTheme.d.ts +14 -0
- package/dist/utils/__tests__/capitalise.test.d.ts +1 -0
- package/dist/utils/capitalise.d.ts +2 -0
- package/lib/components/Alert/Alert.tsx +7 -1
- package/lib/components/Alert/__tests__/__snapshots__/Alert.test.tsx.snap +4 -0
- package/lib/components/Badge/Badge.stories.tsx +19 -0
- package/lib/components/Badge/Badge.tsx +48 -0
- package/lib/components/Badge/index.ts +2 -0
- package/lib/components/Breadcrumbs/__tests__/__snapshots__/Breadcrumbs.test.tsx.snap +4 -4
- package/lib/components/Button/Button.tsx +5 -2
- package/lib/components/Calendar/subcomponents/Grid.tsx +0 -1
- package/lib/components/CookieNotice/CookieNotice.tsx +114 -0
- package/lib/components/CookieNotice/index.ts +2 -0
- package/lib/components/Dialog/BaseDialog.tsx +44 -4
- package/lib/components/Field/__tests__/Field.test.tsx +148 -148
- package/lib/components/FileInput/FileInput.stories.tsx +70 -0
- package/lib/components/FileInput/FileInput.tsx +68 -0
- package/lib/components/FileInput/__tests__/FileInput.test.tsx +99 -0
- package/lib/components/FileInput/__tests__/__snapshots__/FileInput.test.tsx.snap +91 -0
- package/lib/components/FileInput/index.ts +2 -0
- package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +25 -25
- package/lib/components/Header/Header.tsx +19 -2
- package/lib/components/Header/__tests__/__snapshots__/Header.test.tsx.snap +4 -4
- package/lib/components/Heading/Documentation.mdx +1 -1
- package/lib/components/Heading/Heading.tsx +1 -1
- package/lib/components/Heading/__tests__/Heading.test.tsx +7 -19
- package/lib/components/Heading/__tests__/__snapshots__/Heading.test.tsx.snap +7 -7
- package/lib/components/Label/Label.tsx +0 -2
- package/lib/components/Label/__tests__/__snapshots__/Label.test.tsx.snap +7 -7
- package/lib/components/Link/BaseLink.tsx +84 -0
- package/lib/components/Link/Link.tsx +72 -32
- package/lib/components/Link/__tests__/__snapshots__/link.test.tsx.snap +3 -3
- package/lib/components/Link/__tests__/link.test.tsx +6 -13
- package/lib/components/Link/index.ts +1 -1
- package/lib/components/Menu/Menu.context.tsx +3 -1
- package/lib/components/Menu/Menu.tsx +2 -2
- package/lib/components/Menu/MenuContent.tsx +5 -5
- package/lib/components/Menu/MenuItem.tsx +20 -3
- package/lib/components/Menu/MenuSection.tsx +4 -3
- package/lib/components/Pagination/PaginationControls.tsx +1 -3
- package/lib/components/Search/Search.stories.tsx +41 -0
- package/lib/components/Search/Search.tsx +167 -0
- package/lib/components/Search/__tests__/Search.test.tsx +94 -0
- package/lib/components/Search/__tests__/__snapshots__/Search.test.tsx.snap +179 -0
- package/lib/components/Search/index.ts +2 -0
- package/lib/components/Select/Select.stories.tsx +8 -35
- package/lib/components/Select/Select.tsx +2 -2
- package/lib/components/Select/Select.types.ts +20 -15
- package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +3 -3
- package/lib/components/Select/subcomponents/CustomOption.tsx +22 -9
- package/lib/components/Select/subcomponents/CustomSelect.tsx +31 -20
- package/lib/components/Select/subcomponents/Panel.tsx +4 -5
- package/lib/components/Select/subcomponents/VisibleField.tsx +26 -22
- package/lib/components/StandaloneLink/StandaloneLink.stories.tsx +32 -0
- package/lib/components/StandaloneLink/StandaloneLink.tsx +183 -0
- package/lib/components/StandaloneLink/__tests__/StandaloneLink.test.tsx +57 -0
- package/lib/components/StandaloneLink/__tests__/__snapshots__/StandaloneLink.test.tsx.snap +19 -0
- package/lib/components/StandaloneLink/index.ts +2 -0
- package/lib/components/Table/Table.stories.tsx +337 -0
- package/lib/components/Table/Table.tsx +42 -67
- package/lib/components/Table/Table.types.ts +14 -0
- package/lib/components/Table/__tests__/Table.test.tsx +121 -0
- package/lib/components/Table/__tests__/__snapshots__/Table.test.tsx.snap +210 -0
- package/lib/components/Table/index.ts +8 -1
- package/lib/components/Table/subcomponents/Body.tsx +18 -0
- package/lib/components/Table/subcomponents/Cell/Cell.stories.tsx +151 -0
- package/lib/components/Table/subcomponents/Cell/Cell.tsx +72 -0
- package/lib/components/Table/subcomponents/Cell/CellContent.tsx +91 -0
- package/lib/components/Table/subcomponents/Cell/__tests__/Cell.test.tsx +115 -0
- package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +107 -0
- package/lib/components/Table/subcomponents/Head.tsx +34 -0
- package/lib/components/Table/subcomponents/HeadCell/HeadCell.stories.tsx +85 -0
- package/lib/components/Table/subcomponents/HeadCell/HeadCell.tsx +99 -0
- package/lib/components/Table/subcomponents/HeadCell/HeadCellContent.tsx +61 -0
- package/lib/components/Table/subcomponents/HeadCell/__tests__/HeadCell.test.tsx +137 -0
- package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +110 -0
- package/lib/components/Table/subcomponents/Row.tsx +49 -0
- package/lib/components/Table/subcomponents/SortIcon.tsx +63 -0
- package/lib/components/Table/subcomponents/index.ts +14 -0
- package/lib/components/Tabs/Tab.tsx +3 -3
- package/lib/components/Tabs/TabContext.tsx +1 -0
- package/lib/components/Tabs/Tabs.stories.tsx +9 -3
- package/lib/components/Tabs/Tabs.tsx +10 -32
- package/lib/components/Tabs/__tests__/Tabs.test.tsx +10 -4
- package/lib/components/Tabs/__tests__/__snapshots__/Tabs.test.tsx.snap +32 -32
- package/lib/components/Timepicker/Timepicker.stories.tsx +43 -0
- package/lib/components/Timepicker/Timepicker.tsx +96 -0
- package/lib/components/Timepicker/__tests__/Timepicker.test.tsx +55 -0
- package/lib/components/Timepicker/__tests__/__snapshots__/Timepicker.test.tsx.snap +19 -0
- package/lib/components/Timepicker/index.tsx +2 -0
- package/lib/components/Timepicker/utils/convertDateToTimeString.test.ts +54 -0
- package/lib/components/Timepicker/utils/convertDateToTimeString.ts +10 -0
- package/lib/components/Timepicker/utils/index.ts +1 -0
- package/lib/components/WeekPicker/WeekPicker.tsx +26 -0
- package/lib/components/WeekPicker/index.ts +1 -0
- package/lib/components/WeekPicker/subcomponents/CustomDatepicker.tsx +298 -0
- package/lib/components/WeekPicker/subcomponents/DatepickerInput.tsx +111 -0
- package/lib/components/WeekPicker/subcomponents/VisibleField.tsx +126 -0
- package/lib/components/WeekPicker/subcomponents/index.ts +3 -0
- package/lib/components/index.ts +17 -0
- package/lib/hooks/index.ts +2 -0
- package/lib/hooks/useFocusTrap.ts +123 -0
- package/lib/index.ts +1 -0
- package/lib/theme/defaultTheme.ts +7 -0
- package/lib/utils/__tests__/capitalise.test.ts +40 -0
- package/lib/utils/capitalise.ts +4 -0
- package/package.json +1 -1
- package/lib/components/Field/__tests__/__snapshots__/Field.test.tsx.snap +0 -300
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useTheme } from '../../../theme';
|
|
2
|
+
import type { SortOrder } from '../Table.types';
|
|
3
|
+
|
|
4
|
+
interface SortingIconProps extends React.SVGAttributes<SVGElement> {
|
|
5
|
+
sortOrder: SortOrder;
|
|
6
|
+
size?: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const SortingIcon = ({ sortOrder, size = 16 }: SortingIconProps) => {
|
|
10
|
+
const [theme] = useTheme();
|
|
11
|
+
|
|
12
|
+
const leftArrowColour =
|
|
13
|
+
sortOrder === 'asc'
|
|
14
|
+
? theme.color.neutral.black
|
|
15
|
+
: theme.color.neutral.grey20;
|
|
16
|
+
const rightArrowColour =
|
|
17
|
+
sortOrder === 'desc'
|
|
18
|
+
? theme.color.neutral.black
|
|
19
|
+
: theme.color.neutral.grey20;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<svg
|
|
23
|
+
width={size}
|
|
24
|
+
height={size}
|
|
25
|
+
viewBox='0 0 48 48'
|
|
26
|
+
fill='none'
|
|
27
|
+
xmlns='http://www.w3.org/2000/svg'
|
|
28
|
+
>
|
|
29
|
+
<g>
|
|
30
|
+
<path
|
|
31
|
+
d='M8 28L15 35L22 28'
|
|
32
|
+
stroke={leftArrowColour}
|
|
33
|
+
strokeWidth='4'
|
|
34
|
+
strokeLinecap='round'
|
|
35
|
+
strokeLinejoin='round'
|
|
36
|
+
/>
|
|
37
|
+
<path
|
|
38
|
+
d='M15 35V10'
|
|
39
|
+
stroke={leftArrowColour}
|
|
40
|
+
strokeWidth='4'
|
|
41
|
+
strokeLinecap='round'
|
|
42
|
+
strokeLinejoin='round'
|
|
43
|
+
/>
|
|
44
|
+
<path
|
|
45
|
+
d='M43 19L36 12L29 19'
|
|
46
|
+
stroke={rightArrowColour}
|
|
47
|
+
strokeWidth='4'
|
|
48
|
+
strokeLinecap='round'
|
|
49
|
+
strokeLinejoin='round'
|
|
50
|
+
/>
|
|
51
|
+
<path
|
|
52
|
+
d='M36 12V37'
|
|
53
|
+
stroke={rightArrowColour}
|
|
54
|
+
strokeWidth='4'
|
|
55
|
+
strokeLinecap='round'
|
|
56
|
+
strokeLinejoin='round'
|
|
57
|
+
/>
|
|
58
|
+
</g>
|
|
59
|
+
</svg>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default SortingIcon;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { default as Head } from './Head';
|
|
2
|
+
export type { TableHeadProps } from './Head';
|
|
3
|
+
|
|
4
|
+
export { default as HeadCell } from './HeadCell/HeadCell';
|
|
5
|
+
export type { TableHeadCellProps } from './HeadCell/HeadCell';
|
|
6
|
+
|
|
7
|
+
export { default as Body } from './Body';
|
|
8
|
+
export type { TableBodyProps } from './Body';
|
|
9
|
+
|
|
10
|
+
export { default as Row } from './Row';
|
|
11
|
+
export type { TableRowProps } from './Row';
|
|
12
|
+
|
|
13
|
+
export { default as Cell } from './Cell/Cell';
|
|
14
|
+
export type { TableCellProps } from './Cell/Cell';
|
|
@@ -3,7 +3,7 @@ import { css, cx } from '@emotion/css';
|
|
|
3
3
|
import { useTheme } from '../../theme';
|
|
4
4
|
import { useTabContext } from './TabContext';
|
|
5
5
|
|
|
6
|
-
export const NAME = 'ucl-uikit-
|
|
6
|
+
export const NAME = 'ucl-uikit-tabs__tab';
|
|
7
7
|
|
|
8
8
|
export interface TabProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
9
9
|
testId?: string;
|
|
@@ -23,7 +23,7 @@ const Tab = ({
|
|
|
23
23
|
...props
|
|
24
24
|
}: TabProps) => {
|
|
25
25
|
const [theme] = useTheme();
|
|
26
|
-
const { activeTab, setActiveTab, fullWidth } = useTabContext();
|
|
26
|
+
const { activeTab, setActiveTab, fullWidth, color } = useTabContext();
|
|
27
27
|
const isActive = activeTab === value;
|
|
28
28
|
|
|
29
29
|
const baseStyle = css`
|
|
@@ -53,7 +53,7 @@ const Tab = ({
|
|
|
53
53
|
`;
|
|
54
54
|
|
|
55
55
|
const activeStyle = css`
|
|
56
|
-
border-bottom: 4px solid ${theme.color.interaction.blue70};
|
|
56
|
+
border-bottom: 4px solid ${color || theme.color.interaction.blue70};
|
|
57
57
|
color: ${theme.color.text.primary};
|
|
58
58
|
margin-bottom: -1px;
|
|
59
59
|
font-weight: 700;
|
|
@@ -7,6 +7,9 @@ const meta = {
|
|
|
7
7
|
parameters: {
|
|
8
8
|
layout: 'padded',
|
|
9
9
|
},
|
|
10
|
+
args: {
|
|
11
|
+
activeTab: '',
|
|
12
|
+
},
|
|
10
13
|
} satisfies Meta<typeof Tabs>;
|
|
11
14
|
|
|
12
15
|
export default meta;
|
|
@@ -15,7 +18,7 @@ type Story = StoryObj<typeof meta>;
|
|
|
15
18
|
export const FullWidth: Story = {
|
|
16
19
|
name: 'Full width',
|
|
17
20
|
render: () => (
|
|
18
|
-
<Tabs>
|
|
21
|
+
<Tabs activeTab='1'>
|
|
19
22
|
<Tabs.Tab
|
|
20
23
|
label='Tab Item 1'
|
|
21
24
|
value='1'
|
|
@@ -39,7 +42,10 @@ export const FullWidth: Story = {
|
|
|
39
42
|
export const AutoWidth: Story = {
|
|
40
43
|
name: 'Auto width',
|
|
41
44
|
render: () => (
|
|
42
|
-
<Tabs
|
|
45
|
+
<Tabs
|
|
46
|
+
activeTab='1'
|
|
47
|
+
fullWidth={false}
|
|
48
|
+
>
|
|
43
49
|
<Tabs.Tab
|
|
44
50
|
label='Tab Item 1'
|
|
45
51
|
value='1'
|
|
@@ -63,7 +69,7 @@ export const AutoWidth: Story = {
|
|
|
63
69
|
export const Counter: Story = {
|
|
64
70
|
name: 'Counter',
|
|
65
71
|
render: () => (
|
|
66
|
-
<Tabs>
|
|
72
|
+
<Tabs activeTab='1'>
|
|
67
73
|
<Tabs.Tab
|
|
68
74
|
counter={12}
|
|
69
75
|
label='Tab Item 1'
|
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
memo,
|
|
3
|
-
HTMLAttributes,
|
|
4
|
-
useState,
|
|
5
|
-
Children,
|
|
6
|
-
isValidElement,
|
|
7
|
-
useEffect,
|
|
8
|
-
} from 'react';
|
|
1
|
+
import { memo, HTMLAttributes } from 'react';
|
|
9
2
|
import { css, cx } from '@emotion/css';
|
|
10
3
|
import { useTheme } from '../../theme';
|
|
11
4
|
import TabContext from './TabContext';
|
|
12
|
-
import Tab
|
|
5
|
+
import Tab from './Tab';
|
|
13
6
|
import marginsStyle, { MarginProps } from '../common/marginsStyle';
|
|
14
7
|
|
|
15
8
|
export const NAME = 'ucl-uikit-tabs';
|
|
16
9
|
|
|
17
10
|
export interface TabsBaseProps
|
|
18
11
|
extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
19
|
-
|
|
12
|
+
activeTab: string;
|
|
20
13
|
onChange?: (value: string) => void;
|
|
21
14
|
fullWidth?: boolean;
|
|
15
|
+
testId?: string;
|
|
16
|
+
color?: string;
|
|
22
17
|
ref?: React.RefObject<HTMLDivElement>;
|
|
23
18
|
}
|
|
24
19
|
|
|
@@ -29,37 +24,19 @@ type TabsComponent = React.FC<TabsProps> & {
|
|
|
29
24
|
};
|
|
30
25
|
|
|
31
26
|
const TabsBase = ({
|
|
27
|
+
activeTab,
|
|
28
|
+
onChange,
|
|
29
|
+
fullWidth = true,
|
|
30
|
+
color,
|
|
32
31
|
testId = NAME,
|
|
33
32
|
className,
|
|
34
33
|
children,
|
|
35
|
-
onChange,
|
|
36
|
-
fullWidth = true,
|
|
37
34
|
ref,
|
|
38
35
|
...props
|
|
39
36
|
}: TabsProps) => {
|
|
40
37
|
const [theme] = useTheme();
|
|
41
|
-
const [activeTab, setActiveTab] = useState<string>('');
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
if (!activeTab) {
|
|
45
|
-
const firstValidTab = Children.toArray(children).find((child) => {
|
|
46
|
-
return (
|
|
47
|
-
isValidElement<TabProps>(child) &&
|
|
48
|
-
child.type === Tab &&
|
|
49
|
-
typeof child.props.value === 'string'
|
|
50
|
-
);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
if (firstValidTab && isValidElement<TabProps>(firstValidTab)) {
|
|
54
|
-
const firstValue = firstValidTab.props.value;
|
|
55
|
-
setActiveTab(firstValue);
|
|
56
|
-
onChange?.(firstValue);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}, [activeTab, children, onChange]);
|
|
60
38
|
|
|
61
39
|
const handleTabChange = (value: string) => {
|
|
62
|
-
setActiveTab(value);
|
|
63
40
|
if (onChange) onChange(value);
|
|
64
41
|
};
|
|
65
42
|
|
|
@@ -77,6 +54,7 @@ const TabsBase = ({
|
|
|
77
54
|
setActiveTab: handleTabChange,
|
|
78
55
|
onChange,
|
|
79
56
|
fullWidth,
|
|
57
|
+
color,
|
|
80
58
|
}}
|
|
81
59
|
>
|
|
82
60
|
<div
|
|
@@ -9,7 +9,7 @@ describe('Tabs', () => {
|
|
|
9
9
|
test('snapshot: Minimal props', () => {
|
|
10
10
|
const renderResult = render(
|
|
11
11
|
<ThemeContextProvider>
|
|
12
|
-
<Tabs>
|
|
12
|
+
<Tabs activeTab='1'>
|
|
13
13
|
<Tabs.Tab
|
|
14
14
|
label='Tab Item 1'
|
|
15
15
|
value='1'
|
|
@@ -35,7 +35,10 @@ describe('Tabs', () => {
|
|
|
35
35
|
test('snapshot: Custom test id', () => {
|
|
36
36
|
const renderResult = render(
|
|
37
37
|
<ThemeContextProvider>
|
|
38
|
-
<Tabs
|
|
38
|
+
<Tabs
|
|
39
|
+
activeTab='1'
|
|
40
|
+
data-testid='custom-test-id'
|
|
41
|
+
>
|
|
39
42
|
<Tabs.Tab
|
|
40
43
|
label='Tab Item 1'
|
|
41
44
|
value='1'
|
|
@@ -61,7 +64,10 @@ describe('Tabs', () => {
|
|
|
61
64
|
test('snapshot: Auto width', () => {
|
|
62
65
|
const renderResult = render(
|
|
63
66
|
<ThemeContextProvider>
|
|
64
|
-
<Tabs
|
|
67
|
+
<Tabs
|
|
68
|
+
activeTab='1'
|
|
69
|
+
fullWidth={false}
|
|
70
|
+
>
|
|
65
71
|
<Tabs.Tab
|
|
66
72
|
label='Tab Item 1'
|
|
67
73
|
value='1'
|
|
@@ -87,7 +93,7 @@ describe('Tabs', () => {
|
|
|
87
93
|
test('snapshot: Counter', () => {
|
|
88
94
|
const renderResult = render(
|
|
89
95
|
<ThemeContextProvider>
|
|
90
|
-
<Tabs>
|
|
96
|
+
<Tabs activeTab='1'>
|
|
91
97
|
<Tabs.Tab
|
|
92
98
|
counter={12}
|
|
93
99
|
label='Tab Item 1'
|
|
@@ -8,8 +8,8 @@ exports[`Tabs > snapshot: Auto width 1`] = `
|
|
|
8
8
|
>
|
|
9
9
|
<button
|
|
10
10
|
aria-selected="true"
|
|
11
|
-
class="ucl-uikit-
|
|
12
|
-
data-testid="ucl-uikit-
|
|
11
|
+
class="ucl-uikit-tabs__tab css-u8nay3"
|
|
12
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
13
13
|
role="tab"
|
|
14
14
|
>
|
|
15
15
|
Tab Item 1
|
|
@@ -17,8 +17,8 @@ exports[`Tabs > snapshot: Auto width 1`] = `
|
|
|
17
17
|
</button>
|
|
18
18
|
<button
|
|
19
19
|
aria-selected="false"
|
|
20
|
-
class="ucl-uikit-
|
|
21
|
-
data-testid="ucl-uikit-
|
|
20
|
+
class="ucl-uikit-tabs__tab css-eoe29w"
|
|
21
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
22
22
|
role="tab"
|
|
23
23
|
>
|
|
24
24
|
Tab Item 2
|
|
@@ -26,8 +26,8 @@ exports[`Tabs > snapshot: Auto width 1`] = `
|
|
|
26
26
|
</button>
|
|
27
27
|
<button
|
|
28
28
|
aria-selected="false"
|
|
29
|
-
class="ucl-uikit-
|
|
30
|
-
data-testid="ucl-uikit-
|
|
29
|
+
class="ucl-uikit-tabs__tab css-eoe29w"
|
|
30
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
31
31
|
role="tab"
|
|
32
32
|
>
|
|
33
33
|
Tab Item 3
|
|
@@ -35,8 +35,8 @@ exports[`Tabs > snapshot: Auto width 1`] = `
|
|
|
35
35
|
</button>
|
|
36
36
|
<button
|
|
37
37
|
aria-selected="false"
|
|
38
|
-
class="ucl-uikit-
|
|
39
|
-
data-testid="ucl-uikit-
|
|
38
|
+
class="ucl-uikit-tabs__tab css-eoe29w"
|
|
39
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
40
40
|
role="tab"
|
|
41
41
|
>
|
|
42
42
|
A longer tab item showing auto width
|
|
@@ -53,8 +53,8 @@ exports[`Tabs > snapshot: Counter 1`] = `
|
|
|
53
53
|
>
|
|
54
54
|
<button
|
|
55
55
|
aria-selected="true"
|
|
56
|
-
class="ucl-uikit-
|
|
57
|
-
data-testid="ucl-uikit-
|
|
56
|
+
class="ucl-uikit-tabs__tab css-1gzur5d"
|
|
57
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
58
58
|
role="tab"
|
|
59
59
|
>
|
|
60
60
|
Tab Item 1
|
|
@@ -63,8 +63,8 @@ exports[`Tabs > snapshot: Counter 1`] = `
|
|
|
63
63
|
</button>
|
|
64
64
|
<button
|
|
65
65
|
aria-selected="false"
|
|
66
|
-
class="ucl-uikit-
|
|
67
|
-
data-testid="ucl-uikit-
|
|
66
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
67
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
68
68
|
role="tab"
|
|
69
69
|
>
|
|
70
70
|
Tab Item 2
|
|
@@ -73,8 +73,8 @@ exports[`Tabs > snapshot: Counter 1`] = `
|
|
|
73
73
|
</button>
|
|
74
74
|
<button
|
|
75
75
|
aria-selected="false"
|
|
76
|
-
class="ucl-uikit-
|
|
77
|
-
data-testid="ucl-uikit-
|
|
76
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
77
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
78
78
|
role="tab"
|
|
79
79
|
>
|
|
80
80
|
Tab Item 3
|
|
@@ -83,8 +83,8 @@ exports[`Tabs > snapshot: Counter 1`] = `
|
|
|
83
83
|
</button>
|
|
84
84
|
<button
|
|
85
85
|
aria-selected="false"
|
|
86
|
-
class="ucl-uikit-
|
|
87
|
-
data-testid="ucl-uikit-
|
|
86
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
87
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
88
88
|
role="tab"
|
|
89
89
|
>
|
|
90
90
|
Tab Item 4
|
|
@@ -102,8 +102,8 @@ exports[`Tabs > snapshot: Custom test id 1`] = `
|
|
|
102
102
|
>
|
|
103
103
|
<button
|
|
104
104
|
aria-selected="true"
|
|
105
|
-
class="ucl-uikit-
|
|
106
|
-
data-testid="ucl-uikit-
|
|
105
|
+
class="ucl-uikit-tabs__tab css-1gzur5d"
|
|
106
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
107
107
|
role="tab"
|
|
108
108
|
>
|
|
109
109
|
Tab Item 1
|
|
@@ -111,8 +111,8 @@ exports[`Tabs > snapshot: Custom test id 1`] = `
|
|
|
111
111
|
</button>
|
|
112
112
|
<button
|
|
113
113
|
aria-selected="false"
|
|
114
|
-
class="ucl-uikit-
|
|
115
|
-
data-testid="ucl-uikit-
|
|
114
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
115
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
116
116
|
role="tab"
|
|
117
117
|
>
|
|
118
118
|
Tab Item 2
|
|
@@ -120,8 +120,8 @@ exports[`Tabs > snapshot: Custom test id 1`] = `
|
|
|
120
120
|
</button>
|
|
121
121
|
<button
|
|
122
122
|
aria-selected="false"
|
|
123
|
-
class="ucl-uikit-
|
|
124
|
-
data-testid="ucl-uikit-
|
|
123
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
124
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
125
125
|
role="tab"
|
|
126
126
|
>
|
|
127
127
|
Tab Item 3
|
|
@@ -129,8 +129,8 @@ exports[`Tabs > snapshot: Custom test id 1`] = `
|
|
|
129
129
|
</button>
|
|
130
130
|
<button
|
|
131
131
|
aria-selected="false"
|
|
132
|
-
class="ucl-uikit-
|
|
133
|
-
data-testid="ucl-uikit-
|
|
132
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
133
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
134
134
|
role="tab"
|
|
135
135
|
>
|
|
136
136
|
Tab Item 4
|
|
@@ -147,8 +147,8 @@ exports[`Tabs > snapshot: Minimal props 1`] = `
|
|
|
147
147
|
>
|
|
148
148
|
<button
|
|
149
149
|
aria-selected="true"
|
|
150
|
-
class="ucl-uikit-
|
|
151
|
-
data-testid="ucl-uikit-
|
|
150
|
+
class="ucl-uikit-tabs__tab css-1gzur5d"
|
|
151
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
152
152
|
role="tab"
|
|
153
153
|
>
|
|
154
154
|
Tab Item 1
|
|
@@ -156,8 +156,8 @@ exports[`Tabs > snapshot: Minimal props 1`] = `
|
|
|
156
156
|
</button>
|
|
157
157
|
<button
|
|
158
158
|
aria-selected="false"
|
|
159
|
-
class="ucl-uikit-
|
|
160
|
-
data-testid="ucl-uikit-
|
|
159
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
160
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
161
161
|
role="tab"
|
|
162
162
|
>
|
|
163
163
|
Tab Item 2
|
|
@@ -165,8 +165,8 @@ exports[`Tabs > snapshot: Minimal props 1`] = `
|
|
|
165
165
|
</button>
|
|
166
166
|
<button
|
|
167
167
|
aria-selected="false"
|
|
168
|
-
class="ucl-uikit-
|
|
169
|
-
data-testid="ucl-uikit-
|
|
168
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
169
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
170
170
|
role="tab"
|
|
171
171
|
>
|
|
172
172
|
Tab Item 3
|
|
@@ -174,8 +174,8 @@ exports[`Tabs > snapshot: Minimal props 1`] = `
|
|
|
174
174
|
</button>
|
|
175
175
|
<button
|
|
176
176
|
aria-selected="false"
|
|
177
|
-
class="ucl-uikit-
|
|
178
|
-
data-testid="ucl-uikit-
|
|
177
|
+
class="ucl-uikit-tabs__tab css-b3abfp"
|
|
178
|
+
data-testid="ucl-uikit-tabs__tab"
|
|
179
179
|
role="tab"
|
|
180
180
|
>
|
|
181
181
|
Tab Item 4
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import Timepicker from './Timepicker';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Timepicker> = {
|
|
6
|
+
title: 'Components/Work in progress/TimePicker',
|
|
7
|
+
component: Timepicker,
|
|
8
|
+
decorators: [(Story) => <Story />],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof Timepicker>;
|
|
14
|
+
|
|
15
|
+
export const WithInitialTime: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
value: new Date('1970-01-01T12:30:00'),
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Controlled: Story = {
|
|
22
|
+
render: () => {
|
|
23
|
+
const [time, setTime] = useState<Date | null>(
|
|
24
|
+
new Date('1970-01-01T12:30:00')
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const handleChange = (
|
|
28
|
+
value: Date | null,
|
|
29
|
+
event: React.ChangeEvent<HTMLInputElement>
|
|
30
|
+
) => {
|
|
31
|
+
setTime(value);
|
|
32
|
+
console.log('Selected time as Date object:', value, event);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Timepicker
|
|
37
|
+
value={time}
|
|
38
|
+
onValueChange={handleChange}
|
|
39
|
+
testId='controlled-timepicker'
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { InputHTMLAttributes } from 'react';
|
|
2
|
+
import { css, cx } from '@emotion/css';
|
|
3
|
+
import { useTheme } from '../../theme';
|
|
4
|
+
import { convertDatetoTimeString } from './utils';
|
|
5
|
+
|
|
6
|
+
export const NAME = 'ucl-uikit-timepicker';
|
|
7
|
+
|
|
8
|
+
export type TimepickerValue = Date | null;
|
|
9
|
+
|
|
10
|
+
export interface TimepickerProps
|
|
11
|
+
extends Omit<InputHTMLAttributes<HTMLInputElement>, 'value'> {
|
|
12
|
+
testId?: string;
|
|
13
|
+
value?: TimepickerValue;
|
|
14
|
+
onValueChange?: (
|
|
15
|
+
value: TimepickerValue,
|
|
16
|
+
event: React.ChangeEvent<HTMLInputElement>
|
|
17
|
+
) => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const Timepicker = ({
|
|
21
|
+
testId = NAME,
|
|
22
|
+
value,
|
|
23
|
+
className,
|
|
24
|
+
onValueChange,
|
|
25
|
+
...props
|
|
26
|
+
}: TimepickerProps) => {
|
|
27
|
+
const [theme] = useTheme();
|
|
28
|
+
|
|
29
|
+
const baseStyle = css`
|
|
30
|
+
color: ${theme.color.text.primary};
|
|
31
|
+
border-radius: ${theme.radius.r4};
|
|
32
|
+
font-size: ${theme.font.size.f24};
|
|
33
|
+
border-color: ${theme.color.text.primary};
|
|
34
|
+
font-family: ${theme.font.family.primary};
|
|
35
|
+
padding: ${theme.padding.p4};
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const style = cx(NAME, baseStyle, className);
|
|
39
|
+
|
|
40
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
41
|
+
const inputValue = e.target.value;
|
|
42
|
+
|
|
43
|
+
// Ensure the value is not nullish and contains a colon
|
|
44
|
+
if (!inputValue || !inputValue.includes(':')) {
|
|
45
|
+
console.error('Invalid time format:', inputValue);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const parts = inputValue.split(':');
|
|
50
|
+
|
|
51
|
+
// Ensure the value splits into exactly two parts (hours and minutes)
|
|
52
|
+
if (parts.length !== 2) {
|
|
53
|
+
console.error('Invalid time format:', inputValue);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const [hoursStr, minutesStr] = parts;
|
|
58
|
+
|
|
59
|
+
// Convert hours and minutes to numbers
|
|
60
|
+
const hours = Number(hoursStr);
|
|
61
|
+
const minutes = Number(minutesStr);
|
|
62
|
+
|
|
63
|
+
// Validate that hours and minutes are within valid ranges
|
|
64
|
+
if (
|
|
65
|
+
Number.isNaN(hours) ||
|
|
66
|
+
Number.isNaN(minutes) ||
|
|
67
|
+
hours < 0 ||
|
|
68
|
+
hours > 23 ||
|
|
69
|
+
minutes < 0 ||
|
|
70
|
+
minutes > 59
|
|
71
|
+
) {
|
|
72
|
+
console.error('Invalid time values:', { hours, minutes });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Utilises previous date (state) if available and value is not null
|
|
76
|
+
const date = value ? new Date(value) : new Date();
|
|
77
|
+
date.setHours(hours, minutes, 0, 0);
|
|
78
|
+
|
|
79
|
+
if (onValueChange) {
|
|
80
|
+
onValueChange(date, e);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<input
|
|
86
|
+
value={convertDatetoTimeString(value ?? null)}
|
|
87
|
+
onChange={handleChange}
|
|
88
|
+
className={style}
|
|
89
|
+
data-testid={testId}
|
|
90
|
+
type='time'
|
|
91
|
+
{...props}
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export default Timepicker;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import Timepicker from '../Timepicker';
|
|
4
|
+
import { ThemeContextProvider } from '../../../theme/useTheme';
|
|
5
|
+
|
|
6
|
+
describe('Timepicker', () => {
|
|
7
|
+
// Snapshot tests
|
|
8
|
+
|
|
9
|
+
test('snapshot', () => {
|
|
10
|
+
const renderResult = render(
|
|
11
|
+
<ThemeContextProvider>
|
|
12
|
+
<Timepicker />
|
|
13
|
+
</ThemeContextProvider>
|
|
14
|
+
);
|
|
15
|
+
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('snapshot: testID prop', () => {
|
|
19
|
+
const renderResult = render(
|
|
20
|
+
<ThemeContextProvider>
|
|
21
|
+
<Timepicker testId='testId' />
|
|
22
|
+
</ThemeContextProvider>
|
|
23
|
+
);
|
|
24
|
+
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('test ID: default', () => {
|
|
28
|
+
render(
|
|
29
|
+
<ThemeContextProvider>
|
|
30
|
+
<Timepicker />
|
|
31
|
+
</ThemeContextProvider>
|
|
32
|
+
);
|
|
33
|
+
const timePicker = screen.getByTestId('ucl-uikit-timepicker');
|
|
34
|
+
expect(timePicker).toBeDefined();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('test ID: custom', () => {
|
|
38
|
+
render(
|
|
39
|
+
<ThemeContextProvider>
|
|
40
|
+
<Timepicker testId='custom-test-id' />
|
|
41
|
+
</ThemeContextProvider>
|
|
42
|
+
);
|
|
43
|
+
const timePicker = screen.getByTestId('custom-test-id');
|
|
44
|
+
expect(timePicker).toBeDefined();
|
|
45
|
+
});
|
|
46
|
+
// Test rendering with props
|
|
47
|
+
test('renders with initial time', () => {
|
|
48
|
+
const { getByDisplayValue } = render(
|
|
49
|
+
<ThemeContextProvider>
|
|
50
|
+
<Timepicker value={new Date('1970-01-01T12:30:00')} />
|
|
51
|
+
</ThemeContextProvider>
|
|
52
|
+
);
|
|
53
|
+
expect(getByDisplayValue('12:30')).toBeInTheDocument();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Timepicker > snapshot 1`] = `
|
|
4
|
+
<input
|
|
5
|
+
class="ucl-uikit-timepicker css-ihuem"
|
|
6
|
+
data-testid="ucl-uikit-timepicker"
|
|
7
|
+
type="time"
|
|
8
|
+
value=""
|
|
9
|
+
/>
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports[`Timepicker > snapshot: testID prop 1`] = `
|
|
13
|
+
<input
|
|
14
|
+
class="ucl-uikit-timepicker css-ihuem"
|
|
15
|
+
data-testid="testId"
|
|
16
|
+
type="time"
|
|
17
|
+
value=""
|
|
18
|
+
/>
|
|
19
|
+
`;
|