@arbor-education/design-system.components 0.1.2 → 0.1.3
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/.changeset/neat-experts-repair.md +2 -0
- package/.changeset/slick-places-grin.md +5 -0
- package/.changeset/sunny-cars-sell.md +2 -0
- package/.changeset/tough-facts-check.md +5 -0
- package/.changeset/true-rats-add.md +5 -0
- package/.github/workflows/chromatic.yml +2 -1
- package/.github/workflows/release.yml +124 -0
- package/CHANGELOG.md +0 -1
- package/bin/createComponent.sh +39 -9
- package/dist/components/dropdown/Dropdown.d.ts +1 -0
- package/dist/components/dropdown/Dropdown.d.ts.map +1 -1
- package/dist/components/dropdown/DropdownContent.d.ts +1 -0
- package/dist/components/dropdown/DropdownContent.d.ts.map +1 -1
- package/dist/components/dropdown/DropdownContent.js +3 -2
- package/dist/components/dropdown/DropdownContent.js.map +1 -1
- package/dist/components/formField/FormField.d.ts +8 -0
- package/dist/components/formField/FormField.d.ts.map +1 -1
- package/dist/components/formField/FormField.js +3 -1
- package/dist/components/formField/FormField.js.map +1 -1
- package/dist/components/formField/FormField.stories.d.ts.map +1 -1
- package/dist/components/formField/FormField.stories.js +5 -0
- package/dist/components/formField/FormField.stories.js.map +1 -1
- package/dist/components/formField/FormField.test.js +11 -1
- package/dist/components/formField/FormField.test.js.map +1 -1
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts +12 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.d.ts.map +1 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.js +17 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.js.map +1 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.d.ts +10 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.d.ts.map +1 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.js +24 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.js.map +1 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.test.d.ts +2 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.test.d.ts.map +1 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.test.js +88 -0
- package/dist/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.test.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.d.ts +11 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.js +43 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.stories.d.ts +161 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.stories.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.stories.js +172 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.stories.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.test.d.ts +2 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.test.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.test.js +93 -0
- package/dist/components/formField/inputs/dropdown/Dropdown.test.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.d.ts +11 -0
- package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.js +15 -0
- package/dist/components/formField/inputs/dropdown/buttons/dropdownButton/DropdownButton.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.d.ts +10 -0
- package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.js +12 -0
- package/dist/components/formField/inputs/dropdown/items/DropdownItemRenderer.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.d.ts +9 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.js +17 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownItem/DropdownItem.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.d.ts +7 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.js +16 -0
- package/dist/components/formField/inputs/dropdown/items/dropdownMultiLineItem/DropdownMultiLineItem.js.map +1 -0
- package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.d.ts +16 -0
- package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.d.ts.map +1 -0
- package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.js +73 -0
- package/dist/components/formField/inputs/dropdown/wrapper/DropdownWrapper.js.map +1 -0
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts +10 -6
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.d.ts.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.js +10 -6
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.js.map +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.test.js +1 -1
- package/dist/components/formField/inputs/selectDropdown/SelectDropdown.test.js.map +1 -1
- package/dist/components/heading/HeadingInnerContainer.d.ts +5 -0
- package/dist/components/heading/HeadingInnerContainer.d.ts.map +1 -0
- package/dist/components/heading/HeadingInnerContainer.js +7 -0
- package/dist/components/heading/HeadingInnerContainer.js.map +1 -0
- package/dist/components/icon/Icon.d.ts +0 -1
- package/dist/components/icon/Icon.d.ts.map +1 -1
- package/dist/components/icon/Icon.js +1 -1
- package/dist/components/icon/Icon.js.map +1 -1
- package/dist/components/searchBar/SearchBar.d.ts +8 -0
- package/dist/components/searchBar/SearchBar.d.ts.map +1 -0
- package/dist/components/searchBar/SearchBar.js +38 -0
- package/dist/components/searchBar/SearchBar.js.map +1 -0
- package/dist/components/searchBar/SearchBar.test.d.ts +2 -0
- package/dist/components/searchBar/SearchBar.test.d.ts.map +1 -0
- package/dist/components/searchBar/SearchBar.test.js +36 -0
- package/dist/components/searchBar/SearchBar.test.js.map +1 -0
- package/dist/components/slideover/Slideover.d.ts +1 -0
- package/dist/components/slideover/Slideover.d.ts.map +1 -1
- package/dist/components/slideover/Slideover.js +2 -2
- package/dist/components/slideover/Slideover.js.map +1 -1
- package/dist/components/table/HideColumnsDropdown.d.ts +9 -0
- package/dist/components/table/HideColumnsDropdown.d.ts.map +1 -0
- package/dist/components/table/HideColumnsDropdown.js +33 -0
- package/dist/components/table/HideColumnsDropdown.js.map +1 -0
- package/dist/components/table/Table.d.ts +14 -0
- package/dist/components/table/Table.d.ts.map +1 -1
- package/dist/components/table/Table.js +8 -3
- package/dist/components/table/Table.js.map +1 -1
- package/dist/components/table/Table.stories.d.ts +3 -0
- package/dist/components/table/Table.stories.d.ts.map +1 -1
- package/dist/components/table/Table.stories.js +53 -1
- package/dist/components/table/Table.stories.js.map +1 -1
- package/dist/components/table/Table.test.js +132 -0
- package/dist/components/table/Table.test.js.map +1 -1
- package/dist/components/table/TableHeader.d.ts +3 -0
- package/dist/components/table/TableHeader.d.ts.map +1 -1
- package/dist/components/table/TableHeader.js +4 -3
- package/dist/components/table/TableHeader.js.map +1 -1
- package/dist/index.css +93 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/tailwind.css +229 -0
- package/package.json +2 -1
- package/src/components/dropdown/DropdownContent.tsx +4 -2
- package/src/components/formField/FormField.stories.tsx +17 -0
- package/src/components/formField/FormField.test.tsx +13 -1
- package/src/components/formField/FormField.tsx +10 -0
- package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.stories.tsx +29 -0
- package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.test.tsx +121 -0
- package/src/components/formField/inputs/colourPickerDropdown/ColourPickerDropdown.tsx +53 -0
- package/src/components/formField/inputs/colourPickerDropdown/colourPickerDropdown.scss +12 -0
- package/src/components/formField/inputs/selectDropdown/SelectDropdown.test.tsx +1 -1
- package/src/components/formField/inputs/selectDropdown/SelectDropdown.tsx +55 -41
- package/src/components/heading/heading.scss +1 -0
- package/src/components/icon/Icon.tsx +1 -2
- package/src/components/searchBar/SearchBar.test.tsx +40 -0
- package/src/components/searchBar/SearchBar.tsx +97 -0
- package/src/components/searchBar/searchBar.scss +69 -0
- package/src/components/slideover/Slideover.tsx +10 -5
- package/src/components/table/HideColumnsDropdown.tsx +57 -0
- package/src/components/table/Table.stories.tsx +96 -2
- package/src/components/table/Table.test.tsx +240 -0
- package/src/components/table/Table.tsx +10 -1
- package/src/components/table/TableHeader.tsx +8 -0
- package/src/components/table/table.scss +22 -0
- package/src/index.scss +24 -22
- package/src/index.ts +1 -0
- package/.github/workflows/changeset-version.yml +0 -39
- package/.github/workflows/merge-version-packages-pr.yml +0 -31
- package/.github/workflows/production-build.yml +0 -130
- package/release/design-system.components.tgz +0 -0
|
@@ -5,25 +5,33 @@ import { Dropdown } from 'Components/dropdown/Dropdown';
|
|
|
5
5
|
import { Button } from 'Components/button/Button';
|
|
6
6
|
|
|
7
7
|
export type SelectDropdownInputProps = {
|
|
8
|
-
placeholder?: string;
|
|
9
|
-
options: SelectDropdownItemProps[];
|
|
10
|
-
multiple?: boolean;
|
|
11
|
-
disabled?: boolean;
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
'placeholder'?: string;
|
|
9
|
+
'options': SelectDropdownItemProps[];
|
|
10
|
+
'multiple'?: boolean;
|
|
11
|
+
'disabled'?: boolean;
|
|
12
|
+
'hasError'?: boolean;
|
|
13
|
+
'aria-describedBy'?: string;
|
|
14
|
+
'aria-invalid'?: boolean;
|
|
15
|
+
'onSelectionChange'?: (value: string[]) => void;
|
|
16
|
+
'id'?: string;
|
|
17
|
+
'alwaysShowPlaceholder'?: boolean;
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
export const SelectDropdown = (props: SelectDropdownInputProps) => {
|
|
17
|
-
const { options, disabled, multiple, placeholder,
|
|
21
|
+
const { options, disabled, multiple, placeholder, hasError, onSelectionChange, id, 'aria-describedBy': ariaDescribedBy, 'aria-invalid': ariaInvalid, alwaysShowPlaceholder = false } = props;
|
|
18
22
|
|
|
19
23
|
const [selectedValues, setSelectedValues] = useState<string[]>([]);
|
|
20
24
|
const [renderedSelectContent, setRenderedSelectContent] = useState('');
|
|
21
25
|
|
|
22
26
|
useEffect(() => {
|
|
23
|
-
onSelectionChange(selectedValues);
|
|
27
|
+
onSelectionChange?.(selectedValues);
|
|
24
28
|
}, [selectedValues]);
|
|
25
29
|
|
|
26
30
|
useEffect(() => {
|
|
31
|
+
if (alwaysShowPlaceholder) {
|
|
32
|
+
setRenderedSelectContent(placeholder ?? 'Select');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
27
35
|
if (selectedValues.length === 0) {
|
|
28
36
|
setRenderedSelectContent(placeholder ?? 'Select');
|
|
29
37
|
}
|
|
@@ -65,38 +73,44 @@ export const SelectDropdown = (props: SelectDropdownInputProps) => {
|
|
|
65
73
|
};
|
|
66
74
|
|
|
67
75
|
return (
|
|
68
|
-
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
76
|
+
<>
|
|
77
|
+
<input type="hidden" name={id} value={selectedValues.join(',')} />
|
|
78
|
+
<Dropdown>
|
|
79
|
+
<Dropdown.Trigger disabled={disabled}>
|
|
80
|
+
<Button
|
|
81
|
+
variant="dropdown"
|
|
82
|
+
error={hasError}
|
|
83
|
+
iconRightName="chevron-down"
|
|
84
|
+
id={id}
|
|
85
|
+
aria-describedby={ariaDescribedBy}
|
|
86
|
+
aria-invalid={ariaInvalid}
|
|
87
|
+
>
|
|
88
|
+
{renderedSelectContent}
|
|
89
|
+
</Button>
|
|
90
|
+
</Dropdown.Trigger>
|
|
91
|
+
<Dropdown.Content>
|
|
92
|
+
{flatOptions.map(item =>
|
|
93
|
+
'headerLabel' in item
|
|
94
|
+
? (
|
|
95
|
+
<h3 key={`${item.headerLabel}-header`} className="ds-select-dropdown__items--header">
|
|
96
|
+
{item.headerLabel}
|
|
97
|
+
</h3>
|
|
98
|
+
)
|
|
99
|
+
: (
|
|
100
|
+
<SelectDropdownItem
|
|
101
|
+
value={item.value}
|
|
102
|
+
header={item.header}
|
|
103
|
+
label={item.label}
|
|
104
|
+
icon={item.icon}
|
|
105
|
+
key={item.value}
|
|
106
|
+
onSelection={handleItemClick}
|
|
107
|
+
selected={selectedValues.includes(item.value)}
|
|
108
|
+
closeAfterSelection={!multiple}
|
|
109
|
+
/>
|
|
110
|
+
),
|
|
111
|
+
)}
|
|
112
|
+
</Dropdown.Content>
|
|
113
|
+
</Dropdown>
|
|
114
|
+
</>
|
|
101
115
|
);
|
|
102
116
|
};
|
|
@@ -8,7 +8,6 @@ type IconProps = {
|
|
|
8
8
|
screenReaderText?: string;
|
|
9
9
|
name: IconName;
|
|
10
10
|
className?: string;
|
|
11
|
-
ariaLabel?: string;
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
export const Icon = (props: IconProps) => {
|
|
@@ -18,7 +17,7 @@ export const Icon = (props: IconProps) => {
|
|
|
18
17
|
return (
|
|
19
18
|
<>
|
|
20
19
|
{/* why aria-hidden? https://gomakethings.com/revisting-aria-label-versus-a-visually-hidden-class/ */}
|
|
21
|
-
<Component size={size} color={color} className={classes} role="img" aria-hidden
|
|
20
|
+
<Component size={size} color={color} className={classes} role="img" aria-hidden />
|
|
22
21
|
{!!screenReaderText && (
|
|
23
22
|
<span className="sr-only">{screenReaderText}</span>
|
|
24
23
|
)}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { describe, expect, test, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom/vitest';
|
|
4
|
+
import { SearchBar } from './SearchBar';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
|
|
7
|
+
const setSearchMock = vi.fn();
|
|
8
|
+
|
|
9
|
+
describe('SearchBar component', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
setSearchMock.mockClear();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('renders search bar with placeholder text', () => {
|
|
15
|
+
render(<SearchBar setSearchValue={setSearchMock} placeholderText="Search for something" />);
|
|
16
|
+
expect(screen.getByText('Search for something')).toBeInTheDocument();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('renders search bar with icon only', () => {
|
|
20
|
+
render(<SearchBar setSearchValue={setSearchMock} />);
|
|
21
|
+
expect(screen.getByTestId('search-bar-inactive')).toHaveClass('ds-search-bar--inactive-icon-only');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('runs setSearch when input changes', async () => {
|
|
25
|
+
render(<SearchBar setSearchValue={setSearchMock} />);
|
|
26
|
+
await userEvent.click(screen.getByTestId('search-bar-inactive'));
|
|
27
|
+
const input = screen.getByLabelText('Search input');
|
|
28
|
+
fireEvent.change(input, { target: { value: 'Hello' } });
|
|
29
|
+
expect(setSearchMock).toHaveBeenCalledTimes(1);
|
|
30
|
+
expect(setSearchMock).toHaveBeenCalledWith('Hello');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('runs handleClear when clear button is clicked', async () => {
|
|
34
|
+
render(<SearchBar setSearchValue={setSearchMock} />);
|
|
35
|
+
await userEvent.click(screen.getByTestId('search-bar-inactive'));
|
|
36
|
+
await userEvent.click(screen.getByRole('button', { name: 'Clear search' }));
|
|
37
|
+
expect(setSearchMock).toHaveBeenCalledTimes(1);
|
|
38
|
+
expect(setSearchMock).toHaveBeenCalledWith('');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { Button } from 'Components/button/Button';
|
|
3
|
+
import { Icon } from 'Components/icon/Icon';
|
|
4
|
+
import { useRef, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
type SearchBarProps = {
|
|
7
|
+
searchValue?: string;
|
|
8
|
+
setSearchValue?: (searchValue: string) => void;
|
|
9
|
+
placeholderText?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const SearchBar = (props: SearchBarProps) => {
|
|
13
|
+
const { searchValue, setSearchValue, placeholderText } = props;
|
|
14
|
+
|
|
15
|
+
const [isSearchVisible, setIsSearchVisible] = useState(!!searchValue);
|
|
16
|
+
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
17
|
+
|
|
18
|
+
const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
19
|
+
setSearchValue?.(event.target.value);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const handleClear = () => {
|
|
23
|
+
setSearchValue?.('');
|
|
24
|
+
setIsSearchVisible(false);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const handleSearchIconClick = () => {
|
|
28
|
+
setIsSearchVisible(true);
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
searchInputRef.current?.focus();
|
|
31
|
+
}, 0);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const handleClearKeyDown = (event: React.KeyboardEvent<HTMLSpanElement>) => {
|
|
35
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
36
|
+
event.preventDefault();
|
|
37
|
+
handleClear();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (!isSearchVisible) {
|
|
42
|
+
return (
|
|
43
|
+
<Button
|
|
44
|
+
data-testid="search-bar-inactive"
|
|
45
|
+
className={
|
|
46
|
+
classNames('ds-search-bar--inactive', {
|
|
47
|
+
'ds-search-bar--inactive-icon-only': !placeholderText,
|
|
48
|
+
'ds-search-bar--inactive-with-placeholder': placeholderText,
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
onClick={handleSearchIconClick}
|
|
52
|
+
>
|
|
53
|
+
<Icon
|
|
54
|
+
name="search"
|
|
55
|
+
size={16}
|
|
56
|
+
color="var(--search-global-default-color-icon)"
|
|
57
|
+
className="ds-search-bar__icon"
|
|
58
|
+
/>
|
|
59
|
+
{placeholderText
|
|
60
|
+
&& (
|
|
61
|
+
<span className="ds-search-bar--inactive__placeholder">
|
|
62
|
+
{placeholderText}
|
|
63
|
+
</span>
|
|
64
|
+
)}
|
|
65
|
+
</Button>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<span className="ds-search-bar">
|
|
71
|
+
<Icon
|
|
72
|
+
name="search"
|
|
73
|
+
size={16}
|
|
74
|
+
className="ds-search-bar__icon"
|
|
75
|
+
screenReaderText="Search icon"
|
|
76
|
+
/>
|
|
77
|
+
<input
|
|
78
|
+
value={searchValue ?? ''}
|
|
79
|
+
onChange={handleSearch}
|
|
80
|
+
className="ds-search-bar__input"
|
|
81
|
+
type="text"
|
|
82
|
+
ref={searchInputRef}
|
|
83
|
+
aria-label="Search input"
|
|
84
|
+
/>
|
|
85
|
+
<span
|
|
86
|
+
className="ds-search-bar__clear-container"
|
|
87
|
+
role="button"
|
|
88
|
+
tabIndex={0}
|
|
89
|
+
onClick={handleClear}
|
|
90
|
+
onKeyDown={handleClearKeyDown}
|
|
91
|
+
aria-label="Clear search"
|
|
92
|
+
>
|
|
93
|
+
<Icon name="x" size={12} className="ds-search-bar__clear" />
|
|
94
|
+
</span>
|
|
95
|
+
</span>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
.ds-search-bar__icon {
|
|
2
|
+
color: var(--search-global-default-color-icon);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.ds-search-bar {
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
gap: var(--search-global-spacing-horizontal-gap);
|
|
9
|
+
border-radius: var(--search-global-radius);
|
|
10
|
+
background: var(--search-global-default-color-background);
|
|
11
|
+
padding: var(--search-global-spacing-vertical) var(--search-global-spacing-horizontal);
|
|
12
|
+
|
|
13
|
+
&:focus-within {
|
|
14
|
+
background: var(--search-global-focus-color-background);
|
|
15
|
+
box-shadow: 0 0 0 3px var(--color-brand-500);
|
|
16
|
+
|
|
17
|
+
.ds-search-bar__icon {
|
|
18
|
+
color: var(--search-global-focus-color-icon);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.ds-search-bar__clear {
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
display: flex;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.ds-search-bar__input {
|
|
31
|
+
color: var(--search-global-default-color-text);
|
|
32
|
+
background-color: var(--search-global-default-color-background);
|
|
33
|
+
border: none;
|
|
34
|
+
|
|
35
|
+
&:focus {
|
|
36
|
+
outline: none;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ds-search-bar--inactive {
|
|
41
|
+
display: flex;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
width: fit-content;
|
|
44
|
+
height: fit-content;
|
|
45
|
+
align-items: center;
|
|
46
|
+
justify-content: center;
|
|
47
|
+
border: none;
|
|
48
|
+
padding: var(--search-global-spacing-vertical) var(--search-global-spacing-horizontal);
|
|
49
|
+
gap: var(--search-global-spacing-horizontal-gap);
|
|
50
|
+
|
|
51
|
+
&__placeholder {
|
|
52
|
+
color: var(--search-global-default-color-text);
|
|
53
|
+
font-family: var(--type-body-p-family);
|
|
54
|
+
font-size: var(--type-body-p-size);
|
|
55
|
+
font-weight: var(--type-body-p-weight);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&-icon-only {
|
|
59
|
+
padding: var(--search-global-spacing-vertical);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
&:hover {
|
|
63
|
+
background: var(--search-global-hover-color-background);
|
|
64
|
+
|
|
65
|
+
.ds-search-bar__icon {
|
|
66
|
+
color: var(--search-global-hover-color-icon);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -12,18 +12,23 @@ export type SlideoverProps = {
|
|
|
12
12
|
footerContents?: ReactNode;
|
|
13
13
|
headerIcon?: IconName;
|
|
14
14
|
centerHeaderText?: boolean;
|
|
15
|
+
hideBackButton?: boolean;
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
export const Slideover = (props: SlideoverProps) => {
|
|
18
|
-
const { title, children, footerContents, headerIcon, centerHeaderText = true } = props;
|
|
19
|
+
const { title, children, footerContents, headerIcon, centerHeaderText = true, hideBackButton } = props;
|
|
19
20
|
|
|
20
21
|
return (
|
|
21
22
|
<aside className="ds-slideover">
|
|
22
23
|
<div className={classNames('ds-slideover__header', { 'ds-slideover__header--center': centerHeaderText })}>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
{
|
|
25
|
+
!hideBackButton && (
|
|
26
|
+
<Button variant="tertiary" onClick={SlideoverUtils.removeSlideover}>
|
|
27
|
+
<Icon name="chevrons-left" />
|
|
28
|
+
Back
|
|
29
|
+
</Button>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
27
32
|
<Heading level={2}>
|
|
28
33
|
{title}
|
|
29
34
|
{headerIcon && <Icon name={headerIcon} />}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { SelectDropdown } from 'Components/formField/inputs/selectDropdown/SelectDropdown';
|
|
2
|
+
import { useContext, useState } from 'react';
|
|
3
|
+
import { GridApiContext } from './GridApiContext';
|
|
4
|
+
import type { Column } from 'ag-grid-community';
|
|
5
|
+
|
|
6
|
+
type HideColumnsDropdownProps = {
|
|
7
|
+
columns?: Column[];
|
|
8
|
+
onSelectionChanged?: (cols: string[]) => void;
|
|
9
|
+
overrideColumnHiding?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const HideColumnsDropdown = (props: HideColumnsDropdownProps) => {
|
|
13
|
+
const {
|
|
14
|
+
columns: rawColumns,
|
|
15
|
+
onSelectionChanged,
|
|
16
|
+
overrideColumnHiding = false,
|
|
17
|
+
} = props;
|
|
18
|
+
|
|
19
|
+
const gridApi = useContext(GridApiContext);
|
|
20
|
+
const currentColumns = rawColumns || gridApi?.getColumns();
|
|
21
|
+
const [hiddenColumns, setHiddenColumns] = useState<string[]>([]);
|
|
22
|
+
|
|
23
|
+
if (!currentColumns || currentColumns.length === 0) return null;
|
|
24
|
+
|
|
25
|
+
const options = currentColumns.map(column => ({
|
|
26
|
+
label: column.getColDef().headerName,
|
|
27
|
+
selected: column.isVisible(),
|
|
28
|
+
value: column.getColId(),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
const handleVisibilityChange = (columnsToHide: string[]) => {
|
|
32
|
+
if (onSelectionChanged) {
|
|
33
|
+
onSelectionChanged(columnsToHide);
|
|
34
|
+
}
|
|
35
|
+
setHiddenColumns(columnsToHide);
|
|
36
|
+
if (!overrideColumnHiding) {
|
|
37
|
+
const columnsToShow = currentColumns.filter((col) => {
|
|
38
|
+
return !columnsToHide.includes(col.getColId());
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
gridApi?.setColumnsVisible(columnsToHide, false);
|
|
42
|
+
gridApi?.setColumnsVisible(columnsToShow, true);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const placeholderText = hiddenColumns.length > 0 ? `Hide (${hiddenColumns.length})` : 'Hide Columns';
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<SelectDropdown
|
|
50
|
+
multiple
|
|
51
|
+
placeholder={placeholderText}
|
|
52
|
+
options={options}
|
|
53
|
+
onSelectionChange={handleVisibilityChange}
|
|
54
|
+
alwaysShowPlaceholder
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
-
import type
|
|
2
|
+
import { type Column, type ColDef, type ColGroupDef } from 'ag-grid-enterprise';
|
|
3
3
|
import { Table } from './Table';
|
|
4
4
|
import { Button } from 'Components/button/Button';
|
|
5
5
|
import { Icon } from 'Components/icon/Icon';
|
|
@@ -8,6 +8,7 @@ import { BulkActionsDropdown } from './BulkActionsDropdown';
|
|
|
8
8
|
import { useState, type ComponentProps } from 'react';
|
|
9
9
|
import { RowCountInfo } from './pagination/RowCountInfo';
|
|
10
10
|
import { PaginationPanel } from './pagination/PaginationPanel';
|
|
11
|
+
import { HideColumnsDropdown } from './HideColumnsDropdown';
|
|
11
12
|
|
|
12
13
|
type TableProps = ComponentProps<typeof Table>;
|
|
13
14
|
|
|
@@ -62,7 +63,6 @@ const HeaderContent = [
|
|
|
62
63
|
<Button key={1} variant="secondary" size="S">Button 2</Button>
|
|
63
64
|
</div>,
|
|
64
65
|
<div key={1} style={{ display: 'flex', gap: '1rem' }}>
|
|
65
|
-
<Icon name="search" />
|
|
66
66
|
<Icon name="download" />
|
|
67
67
|
<Icon name="settings" />
|
|
68
68
|
<Icon name="circle-help" />
|
|
@@ -105,6 +105,17 @@ export const WithHeader: Story = {
|
|
|
105
105
|
},
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
+
export const WithHeaderAndNoSearch: Story = {
|
|
109
|
+
args: {
|
|
110
|
+
rowData: sampleData,
|
|
111
|
+
columnDefs: sampleColumnDefs,
|
|
112
|
+
defaultColDef: defaultColDef,
|
|
113
|
+
domLayout: 'autoHeight',
|
|
114
|
+
headerContent: HeaderContent,
|
|
115
|
+
hasSearch: false,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
108
119
|
export const WithHeaderAndFooter: Story = {
|
|
109
120
|
args: {
|
|
110
121
|
rowData: sampleData,
|
|
@@ -142,6 +153,89 @@ export const WithBulkActions: Story = {
|
|
|
142
153
|
},
|
|
143
154
|
};
|
|
144
155
|
|
|
156
|
+
export const WithHideColumnsDropdown: Story = {
|
|
157
|
+
args: {
|
|
158
|
+
rowData: sampleData,
|
|
159
|
+
columnDefs: sampleColumnDefs,
|
|
160
|
+
defaultColDef: defaultColDef,
|
|
161
|
+
domLayout: 'autoHeight',
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
163
|
+
// @ts-ignore
|
|
164
|
+
overrideColumnHiding: false,
|
|
165
|
+
},
|
|
166
|
+
render: (args) => {
|
|
167
|
+
const {
|
|
168
|
+
rowData,
|
|
169
|
+
columnDefs,
|
|
170
|
+
defaultColDef,
|
|
171
|
+
domLayout,
|
|
172
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
173
|
+
// @ts-ignore
|
|
174
|
+
overrideColumnHiding,
|
|
175
|
+
} = args;
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
<Table
|
|
179
|
+
rowData={rowData}
|
|
180
|
+
columnDefs={columnDefs}
|
|
181
|
+
defaultColDef={defaultColDef}
|
|
182
|
+
domLayout={domLayout}
|
|
183
|
+
headerContent={(
|
|
184
|
+
<HideColumnsDropdown
|
|
185
|
+
overrideColumnHiding={overrideColumnHiding}
|
|
186
|
+
onSelectionChanged={console.log}
|
|
187
|
+
/>
|
|
188
|
+
)}
|
|
189
|
+
/>
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export const WithRestrictedHideColumnsDropdown: Story = {
|
|
195
|
+
args: {
|
|
196
|
+
rowData: sampleData,
|
|
197
|
+
columnDefs: sampleColumnDefs,
|
|
198
|
+
defaultColDef: defaultColDef,
|
|
199
|
+
domLayout: 'autoHeight',
|
|
200
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
201
|
+
// @ts-ignore
|
|
202
|
+
overrideColumnHiding: false,
|
|
203
|
+
},
|
|
204
|
+
render: (args) => {
|
|
205
|
+
const {
|
|
206
|
+
rowData,
|
|
207
|
+
columnDefs,
|
|
208
|
+
defaultColDef,
|
|
209
|
+
domLayout,
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
211
|
+
// @ts-ignore
|
|
212
|
+
overrideColumnHiding,
|
|
213
|
+
} = args;
|
|
214
|
+
|
|
215
|
+
const [columns, setColumns] = useState<Column[]>([]);
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<Table
|
|
219
|
+
rowData={rowData}
|
|
220
|
+
columnDefs={columnDefs}
|
|
221
|
+
defaultColDef={defaultColDef}
|
|
222
|
+
domLayout={domLayout}
|
|
223
|
+
onGridReady={(params) => {
|
|
224
|
+
const { api } = params;
|
|
225
|
+
setColumns(api.getColumns()?.slice(1) || []);
|
|
226
|
+
}}
|
|
227
|
+
headerContent={(
|
|
228
|
+
<HideColumnsDropdown
|
|
229
|
+
overrideColumnHiding={overrideColumnHiding}
|
|
230
|
+
onSelectionChanged={console.log}
|
|
231
|
+
columns={columns}
|
|
232
|
+
/>
|
|
233
|
+
)}
|
|
234
|
+
/>
|
|
235
|
+
);
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
|
|
145
239
|
export const WithClientSidePagination: StoryObj<TableProps> = {
|
|
146
240
|
args: {
|
|
147
241
|
rowData: sampleData,
|