@scality/core-ui 0.135.0 → 0.136.0

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.
Files changed (47) hide show
  1. package/dist/components/searchinput/SearchInput.component.d.ts +0 -1
  2. package/dist/components/searchinput/SearchInput.component.d.ts.map +1 -1
  3. package/dist/components/searchinput/SearchInput.component.js +1 -1
  4. package/dist/components/selectv2/Selectv2.component.d.ts +1 -1
  5. package/dist/components/selectv2/Selectv2.component.d.ts.map +1 -1
  6. package/dist/components/selectv2/Selectv2.component.js +5 -9
  7. package/dist/components/tablev2/Search.d.ts +1 -1
  8. package/dist/components/tablev2/Search.d.ts.map +1 -1
  9. package/dist/components/tablev2/Search.js +1 -1
  10. package/dist/components/tablev2/TableCommon.d.ts +1 -1
  11. package/dist/components/tablev2/TableCommon.js +3 -3
  12. package/dist/components/tablev2/Tablestyle.d.ts +1 -1
  13. package/dist/components/tablev2/Tablestyle.d.ts.map +1 -1
  14. package/dist/components/tablev2/Tablev2.component.d.ts +5 -1
  15. package/dist/components/tablev2/Tablev2.component.d.ts.map +1 -1
  16. package/dist/components/tablev2/Tablev2.component.js +6 -0
  17. package/dist/components/tablev2/useSyncedScroll.d.ts +2 -1
  18. package/dist/components/tablev2/useSyncedScroll.d.ts.map +1 -1
  19. package/dist/components/tablev2/useSyncedScroll.js +17 -19
  20. package/dist/components/tabsv2/StyledTabs.d.ts +1 -1
  21. package/dist/components/tabsv2/StyledTabs.d.ts.map +1 -1
  22. package/dist/components/tabsv2/Tabsv2.component.js +5 -1
  23. package/dist/components/toggle/Toggle.component.d.ts +1 -1
  24. package/dist/components/toggle/Toggle.component.d.ts.map +1 -1
  25. package/dist/components/toggle/Toggle.component.js +8 -11
  26. package/dist/organisms/attachments/AttachmentTable.d.ts.map +1 -1
  27. package/dist/organisms/attachments/AttachmentTable.js +2 -2
  28. package/package.json +2 -2
  29. package/src/lib/components/searchinput/SearchInput.component.tsx +0 -2
  30. package/src/lib/components/searchinput/SearchInput.test.tsx +88 -0
  31. package/src/lib/components/selectv2/Selectv2.component.tsx +7 -11
  32. package/src/lib/components/selectv2/selectv2.test.tsx +190 -200
  33. package/src/lib/components/tablev2/Search.tsx +1 -2
  34. package/src/lib/components/tablev2/TableCommon.tsx +5 -5
  35. package/src/lib/components/tablev2/Tablestyle.tsx +1 -1
  36. package/src/lib/components/tablev2/Tablev2.component.tsx +14 -0
  37. package/src/lib/components/tablev2/useSyncedScroll.ts +22 -24
  38. package/src/lib/components/tabsv2/StyledTabs.ts +1 -1
  39. package/src/lib/components/tabsv2/Tabsv2.component.tsx +1 -1
  40. package/src/lib/components/toggle/Toggle.component.tsx +9 -12
  41. package/src/lib/components/toggle/Toggle.test.tsx +56 -0
  42. package/src/lib/organisms/attachments/AttachmentTable.tsx +0 -2
  43. package/stories/SearchInput/searchinput.guideline.mdx +20 -0
  44. package/stories/{searchinput.stories.tsx → SearchInput/searchinput.stories.tsx} +13 -20
  45. package/stories/Select/selectv2.stories.tsx +23 -5
  46. package/stories/Toggle/toggle.guideline.mdx +20 -0
  47. package/stories/{toggle.stories.tsx → Toggle/toggle.stories.tsx} +17 -10
