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,94 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { vi } from 'vitest';
|
|
5
|
+
import { ThemeContextProvider } from '../../../theme/useTheme';
|
|
6
|
+
import Search from '../Search';
|
|
7
|
+
|
|
8
|
+
describe('Search', () => {
|
|
9
|
+
// Snapshot tests
|
|
10
|
+
|
|
11
|
+
test('snapshot: no props', () => {
|
|
12
|
+
const renderResult = render(
|
|
13
|
+
<ThemeContextProvider>
|
|
14
|
+
<Search />
|
|
15
|
+
</ThemeContextProvider>
|
|
16
|
+
);
|
|
17
|
+
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('snapshot: testId prop', () => {
|
|
21
|
+
const renderResult = render(
|
|
22
|
+
<ThemeContextProvider>
|
|
23
|
+
<Search testId='test123' />
|
|
24
|
+
</ThemeContextProvider>
|
|
25
|
+
);
|
|
26
|
+
expect(renderResult.container.firstChild).toMatchSnapshot();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Interaction tests
|
|
30
|
+
|
|
31
|
+
test('test ID: default', () => {
|
|
32
|
+
render(
|
|
33
|
+
<ThemeContextProvider>
|
|
34
|
+
<Search />
|
|
35
|
+
</ThemeContextProvider>
|
|
36
|
+
);
|
|
37
|
+
const search = screen.getByTestId('ucl-uikit-search');
|
|
38
|
+
expect(search).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('test ID: custom', () => {
|
|
42
|
+
render(
|
|
43
|
+
<ThemeContextProvider>
|
|
44
|
+
<Search testId='custom-test-id' />
|
|
45
|
+
</ThemeContextProvider>
|
|
46
|
+
);
|
|
47
|
+
const search = screen.getByTestId('custom-test-id');
|
|
48
|
+
expect(search).toBeInTheDocument();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('allows user to type in search input', async () => {
|
|
52
|
+
const user = userEvent.setup();
|
|
53
|
+
|
|
54
|
+
render(
|
|
55
|
+
<ThemeContextProvider>
|
|
56
|
+
<Search />
|
|
57
|
+
</ThemeContextProvider>
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const input = screen.getByRole('textbox');
|
|
61
|
+
|
|
62
|
+
await user.type(input, 'hello world');
|
|
63
|
+
expect(input).toHaveValue('hello world');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('allows user to click on search button', async () => {
|
|
67
|
+
const user = userEvent.setup();
|
|
68
|
+
render(
|
|
69
|
+
<ThemeContextProvider>
|
|
70
|
+
<Search />
|
|
71
|
+
</ThemeContextProvider>
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const input = screen.getByTestId('ucl-uikit-search-search-btn');
|
|
75
|
+
await user.click(input);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('calls onSearch when seatch button is clicked', async () => {
|
|
79
|
+
const user = userEvent.setup();
|
|
80
|
+
const mockOnSearch = vi.fn();
|
|
81
|
+
|
|
82
|
+
render(
|
|
83
|
+
<ThemeContextProvider>
|
|
84
|
+
<Search onSearch={mockOnSearch} />
|
|
85
|
+
</ThemeContextProvider>
|
|
86
|
+
);
|
|
87
|
+
const input = screen.getByRole('textbox');
|
|
88
|
+
await user.type(input, 'test search');
|
|
89
|
+
const searchButton = screen.getByTestId('ucl-uikit-search-search-btn');
|
|
90
|
+
await user.click(searchButton);
|
|
91
|
+
|
|
92
|
+
expect(mockOnSearch).toHaveBeenCalledWith('test search');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`Search > snapshot: no props 1`] = `
|
|
4
|
+
<div
|
|
5
|
+
class="ucl-uikit-search css-176lya2"
|
|
6
|
+
>
|
|
7
|
+
<span
|
|
8
|
+
class="ucl-uikit-input css-1bpb1dw"
|
|
9
|
+
>
|
|
10
|
+
<input
|
|
11
|
+
class="ucl-uikit-input__input css-181a0dk"
|
|
12
|
+
data-testid="ucl-uikit-search"
|
|
13
|
+
id=""
|
|
14
|
+
placeholder=""
|
|
15
|
+
type="text"
|
|
16
|
+
value=""
|
|
17
|
+
/>
|
|
18
|
+
</span>
|
|
19
|
+
<div
|
|
20
|
+
class="css-1mxrgm7"
|
|
21
|
+
>
|
|
22
|
+
<button
|
|
23
|
+
aria-label="Clear search"
|
|
24
|
+
class="ucl-uikit-icon-button css-1317vpi"
|
|
25
|
+
data-testid="ucl-uikit-search-clear-search-btn"
|
|
26
|
+
>
|
|
27
|
+
<svg
|
|
28
|
+
class="ucl-uikit-icon css-148hpxb"
|
|
29
|
+
data-testid="ucl-uikit-icon"
|
|
30
|
+
fill="none"
|
|
31
|
+
height="24"
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
stroke-linecap="round"
|
|
34
|
+
stroke-linejoin="round"
|
|
35
|
+
stroke-width="2"
|
|
36
|
+
viewBox="0 0 24 24"
|
|
37
|
+
width="24"
|
|
38
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
39
|
+
>
|
|
40
|
+
<line
|
|
41
|
+
x1="18"
|
|
42
|
+
x2="6"
|
|
43
|
+
y1="6"
|
|
44
|
+
y2="18"
|
|
45
|
+
/>
|
|
46
|
+
<line
|
|
47
|
+
x1="6"
|
|
48
|
+
x2="18"
|
|
49
|
+
y1="6"
|
|
50
|
+
y2="18"
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
</button>
|
|
54
|
+
<div
|
|
55
|
+
class="css-5jwcn5"
|
|
56
|
+
/>
|
|
57
|
+
<button
|
|
58
|
+
aria-label="Search"
|
|
59
|
+
class="ucl-uikit-icon-button css-1soyhl2"
|
|
60
|
+
data-testid="ucl-uikit-search-search-btn"
|
|
61
|
+
>
|
|
62
|
+
<svg
|
|
63
|
+
class="ucl-uikit-icon css-148hpxb"
|
|
64
|
+
data-testid="ucl-uikit-icon"
|
|
65
|
+
fill="none"
|
|
66
|
+
height="24"
|
|
67
|
+
stroke="currentColor"
|
|
68
|
+
stroke-linecap="round"
|
|
69
|
+
stroke-linejoin="round"
|
|
70
|
+
stroke-width="2"
|
|
71
|
+
viewBox="0 0 24 24"
|
|
72
|
+
width="24"
|
|
73
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
74
|
+
>
|
|
75
|
+
<circle
|
|
76
|
+
cx="11"
|
|
77
|
+
cy="11"
|
|
78
|
+
r="8"
|
|
79
|
+
/>
|
|
80
|
+
<line
|
|
81
|
+
x1="21"
|
|
82
|
+
x2="16.65"
|
|
83
|
+
y1="21"
|
|
84
|
+
y2="16.65"
|
|
85
|
+
/>
|
|
86
|
+
</svg>
|
|
87
|
+
</button>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
`;
|
|
91
|
+
|
|
92
|
+
exports[`Search > snapshot: testId prop 1`] = `
|
|
93
|
+
<div
|
|
94
|
+
class="ucl-uikit-search css-176lya2"
|
|
95
|
+
>
|
|
96
|
+
<span
|
|
97
|
+
class="ucl-uikit-input css-1bpb1dw"
|
|
98
|
+
>
|
|
99
|
+
<input
|
|
100
|
+
class="ucl-uikit-input__input css-181a0dk"
|
|
101
|
+
data-testid="test123"
|
|
102
|
+
id=""
|
|
103
|
+
placeholder=""
|
|
104
|
+
type="text"
|
|
105
|
+
value=""
|
|
106
|
+
/>
|
|
107
|
+
</span>
|
|
108
|
+
<div
|
|
109
|
+
class="css-1mxrgm7"
|
|
110
|
+
>
|
|
111
|
+
<button
|
|
112
|
+
aria-label="Clear search"
|
|
113
|
+
class="ucl-uikit-icon-button css-1317vpi"
|
|
114
|
+
data-testid="test123-clear-search-btn"
|
|
115
|
+
>
|
|
116
|
+
<svg
|
|
117
|
+
class="ucl-uikit-icon css-148hpxb"
|
|
118
|
+
data-testid="ucl-uikit-icon"
|
|
119
|
+
fill="none"
|
|
120
|
+
height="24"
|
|
121
|
+
stroke="currentColor"
|
|
122
|
+
stroke-linecap="round"
|
|
123
|
+
stroke-linejoin="round"
|
|
124
|
+
stroke-width="2"
|
|
125
|
+
viewBox="0 0 24 24"
|
|
126
|
+
width="24"
|
|
127
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
128
|
+
>
|
|
129
|
+
<line
|
|
130
|
+
x1="18"
|
|
131
|
+
x2="6"
|
|
132
|
+
y1="6"
|
|
133
|
+
y2="18"
|
|
134
|
+
/>
|
|
135
|
+
<line
|
|
136
|
+
x1="6"
|
|
137
|
+
x2="18"
|
|
138
|
+
y1="6"
|
|
139
|
+
y2="18"
|
|
140
|
+
/>
|
|
141
|
+
</svg>
|
|
142
|
+
</button>
|
|
143
|
+
<div
|
|
144
|
+
class="css-5jwcn5"
|
|
145
|
+
/>
|
|
146
|
+
<button
|
|
147
|
+
aria-label="Search"
|
|
148
|
+
class="ucl-uikit-icon-button css-1soyhl2"
|
|
149
|
+
data-testid="test123-search-btn"
|
|
150
|
+
>
|
|
151
|
+
<svg
|
|
152
|
+
class="ucl-uikit-icon css-148hpxb"
|
|
153
|
+
data-testid="ucl-uikit-icon"
|
|
154
|
+
fill="none"
|
|
155
|
+
height="24"
|
|
156
|
+
stroke="currentColor"
|
|
157
|
+
stroke-linecap="round"
|
|
158
|
+
stroke-linejoin="round"
|
|
159
|
+
stroke-width="2"
|
|
160
|
+
viewBox="0 0 24 24"
|
|
161
|
+
width="24"
|
|
162
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
163
|
+
>
|
|
164
|
+
<circle
|
|
165
|
+
cx="11"
|
|
166
|
+
cy="11"
|
|
167
|
+
r="8"
|
|
168
|
+
/>
|
|
169
|
+
<line
|
|
170
|
+
x1="21"
|
|
171
|
+
x2="16.65"
|
|
172
|
+
y1="21"
|
|
173
|
+
y2="16.65"
|
|
174
|
+
/>
|
|
175
|
+
</svg>
|
|
176
|
+
</button>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
`;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { useArgs } from '@storybook/preview-api';
|
|
3
3
|
import Select from './Select';
|
|
4
|
-
import { Icon } from '../';
|
|
5
4
|
|
|
6
5
|
const meta = {
|
|
7
6
|
title: 'Components/Ready to use/Select',
|
|
@@ -20,8 +19,8 @@ const meta = {
|
|
|
20
19
|
testId: {
|
|
21
20
|
control: { type: 'text' },
|
|
22
21
|
},
|
|
23
|
-
|
|
24
|
-
control: { type: '
|
|
22
|
+
lineBreak: {
|
|
23
|
+
control: { type: 'boolean' },
|
|
25
24
|
},
|
|
26
25
|
},
|
|
27
26
|
args: {
|
|
@@ -41,7 +40,7 @@ type Story = StoryObj<typeof meta>;
|
|
|
41
40
|
export const Default: Story = {
|
|
42
41
|
render: () => {
|
|
43
42
|
const [args, updateArgs] = useArgs();
|
|
44
|
-
const onValueChange = (value: string) => {
|
|
43
|
+
const onValueChange = (value: string | number) => {
|
|
45
44
|
updateArgs({ value });
|
|
46
45
|
};
|
|
47
46
|
return (
|
|
@@ -61,7 +60,7 @@ export const Native: Story = {
|
|
|
61
60
|
},
|
|
62
61
|
render: () => {
|
|
63
62
|
const [args, updateArgs] = useArgs();
|
|
64
|
-
const onValueChange = (value: string) => {
|
|
63
|
+
const onValueChange = (value: string | number) => {
|
|
65
64
|
updateArgs({ value });
|
|
66
65
|
};
|
|
67
66
|
return (
|
|
@@ -75,39 +74,13 @@ export const Native: Story = {
|
|
|
75
74
|
},
|
|
76
75
|
};
|
|
77
76
|
|
|
78
|
-
export const OptionsWithIcons: Story = {
|
|
79
|
-
name: 'Options with icons',
|
|
80
|
-
args: {
|
|
81
|
-
options: [
|
|
82
|
-
{ label: 'Option 1', value: '1', icon: <Icon.Printer /> },
|
|
83
|
-
{ label: 'Option 2', value: '2', icon: <Icon.User /> },
|
|
84
|
-
{ label: 'Option 3', value: '3', icon: <Icon.Info /> },
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
render: () => {
|
|
88
|
-
const [args, updateArgs] = useArgs();
|
|
89
|
-
const onValueChange = (value: string) => {
|
|
90
|
-
updateArgs({ value });
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<Select
|
|
95
|
-
{...args}
|
|
96
|
-
options={args.options}
|
|
97
|
-
value={args.value}
|
|
98
|
-
onValueChange={onValueChange}
|
|
99
|
-
/>
|
|
100
|
-
);
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
|
|
104
77
|
export const Disabled: Story = {
|
|
105
78
|
args: {
|
|
106
79
|
disabled: true,
|
|
107
80
|
},
|
|
108
81
|
render: () => {
|
|
109
82
|
const [args, updateArgs] = useArgs();
|
|
110
|
-
const onValueChange = (value: string) => {
|
|
83
|
+
const onValueChange = (value: string | number) => {
|
|
111
84
|
updateArgs({ value });
|
|
112
85
|
};
|
|
113
86
|
|
|
@@ -126,7 +99,7 @@ export const WithPlaceholder: Story = {
|
|
|
126
99
|
args: { placeholder: 'Please select an option' },
|
|
127
100
|
render: () => {
|
|
128
101
|
const [args, updateArgs] = useArgs();
|
|
129
|
-
const onValueChange = (value: string) => {
|
|
102
|
+
const onValueChange = (value: string | number) => {
|
|
130
103
|
updateArgs({ value });
|
|
131
104
|
};
|
|
132
105
|
|
|
@@ -152,7 +125,7 @@ export const SingleLongOption: Story = {
|
|
|
152
125
|
},
|
|
153
126
|
render: () => {
|
|
154
127
|
const [args, updateArgs] = useArgs();
|
|
155
|
-
const onValueChange = (value: string) => {
|
|
128
|
+
const onValueChange = (value: string | number) => {
|
|
156
129
|
updateArgs({ value });
|
|
157
130
|
};
|
|
158
131
|
|
|
@@ -190,7 +163,7 @@ export const ManyOptions: Story = {
|
|
|
190
163
|
},
|
|
191
164
|
render: () => {
|
|
192
165
|
const [args, updateArgs] = useArgs();
|
|
193
|
-
const onValueChange = (value: string) => {
|
|
166
|
+
const onValueChange = (value: string | number) => {
|
|
194
167
|
updateArgs({ value });
|
|
195
168
|
};
|
|
196
169
|
return (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NativeSelect, CustomSelect } from './subcomponents';
|
|
2
2
|
import { SelectProps } from './Select.types';
|
|
3
3
|
|
|
4
|
-
const Select = (props: SelectProps) => {
|
|
4
|
+
const Select = <T extends string | number = string>(props: SelectProps<T>) => {
|
|
5
5
|
if (props.native) {
|
|
6
6
|
const { onChange, value, ...rest } = props;
|
|
7
7
|
return (
|
|
@@ -14,7 +14,7 @@ const Select = (props: SelectProps) => {
|
|
|
14
14
|
} else {
|
|
15
15
|
const { onValueChange, ...rest } = props;
|
|
16
16
|
return (
|
|
17
|
-
<CustomSelect
|
|
17
|
+
<CustomSelect<T>
|
|
18
18
|
onValueChange={onValueChange}
|
|
19
19
|
{...rest}
|
|
20
20
|
/>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Maps to a native <option> element in <NativeSelect>
|
|
4
4
|
* or a <CustomOption> in <CustomSelect>
|
|
5
5
|
*/
|
|
6
|
-
export type OptionData = {
|
|
6
|
+
export type OptionData<T> = {
|
|
7
7
|
/**
|
|
8
8
|
* Display text shown to the user
|
|
9
9
|
*/
|
|
@@ -12,23 +12,25 @@ export type OptionData = {
|
|
|
12
12
|
* Data-friendly value that is returned when the option is selected
|
|
13
13
|
* We assume this will be submitted to a server or used in some other way
|
|
14
14
|
*/
|
|
15
|
-
value:
|
|
15
|
+
value: T;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
18
|
-
* Only used by <CustomOption>
|
|
19
|
-
* Takes in an actual <Icon> component
|
|
17
|
+
* Apply additional props to a select option component.
|
|
20
18
|
*/
|
|
19
|
+
optionProps?: Record<string, unknown>;
|
|
20
|
+
/**
|
|
21
|
+
Deprecated
|
|
22
|
+
*/
|
|
21
23
|
icon?: React.ReactNode;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* Top level props that <Select> accepts when implemented
|
|
26
28
|
*/
|
|
27
|
-
interface BaseSelectProps {
|
|
29
|
+
interface BaseSelectProps<T = string> {
|
|
28
30
|
/**
|
|
29
31
|
* An array of option data, to be rendered either natively or custom
|
|
30
32
|
*/
|
|
31
|
-
options: OptionData[];
|
|
33
|
+
options: OptionData<T>[];
|
|
32
34
|
/**
|
|
33
35
|
* Placeholder text shown when no option is selected
|
|
34
36
|
* Displayed in visible field of custom implementation
|
|
@@ -70,15 +72,17 @@ interface BaseSelectProps {
|
|
|
70
72
|
* Internal props for the custom implementation, with <div> as root element
|
|
71
73
|
* onChange already exists on <div>. We override it.
|
|
72
74
|
*/
|
|
73
|
-
export type CustomSelectProps = Omit<
|
|
75
|
+
export type CustomSelectProps<T> = Omit<
|
|
74
76
|
React.HTMLAttributes<HTMLDivElement>,
|
|
75
77
|
'onChange'
|
|
76
78
|
> &
|
|
77
|
-
BaseSelectProps & {
|
|
79
|
+
BaseSelectProps<T> & {
|
|
78
80
|
native?: false;
|
|
79
|
-
value?:
|
|
81
|
+
value?: T;
|
|
80
82
|
disabled?: boolean;
|
|
81
|
-
|
|
83
|
+
lineBreak?: boolean;
|
|
84
|
+
panelClassName?: string;
|
|
85
|
+
onValueChange?: (value: T, ev: React.UIEvent) => void;
|
|
82
86
|
ref?: React.RefObject<HTMLDivElement | null>;
|
|
83
87
|
};
|
|
84
88
|
|
|
@@ -92,16 +96,17 @@ export type NativeSelectProps = React.SelectHTMLAttributes<HTMLSelectElement> &
|
|
|
92
96
|
ref?: React.RefObject<HTMLSelectElement | null>;
|
|
93
97
|
};
|
|
94
98
|
|
|
95
|
-
export type SelectProps = NativeSelectProps | CustomSelectProps
|
|
99
|
+
export type SelectProps<T> = NativeSelectProps | CustomSelectProps<T>;
|
|
96
100
|
|
|
97
101
|
/**
|
|
98
102
|
* Each option as displayed in the Panel of <CustomSelect>
|
|
99
103
|
* Roughly equivalent to a custom version of <option>
|
|
100
104
|
*/
|
|
101
|
-
export interface CustomOptionProps
|
|
105
|
+
export interface CustomOptionProps<T>
|
|
102
106
|
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect'> {
|
|
103
|
-
value:
|
|
107
|
+
value: T;
|
|
104
108
|
testId?: string;
|
|
105
109
|
isSelected?: boolean;
|
|
106
|
-
onSelect: (event: React.MouseEvent, value:
|
|
110
|
+
onSelect: (event: React.MouseEvent, value: T) => void;
|
|
111
|
+
lineBreak?: boolean;
|
|
107
112
|
}
|
|
@@ -4,7 +4,7 @@ exports[`Select > Snapshot: default 1`] = `
|
|
|
4
4
|
<div
|
|
5
5
|
aria-expanded="false"
|
|
6
6
|
aria-haspopup="listbox"
|
|
7
|
-
class="ucl-uikit-select css-
|
|
7
|
+
class="ucl-uikit-select css-1g9yg1n"
|
|
8
8
|
data-testid="ucl-uikit-select"
|
|
9
9
|
role="combobox"
|
|
10
10
|
tabindex="0"
|
|
@@ -14,10 +14,10 @@ exports[`Select > Snapshot: default 1`] = `
|
|
|
14
14
|
data-testid="ucl-uikit-select__visible-field"
|
|
15
15
|
>
|
|
16
16
|
<span
|
|
17
|
-
class="css-
|
|
17
|
+
class="css-16t5nns"
|
|
18
18
|
/>
|
|
19
19
|
<svg
|
|
20
|
-
class="ucl-uikit-icon css-
|
|
20
|
+
class="ucl-uikit-icon css-hseitk"
|
|
21
21
|
data-testid="ucl-uikit-icon"
|
|
22
22
|
fill="none"
|
|
23
23
|
height="24"
|
|
@@ -5,15 +5,16 @@ import { CustomOptionProps } from '../Select.types';
|
|
|
5
5
|
|
|
6
6
|
const NAME = 'ucl-uikit-select__option';
|
|
7
7
|
|
|
8
|
-
const CustomOption = ({
|
|
8
|
+
const CustomOption = <T extends string | number>({
|
|
9
9
|
value,
|
|
10
10
|
isSelected = false,
|
|
11
11
|
onSelect,
|
|
12
|
+
lineBreak = false,
|
|
12
13
|
testId = NAME,
|
|
13
14
|
className,
|
|
14
15
|
children,
|
|
15
16
|
...props
|
|
16
|
-
}: CustomOptionProps) => {
|
|
17
|
+
}: CustomOptionProps<T>) => {
|
|
17
18
|
const [theme] = useTheme();
|
|
18
19
|
const internalRef = useRef<HTMLDivElement>(null);
|
|
19
20
|
|
|
@@ -33,30 +34,42 @@ const CustomOption = ({
|
|
|
33
34
|
};
|
|
34
35
|
|
|
35
36
|
const baseStyle = css`
|
|
36
|
-
display: flex;
|
|
37
|
-
align-items: center;
|
|
38
|
-
justify-content: left;
|
|
39
37
|
gap: 16px;
|
|
40
|
-
width: 100%;
|
|
41
38
|
min-height: 40px;
|
|
42
39
|
box-sizing: border-box;
|
|
43
|
-
padding:
|
|
40
|
+
padding: ${theme.padding.p8} ${theme.padding.p16};
|
|
44
41
|
font-family: ${theme.font.family.primary};
|
|
45
42
|
font-size: ${theme.font.size.f16};
|
|
43
|
+
line-height: ${theme.font.lineHeight.h140};
|
|
46
44
|
background-color: ${theme.color.neutral.white};
|
|
47
45
|
overflow: hidden;
|
|
48
|
-
white-space: nowrap;
|
|
49
46
|
|
|
50
47
|
&:hover {
|
|
51
48
|
background-color: ${theme.color.neutral.grey5};
|
|
52
49
|
}
|
|
53
50
|
`;
|
|
54
51
|
|
|
52
|
+
const noLineWrapStyle = css`
|
|
53
|
+
white-space: nowrap;
|
|
54
|
+
text-overflow: ellipsis;
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const lineBreakStyle = css`
|
|
58
|
+
word-break: break-all;
|
|
59
|
+
`;
|
|
60
|
+
|
|
55
61
|
const selectedStyle = css`
|
|
56
62
|
background-color: ${theme.color.neutral.grey5};
|
|
57
63
|
`;
|
|
58
64
|
|
|
59
|
-
const style = cx(
|
|
65
|
+
const style = cx(
|
|
66
|
+
NAME,
|
|
67
|
+
baseStyle,
|
|
68
|
+
!lineBreak && noLineWrapStyle,
|
|
69
|
+
lineBreak && lineBreakStyle,
|
|
70
|
+
isSelected && selectedStyle,
|
|
71
|
+
className
|
|
72
|
+
);
|
|
60
73
|
|
|
61
74
|
return (
|
|
62
75
|
<div
|
|
@@ -5,20 +5,36 @@ import { useTheme } from '../../../theme';
|
|
|
5
5
|
import type { CustomSelectProps } from '../Select.types';
|
|
6
6
|
|
|
7
7
|
const NAME = 'ucl-uikit-select';
|
|
8
|
-
export const DEFAULT_WIDTH_PX = 200;
|
|
9
8
|
|
|
10
|
-
const CustomSelect = ({
|
|
9
|
+
const CustomSelect = <T extends string | number>({
|
|
11
10
|
value,
|
|
12
11
|
options = [],
|
|
13
12
|
onValueChange,
|
|
14
13
|
disabled,
|
|
15
14
|
placeholder,
|
|
16
|
-
|
|
15
|
+
lineBreak = false,
|
|
16
|
+
width,
|
|
17
17
|
testId = NAME,
|
|
18
18
|
className,
|
|
19
|
+
panelClassName,
|
|
19
20
|
ref,
|
|
20
21
|
...props
|
|
21
|
-
}: CustomSelectProps) => {
|
|
22
|
+
}: CustomSelectProps<T>) => {
|
|
23
|
+
// todo: remove width prop (deprecated)
|
|
24
|
+
if (width !== undefined) {
|
|
25
|
+
console.warn(
|
|
26
|
+
'Select width prop is deprecated; it has no effect. Use className instead.'
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const atLeastOneOptionHasIcon = !!options.find(
|
|
31
|
+
(opt) => opt.icon !== undefined
|
|
32
|
+
);
|
|
33
|
+
// todo: remove option icon prop (deprecated)
|
|
34
|
+
if (atLeastOneOptionHasIcon) {
|
|
35
|
+
console.warn('Select option icon prop is deprecated; it has no effect.');
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
const internalRef = useRef<HTMLDivElement>(null);
|
|
23
39
|
const effectiveRef = ref || internalRef;
|
|
24
40
|
|
|
@@ -58,7 +74,7 @@ const CustomSelect = ({
|
|
|
58
74
|
};
|
|
59
75
|
|
|
60
76
|
// Used by <CustomOption> and passed as prop
|
|
61
|
-
const handleSelect = (event: React.MouseEvent, optionValue:
|
|
77
|
+
const handleSelect = (event: React.MouseEvent, optionValue: T) => {
|
|
62
78
|
if (onValueChange) onValueChange(optionValue, event);
|
|
63
79
|
closePanel();
|
|
64
80
|
};
|
|
@@ -134,7 +150,8 @@ const CustomSelect = ({
|
|
|
134
150
|
justify-content: space-between;
|
|
135
151
|
position: relative;
|
|
136
152
|
min-width: 80px;
|
|
137
|
-
width:
|
|
153
|
+
width: 100%;
|
|
154
|
+
max-width: calc(100vw - 64px);
|
|
138
155
|
height: 48px;
|
|
139
156
|
box-sizing: border-box;
|
|
140
157
|
padding: 0 16px;
|
|
@@ -156,10 +173,6 @@ const CustomSelect = ({
|
|
|
156
173
|
}
|
|
157
174
|
`;
|
|
158
175
|
|
|
159
|
-
const widthStyle = css`
|
|
160
|
-
width: ${width}px;
|
|
161
|
-
`;
|
|
162
|
-
|
|
163
176
|
const disabledStyle = css`
|
|
164
177
|
color: ${theme.color.text.disabled};
|
|
165
178
|
border: ${theme.border.b1} solid ${theme.color.neutral.grey20};
|
|
@@ -170,13 +183,7 @@ const CustomSelect = ({
|
|
|
170
183
|
}
|
|
171
184
|
`;
|
|
172
185
|
|
|
173
|
-
const style = cx(
|
|
174
|
-
NAME,
|
|
175
|
-
baseStyle,
|
|
176
|
-
!!width && widthStyle,
|
|
177
|
-
disabled && disabledStyle,
|
|
178
|
-
className
|
|
179
|
-
);
|
|
186
|
+
const style = cx(NAME, baseStyle, disabled && disabledStyle, className);
|
|
180
187
|
|
|
181
188
|
return (
|
|
182
189
|
<div
|
|
@@ -198,17 +205,21 @@ const CustomSelect = ({
|
|
|
198
205
|
disabled={disabled}
|
|
199
206
|
/>
|
|
200
207
|
{isOpen && (
|
|
201
|
-
<Panel
|
|
208
|
+
<Panel
|
|
209
|
+
className={panelClassName}
|
|
210
|
+
role='listbox'
|
|
211
|
+
>
|
|
202
212
|
{options.map((option) => (
|
|
203
|
-
<CustomOption
|
|
213
|
+
<CustomOption<T>
|
|
204
214
|
key={option.value}
|
|
205
215
|
value={option.value}
|
|
206
216
|
isSelected={value === option.value}
|
|
207
217
|
onSelect={handleSelect}
|
|
218
|
+
lineBreak={lineBreak}
|
|
208
219
|
role='option'
|
|
209
220
|
aria-selected={value === option.value}
|
|
221
|
+
{...option.optionProps}
|
|
210
222
|
>
|
|
211
|
-
{option.icon}
|
|
212
223
|
{option.label}
|
|
213
224
|
</CustomOption>
|
|
214
225
|
))}
|