@@ -135,7 +135,11 @@ const InternalOption = (width, isDefaultVariant) => (props) => {
135
135
  ? 'sc-highlighted-matching-text'
136
136
  : '';
137
137
  return (
138
- <span key={i} className={highlightStyle}>
138
+ <span
139
+ role={highlightStyle ? 'mark' : undefined}
140
+ key={i}
141
+ className={highlightStyle}
142
+ >
139
143
  {part}
140
144
  </span>
141
145
  );
@@ -238,7 +242,6 @@ const MenuList = (props) => {
238
242
  selectedIndex * optionHeight - (ITEMS_PER_SCROLL_WINDOW - 1) * optionHeight;
239
243
  useEffect(() => {
240
244
  if (listRef && listRef.current) {
241
- // @ts-ignore
242
245
  listRef.current.scrollTo(
243
246
  getScrollOffset(
244
247
  listRef.current,
@@ -282,6 +285,7 @@ const ValueContainer = ({ children, ...props }) => {
282
285
  const icon = selectedOption ? selectedOption.icon : null;
283
286
  const ariaProps = {
284
287
  innerProps: {
288
+ disabled: true,
285
289
  role: props.selectProps.isSearchable ? 'combobox' : 'listbox',
286
290
  'aria-expanded': props.selectProps.menuIsOpen,
287
291
  'aria-autocomplete': 'list',
@@ -302,7 +306,6 @@ export type SelectProps = {
302
306
  placeholder?: string;
303
307
  disabled?: boolean;
304
308
  children?: React.ReactNode;
305
- defaultValue?: string;
306
309
  value?: string;
307
310
  onFocus?: (event: FocusEvent) => void;
308
311
  onBlur?: (event: FocusEvent) => void;
@@ -310,6 +313,7 @@ export type SelectProps = {
310
313
  variant?: 'default' | 'rounded';
311
314
  size?: '1' | '2/3' | '1/2' | '1/3';
312
315
  className?: string;
316
+ /** use menuPositon='fixed' inside modal to avoid display issue */
313
317
  menuPosition?: 'fixed' | 'absolute';
314
318
  };
315
319
  type SelectOptionProps = {
@@ -357,7 +361,6 @@ function SelectWithOptionContext(props: SelectProps) {
357
361
  function SelectBox({
358
362
  placeholder = 'Select...',
359
363
  disabled = false,
360
- defaultValue,
361
364
  value,
362
365
  onChange,
363
366
  variant = 'default',
@@ -366,11 +369,6 @@ function SelectBox({
366
369
  id,
367
370
  ...rest
368
371
  }: SelectProps) {
369
- if (defaultValue && value) {
370
- console.error(
371
- 'The `defaultValue` will be overridden by the `value` if they are set at the same time.',
372
- );
373
- }
374
372
  const [keyboardFocusEnabled, setKeyboardFocusEnabled] = useState(false);
375
373
  const [searchSelection, setSearchSelection] = useState('');
376
374
  const [searchValue, setSearchValue] = useState('');
@@ -414,7 +412,6 @@ function SelectBox({
414
412
  // Force to reset the value
415
413
  useEffect(() => {
416
414
  if (
417
- !defaultValue &&
418
415
  !isEmptyStringInOptions &&
419
416
  value === '' &&
420
417
  selectRef.current &&
@@ -436,7 +433,6 @@ function SelectBox({
436
433
  value={
437
434
  searchSelection || options.find((opt) => opt.value === value)
438
435
  }
439
- defaultValue={defaultValue}
440
436
  inputValue={options.length > NOPT_SEARCH ? searchValue : undefined}
441
437
  selectedOption={options.find((opt) => opt.value === value)}
442
438
  keyboardFocusEnabled={keyboardFocusEnabled}
@@ -1,13 +1,7 @@
1
- import {
2
- screen,
3
- render as testingRender,
4
- within,
5
- } from '@testing-library/react';
1
+ import { screen, render as testingRender } from '@testing-library/react';
6
2
  import userEvent from '@testing-library/user-event';
7
3
  import React, { useState } from 'react';
8
4
  import { QueryClient, QueryClientProvider } from 'react-query';
9
- import { debug } from 'jest-preview';
10
- import { Icon } from '../icon/Icon.component';
11
5
  import { Option, Select } from '../selectv2/Selectv2.component';
12
6
 
13
7
  const render = (args) => {
@@ -27,26 +21,24 @@ const generateOptionsData = (n: number) =>
27
21
 
28
22
  const generateOptions = (n: number) => {
29
23
  return generateOptionsData(n).map((o, i) => (
30
- <Option key={i} value={o.value} {...o}>
24
+ <Option key={i} {...o} value={o.value}>
31
25
  {o.label}
32
26
  </Option>
33
27
  ));
34
28
  };
29
+ const optionsWithScrollSearchBar = generateOptions(10); // more than 8 options should display searchbar + scrollbar
30
+
31
+ const simpleOptions = generateOptions(4); // less than 5 options should not displays any scroll/search bar
35
32
 
36
33
  const SelectWrapper = (props) => {
37
- const [value, setValue] = useState(null);
34
+ const [value, setValue] = useState<string | null>(null);
38
35
  return (
39
36
  <Select value={value} onChange={(value) => setValue(value)} {...props}>
40
- {props.children}
37
+ {props.children || simpleOptions}
41
38
  </Select>
42
39
  );
43
40
  };
44
41
 
45
- const variants = ['default', 'rounded'];
46
- const optionsWithScrollSearchBar = generateOptions(10); // more than 8 options should display searchbar + scrollbar
47
-
48
- const simpleOptions = generateOptions(4); // less than 5 options should not displays any scroll/search bar
49
-
50
42
  const SelectReset = (props) => {
51
43
  const [value, setValue] = useState('default');
52
44
 
@@ -64,220 +56,218 @@ const SelectReset = (props) => {
64
56
  };
65
57
 
66
58
  describe('SelectV2', () => {
67
- const toBeClose = (container) => {
68
- expect(container.getElementsByClassName('sc-select__option').length).toBe(
69
- 0,
70
- );
71
- };
72
-
73
- const toBeOpenWith = (container, optionsLength: number) => {
74
- expect(container.getElementsByClassName('sc-select__option').length).toBe(
75
- optionsLength,
76
- );
77
- };
78
-
79
- const toggleSelect = (container) => {
80
- userEvent.click(container.querySelector('.sc-select__control'));
59
+ const selectors = {
60
+ option: (name: string | RegExp) => screen.getByRole('option', { name }),
61
+ options: () => screen.queryAllByRole('option'),
62
+ select: (withSearch?: boolean, name?: string) => {
63
+ if (withSearch) {
64
+ return screen.getByRole('combobox', { name });
65
+ }
66
+ return screen.getByRole('listbox', { name });
67
+ },
68
+ input: () => screen.getByRole('textbox'),
69
+ noOptions: () => screen.getByText(/No options/i),
70
+ highlightedText: () => screen.getByRole('mark'),
81
71
  };
82
72
 
83
- test.each(variants)(
84
- 'should open select on click/Enter/ArrowDown',
85
- (variant) => {
86
- const { container } = render(
87
- <SelectWrapper variant={variant}>{simpleOptions}</SelectWrapper>,
88
- );
89
- // should open on click
90
- toBeClose(container);
91
- toggleSelect(container); // open
92
-
93
- toBeOpenWith(container, simpleOptions.length);
94
- toggleSelect(container); // close
95
-
96
- userEvent.tab(); // remove focus
73
+ it('should throw error if <Option/> is outside <Select/>', () => {
74
+ expect(() => render(<Option value="Option 1" />)).toThrowError();
75
+ });
97
76
 
98
- // should open with Enter/ArrowDown
99
- ['Enter', 'ArrowDown'].forEach((key) => {
100
- // should open on arrow down
101
- toBeClose(container);
102
- userEvent.tab(); // focus
77
+ it('should open/close on click', () => {
78
+ render(<SelectWrapper />);
79
+ const select = selectors.select();
80
+ expect(select).toBeInTheDocument();
81
+ let options = selectors.options();
82
+ expect(options).toHaveLength(0);
83
+
84
+ // should open on click
85
+ userEvent.click(select);
86
+ simpleOptions.forEach((opt) => {
87
+ const option = selectors.option(opt.props.label);
88
+ expect(option).toBeInTheDocument();
89
+ });
90
+
91
+ userEvent.click(select);
92
+ options = selectors.options();
93
+ expect(options).toHaveLength(0);
94
+ });
103
95
 
104
- userEvent.keyboard(`{${key}}`);
105
- toBeOpenWith(container, simpleOptions.length);
106
- toggleSelect(container); // close select
96
+ it('should open/close with keyboard', () => {
97
+ render(<SelectWrapper />);
98
+ const select = selectors.select();
99
+ expect(select).toBeInTheDocument();
100
+ const options = selectors.options();
101
+ expect(options).toHaveLength(0);
102
+
103
+ // should open on Enter
104
+ userEvent.tab();
105
+ userEvent.keyboard('{Enter}');
106
+ simpleOptions.forEach((opt) => {
107
+ const option = selectors.option(opt.props.label);
108
+ expect(option).toBeInTheDocument();
109
+ });
110
+
111
+ // should close on Enter
112
+ userEvent.keyboard('{Enter}');
113
+ expect(options).toHaveLength(0);
114
+
115
+ // should open on ArrowDown
116
+ userEvent.tab();
117
+ userEvent.keyboard('{ArrowDown}');
118
+ simpleOptions.forEach((opt) => {
119
+ const option = selectors.option(opt.props.label);
120
+ expect(option).toBeInTheDocument();
121
+ });
122
+ });
107
123
 
108
- toBeClose(container);
109
- userEvent.tab(); // remove focus
110
- });
111
- },
112
- );
113
- test.each(variants)('should display custom placeholder', (variant) => {
124
+ it('should display custom placeholder', () => {
114
125
  const placeholder = 'My placeholder...';
115
- const { container } = render(
116
- <SelectWrapper variant={variant} placeholder={placeholder}>
126
+ render(<SelectWrapper placeholder={placeholder} />);
127
+ expect(screen.getByText(placeholder)).toBeInTheDocument();
128
+ });
129
+
130
+ it('should be disabled', () => {
131
+ render(
132
+ <SelectWrapper value="1" disabled={true}>
117
133
  {simpleOptions}
118
134
  </SelectWrapper>,
119
135
  );
120
- expect(
121
- container.querySelector('.sc-select__placeholder'),
122
- ).toHaveTextContent(placeholder);
123
- });
124
- test.each(variants)('should display default value', (variant) => {
125
- const options = [
126
- {
127
- value: 0,
128
- label: 'Label 0',
129
- },
130
- ];
131
- const { container } = render(
132
- <Select variant={variant} defaultValue={options[0]} options={options} />,
133
- );
134
- expect(container.querySelector('.sc-select__placeholder')).toBeNull();
135
- expect(
136
- container.querySelector('.sc-select__single-value'),
137
- ).toHaveTextContent('Label 0');
136
+ userEvent.tab();
137
+ const select = selectors.select();
138
+ expect(select).not.toHaveFocus();
139
+ // use input instead of select because select will still trigger the open/close action
140
+ // despite select container not being clickable and input being disabled
141
+ const input = selectors.input();
142
+ userEvent.click(input);
143
+ const options = selectors.options();
144
+ expect(options).toHaveLength(0);
138
145
  });
139
- test.each(variants)('select should be disabled', (variant) => {
140
- const { container } = render(
141
- <Select variant={variant} disabled defaultValue="0">
142
- <Option value="0">{'Label 0'}</Option>
143
- </Select>,
146
+
147
+ it('should display no option', () => {
148
+ render(
149
+ <SelectWrapper>
150
+ <></>
151
+ </SelectWrapper>,
144
152
  );
145
- expect(container.querySelector('input')).toBeDisabled();
153
+ const select = selectors.select();
154
+ userEvent.click(select);
155
+ const noOptions = selectors.noOptions();
156
+ expect(noOptions).toBeInTheDocument();
146
157
  });
147
- test.each(variants)('should display no options', (variant) => {
148
- const { container } = render(<Select variant={variant} />);
149
- toggleSelect(container, variant);
150
- expect(
151
- container.querySelector('.sc-select__menu-notice--no-options'),
152
- ).toHaveTextContent('No options');
158
+
159
+ it('should filter and highlight on search', () => {
160
+ render(<SelectWrapper>{optionsWithScrollSearchBar} </SelectWrapper>);
161
+ const select = selectors.select(true);
162
+ userEvent.click(select);
163
+ const input = selectors.input();
164
+
165
+ userEvent.type(input, '2');
166
+ const options = selectors.options();
167
+ expect(options).toHaveLength(1);
168
+ const searchedText = selectors.highlightedText();
169
+ expect(searchedText).toHaveTextContent('2');
153
170
  });
154
- test.each(variants)(
155
- 'should display a search bar if more than 8 options',
156
- (variant) => {
157
- const { container } = render(
158
- <SelectWrapper variant={variant}>
159
- {optionsWithScrollSearchBar}
160
- </SelectWrapper>,
161
- );
162
- expect(container.querySelector('.sc-select__input')).not.toBeNull();
163
- },
164
- );
165
- test.each(variants)('should display option', (variant) => {
166
- const { container, getByTestId } = render(
167
- <Select variant={variant}>
168
- <Option data-testid="disabledOption" value="0" disabled>
169
- Label 1
170
- </Option>
171
- <Option
172
- data-testid="option2"
173
- value="1"
174
- icon={<Icon name="Deletion-marker" />}
175
- >
176
- Label 2
177
- </Option>
178
- </Select>,
179
- );
180
- toggleSelect(container);
181
- expect(getByTestId('disabledOption')).toHaveAttribute(
182
- 'aria-disabled',
183
- 'true',
184
- );
185
- const icon = getByTestId('option2').querySelector('i');
186
- expect(icon).not.toBeNull();
187
- expect(icon).toHaveAttribute('aria-label', 'Deletion-marker ');
171
+
172
+ it('should unfocus the search input when the select is closed', () => {
173
+ render(<SelectWrapper>{optionsWithScrollSearchBar} </SelectWrapper>);
174
+ const select = selectors.select(true);
175
+ userEvent.click(select);
176
+ let input = selectors.input();
177
+ expect(input).toHaveFocus();
178
+ const option = selectors.option(/Item 1/);
179
+ userEvent.click(option);
180
+ input = selectors.input();
181
+ expect(input).not.toHaveFocus();
188
182
  });
189
- test.each(variants)(
190
- '<Option/> component should throw if outside <Select/>',
191
- () => {
192
- // mock console.error to not display error message on throw
193
- jest.spyOn(console, 'error');
194
- console.error.mockImplementation(() => {});
195
- expect(() => render(<Option />)).toThrowError();
196
- console.error.mockRestore(); // restore console.error
197
- },
198
- );
199
- test.each(variants)('should highlight text on search', (variant) => {
200
- const { container, getByTestId } = render(
201
- <SelectWrapper variant={variant}>
202
- {optionsWithScrollSearchBar}
203
- </SelectWrapper>,
183
+
184
+ it('should be possible to use searchbar when option is selected', () => {
185
+ render(
186
+ <SelectWrapper value="1">{optionsWithScrollSearchBar}</SelectWrapper>,
204
187
  );
205
- toggleSelect(container);
206
- userEvent.type(container.querySelector('input'), 'Ite');
207
- const firstOption = getByTestId('option0');
208
- expect(firstOption).toHaveClass('sc-select__option--is-focused');
209
- expect(
210
- container.querySelector('.sc-highlighted-matching-text'),
211
- ).toHaveTextContent('Ite');
188
+ expect(screen.getByText(/Item 1/)).toBeVisible();
189
+ const select = selectors.select(true);
190
+ userEvent.click(select);
191
+ const input = selectors.input();
192
+ userEvent.type(input, '2');
193
+ expect(screen.queryByText(/Item 1/)).not.toBeInTheDocument();
194
+ const options = selectors.options();
195
+ expect(options).toHaveLength(1);
212
196
  });
213
- test.each(variants)('should select/unselect option', (variant) => {
214
- const { container, getByTestId } = render(
215
- <SelectWrapper variant={variant}>{simpleOptions}</SelectWrapper>,
216
- );
217
- // select option
218
- toggleSelect(container); // open select
219
197
 
220
- toBeOpenWith(container, simpleOptions.length);
221
- userEvent.click(getByTestId('option0'));
222
- toBeClose(container); // selecting an option should close select
223
-
224
- // unselect option
225
- toggleSelect(container); // reopen select
198
+ it('should select/unselect option with keyboard', () => {
199
+ render(<SelectWrapper />);
200
+ const select = selectors.select();
201
+ userEvent.tab();
202
+ userEvent.keyboard('{ArrowDown}');
226
203
 
227
- expect(getByTestId('option0')).toHaveClass(
228
- 'sc-select__option--is-selected',
229
- );
230
- // should be focused on the selected option
231
- expect(getByTestId('option0')).toHaveAttribute('aria-selected', 'true');
232
- userEvent.click(getByTestId('option1')); // click on another option
204
+ // should select first option
205
+ userEvent.keyboard('{Enter}');
206
+ expect(select).toHaveTextContent('Item 0');
233
207
 
234
- toBeClose(container); // selecting an option should close select
208
+ // should select second option
209
+ userEvent.tab();
210
+ userEvent.keyboard('{ArrowDown}');
211
+ userEvent.keyboard('{ArrowDown}');
235
212
 
236
- toggleSelect(container); // reopen select
213
+ userEvent.keyboard('{Enter}');
214
+ expect(select).toHaveTextContent('Item 1');
215
+ });
237
216
 
238
- expect(getByTestId('option1')).toHaveClass(
239
- 'sc-select__option--is-selected',
240
- );
241
- expect(getByTestId('option1')).toHaveAttribute('aria-selected', 'true');
242
- expect(getByTestId('option0')).not.toHaveClass(
243
- 'sc-select__option--is-selected',
217
+ it('should scroll to selected value when opening select', () => {
218
+ render(
219
+ <SelectWrapper value={optionsWithScrollSearchBar[9].props.value}>
220
+ {optionsWithScrollSearchBar}
221
+ </SelectWrapper>,
244
222
  );
245
- expect(getByTestId('option0')).not.toHaveAttribute('aria-selected', 'true');
223
+ const select = selectors.select(true);
224
+ userEvent.click(select);
225
+ const option = selectors.option(/Item 9/);
226
+ expect(screen.queryByRole('option', { name: /Item 1/i })).toBeNull();
227
+ expect(option).toBeVisible();
246
228
  });
247
- test.each(variants)('should focus on keyDown/keyUp', (variant) => {
248
- const { container, getByTestId } = render(
249
- <SelectWrapper variant={variant}>{simpleOptions}</SelectWrapper>,
250
- );
251
- toggleSelect(container);
252
- userEvent.keyboard('{ArrowDown}');
253
- expect(getByTestId('option0')).not.toHaveClass(
254
- 'sc-select__option--is-focused',
255
- );
256
- expect(getByTestId('option1')).toHaveClass('sc-select__option--is-focused');
257
- userEvent.keyboard('{ArrowUp}');
258
- expect(getByTestId('option0')).toHaveClass('sc-select__option--is-focused');
259
- expect(getByTestId('option1')).not.toHaveClass(
260
- 'sc-select__option--is-focused',
261
- );
229
+
230
+ it('should be able to reset the value', () => {
231
+ render(<SelectReset>{simpleOptions}</SelectReset>);
232
+ const button = screen.getByText(/reset/);
233
+ userEvent.click(button);
234
+ const select = selectors.select();
235
+ expect(select).toHaveTextContent('Select...');
262
236
  });
263
- test.each(variants)('should be able to reset the value', (variant) => {
264
- const { container } = render(
265
- <SelectReset variant={variant}>{simpleOptions}</SelectReset>,
237
+
238
+ it('should not be possible to select an option if it is disabled', () => {
239
+ render(
240
+ <SelectWrapper>
241
+ <Option value="1" disabled>
242
+ Item 1
243
+ </Option>
244
+ <Option value="2">Item 2</Option>
245
+ </SelectWrapper>,
266
246
  );
267
- userEvent.click(container.querySelector('button'));
268
- expect(
269
- container.querySelector('.sc-select__placeholder'),
270
- ).toHaveTextContent('Select...');
247
+ const select = selectors.select();
248
+ userEvent.click(select);
249
+ const option = selectors.option(/Item 1/);
250
+
251
+ userEvent.click(option);
252
+ const option2 = selectors.option(/Item 2/);
253
+ expect(option2).toBeVisible();
271
254
  });
272
255
 
273
- it('should not trigger onChange when defaultValue is empty string', () => {
274
- const onChange = jest.fn();
256
+ it('should display a tooltip if the option is disabled with a reason', () => {
275
257
  render(
276
- <Select value={''} onChange={onChange}>
277
- <Option value="test">test</Option>
278
- </Select>,
258
+ <SelectWrapper>
259
+ <Option value="1" disabled disabledReason="This option is disabled">
260
+ Item 1
261
+ </Option>
262
+ </SelectWrapper>,
279
263
  );
280
- expect(onChange).toBeCalledTimes(0);
264
+ const select = selectors.select();
265
+ userEvent.click(select);
266
+ const option = selectors.option(/Item 1/);
267
+ expect(option).toHaveAttribute('aria-disabled', 'true');
268
+ userEvent.hover(option);
269
+ const tooltip = screen.getByText(/This option is disabled/);
270
+ expect(tooltip).toBeInTheDocument();
281
271
  });
282
272
 
283
273
  it('should select with the right selector', async () => {
@@ -17,7 +17,7 @@ export type SearchProps = {
17
17
  value?: string;
18
18
  locale?: TableLocalType;
19
19
  totalCount?: number;
20
- } & Omit<Props, 'disableToggle' | 'onChange'>;
20
+ } & Omit<Props, 'onChange'>;
21
21
 
22
22
  const SearchContainer = styled.div`
23
23
  display: flex;
@@ -88,7 +88,6 @@ export function TableSearch(props: SearchProps) {
88
88
  <SearchInput
89
89
  value={value}
90
90
  placeholder={translations[locale].search}
91
- disableToggle
92
91
  size="1"
93
92
  onChange={(evt) => {
94
93
  if (typeof onChange === 'function') {
@@ -44,14 +44,14 @@ export const VirtualizedRows = <
44
44
  listRef,
45
45
  itemKey,
46
46
  }: VirtualizedRowsType<DATA_ROW>) => (
47
- <AutoSizer>
48
- {({ height, width }) => {
47
+ <AutoSizer disableWidth>
48
+ {({ height }) => {
49
49
  return (
50
50
  <List
51
- height={height}
51
+ height={height - 1}
52
52
  itemCount={rows.length} // how many items we are going to render
53
53
  itemSize={convertRemToPixels(tableRowHeight[rowHeight])} // height of each row in pixel
54
- width={width}
54
+ width={'100%'}
55
55
  itemKey={itemKey}
56
56
  itemData={rows}
57
57
  ref={listRef}
@@ -81,7 +81,7 @@ export const VirtualizedRows = <
81
81
  );
82
82
 
83
83
  export const useTableScrollbar = () => {
84
- const [hasScrollbar, setHasScrollbar] = useState(false);
84
+ const { hasScrollbar, setHasScrollbar } = useTableContext();
85
85
  const [scrollBarWidth, setScrollBarWidth] = useState(0);
86
86
 
87
87
  const handleScrollbarWidth = useCallback((node) => {
@@ -42,7 +42,7 @@ export const TableHeader = styled.div<{
42
42
  `;
43
43
 
44
44
  type HeadRowType = {
45
- hasScrollBar: boolean;
45
+ hasScrollBar?: boolean;
46
46
  scrollBarWidth: number;
47
47
  rowHeight: TableHeightKeyType;
48
48
  separationLineVariant: TableVariantType;
@@ -105,6 +105,10 @@ type TableContextType<
105
105
  en: { singular: string; plural: string };
106
106
  fr?: { singular: string; plural: string };
107
107
  };
108
+ syncScrollListener: ((event: Event) => void) | null;
109
+ setSyncScrollListener: (listener: (event: Event) => void) => void;
110
+ setHasScrollbar: React.Dispatch<React.SetStateAction<boolean>>;
111
+ hasScrollbar?: boolean;
108
112
  };
109
113
  const TableContext = React.createContext<TableContextType | null>(null);
110
114
 
@@ -215,6 +219,12 @@ function Table<
215
219
 
216
220
  const [rowHeight, setRowHeight] = React.useState<TableHeightKeyType>('h40');
217
221
 
222
+ const [syncScrollListener, setSyncScrollListener] = React.useState<
223
+ ((event: Event) => void) | null
224
+ >(null);
225
+
226
+ const [hasScrollbar, setHasScrollbar] = React.useState<boolean>(false);
227
+
218
228
  const {
219
229
  headerGroups,
220
230
  rows,
@@ -310,6 +320,10 @@ function Table<
310
320
  toggleAllRowsSelected,
311
321
  status,
312
322
  entityName,
323
+ syncScrollListener,
324
+ setSyncScrollListener,
325
+ setHasScrollbar,
326
+ hasScrollbar,
313
327
  };
314
328
  return (
315
329
  <TableContext.Provider