@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
@@ -1,17 +1,15 @@
1
- import { useEffect, useState, useCallback } from 'react';
1
+ import { useEffect, useState, useCallback, useRef } from 'react';
2
2
  import { Row } from 'react-table';
3
3
  import { FixedSizeList } from 'react-window';
4
+ import { useTableContext } from './Tablev2.component';
4
5
 
5
6
  export default function useSyncedScroll<
6
7
  DATA_ROW extends Record<string, unknown> = Record<string, unknown>,
7
8
  >(): {
8
9
  headerRef: (element: HTMLDivElement) => void;
9
- bodyRef: (tableBody: FixedSizeList<Row<DATA_ROW>[]>) => void;
10
+ bodyRef: React.RefObject<FixedSizeList<Row<DATA_ROW>[]>>;
10
11
  } {
11
- const [listener, setListener] =
12
- useState<((event: Event) => void) | null>(null);
13
- const [tableBody, setTableBody] =
14
- useState<FixedSizeList<Row<DATA_ROW>[]> | null>(null);
12
+ const { syncScrollListener, setSyncScrollListener } = useTableContext();
15
13
 
16
14
  const headerRef = useCallback(
17
15
  (element: HTMLDivElement) => {
@@ -24,41 +22,41 @@ export default function useSyncedScroll<
24
22
  });
25
23
  }
26
24
  };
27
- if (!listener) {
28
- setListener(() => {
25
+ if (!syncScrollListener) {
26
+ setSyncScrollListener(() => {
29
27
  return callback;
30
28
  });
31
29
  }
32
30
  }
33
31
  },
34
- [listener],
32
+ [syncScrollListener],
35
33
  );
36
34
 
37
- const bodyRef = useCallback((tableBody: FixedSizeList<Row<DATA_ROW>[]>) => {
38
- setTableBody(tableBody);
39
- }, []);
35
+ const bodyRef = useRef<FixedSizeList<Row<DATA_ROW>[]> | null>(null);
40
36
 
41
37
  useEffect(() => {
42
- if (tableBody && listener) {
38
+ if (bodyRef.current && syncScrollListener) {
43
39
  /*
44
40
  We intentionally use _outerRef prop here despite the fact that it is
45
41
  internal use only and not typed, as it is the only way for us to access to the scrollable element
46
42
  */
47
43
  //@ts-expect-error
48
- (tableBody._outerRef as HTMLDivElement).addEventListener(
44
+ (bodyRef.current._outerRef as HTMLDivElement).addEventListener(
49
45
  'scroll',
50
- listener,
46
+ syncScrollListener,
51
47
  );
52
-
53
- return () => {
54
- //@ts-expect-error
55
- if (tableBody && tableBody._outerRef) {
56
- //@ts-expect-error
57
- tableBody._outerRef.removeEventListener('scroll', listener);
58
- }
59
- };
60
48
  }
61
- }, [tableBody, listener]);
49
+ return () => {
50
+ //@ts-expect-error
51
+ if (bodyRef.current && bodyRef.current._outerRef) {
52
+ //@ts-expect-error
53
+ bodyRef.current._outerRef.removeEventListener(
54
+ 'scroll',
55
+ syncScrollListener,
56
+ );
57
+ }
58
+ };
59
+ }, [bodyRef.current, syncScrollListener]);
62
60
 
63
61
  return { headerRef, bodyRef };
64
62
  }
@@ -58,7 +58,7 @@ export const TabItem = styled.div<{
58
58
  `;
59
59
  export const TabsContainer = styled.div<{
60
60
  tabLineColor?: string;
61
- separatorColor: string;
61
+ separatorColor?: string;
62
62
  }>`
63
63
  height: 100%;
64
64
  width: 100%;
@@ -185,8 +185,8 @@ function Tabs({
185
185
  });
186
186
  return (
187
187
  <TabsContext.Provider value={true}>
188
- {/*@ts-expect-error containerType is not yet a valid prop for react */}
189
188
  <TabsContainer
189
+ // @ts-expect-error containerType is not yet a valid prop for react
190
190
  style={{ containerType: 'size' }}
191
191
  className={['sc-tabs', className].join(' ')}
192
192
  tabLineColor={tabLineColor}
@@ -1,12 +1,11 @@
1
1
  import { ChangeEvent, InputHTMLAttributes, useRef } from 'react';
2
2
  import styled, { css } from 'styled-components';
3
3
 
4
- import { spacing } from '../../style/theme';
5
4
  import { LABEL_PREFIX, useFieldContext } from '../form/Form.component';
6
- import { Stack } from '../../spacing';
5
+ import { Stack, spacing } from '../../spacing';
7
6
  import { Text } from '../text/Text.component';
8
7
 
9
- type Props = InputHTMLAttributes<HTMLInputElement> & {
8
+ export type Props = InputHTMLAttributes<HTMLInputElement> & {
10
9
  toggle: boolean;
11
10
  onChange: (e: ChangeEvent<HTMLInputElement>) => void;
12
11
  label?: string;
@@ -20,8 +19,7 @@ const ToggleContainer = styled.span<{ disabled?: boolean }>`
20
19
  `;
21
20
  const Switch = styled.label<{ disabled?: boolean }>`
22
21
  position: relative;
23
- width: ${spacing.sp24};
24
- height: ${spacing.sp14};
22
+ width: ${spacing.r24};
25
23
  align-self: center;
26
24
  ${(props) => {
27
25
  return css`
@@ -39,23 +37,22 @@ const Slider = styled.div<{ toggle?: boolean }>`
39
37
  width: 100%;
40
38
  height: 1rem;
41
39
  background-color: ${(props) => props.theme.backgroundLevel1};
42
- border: ${spacing.sp1} solid
40
+ border: ${spacing.r1} solid
43
41
  ${(props) => props.theme[props.toggle ? 'selectedActive' : 'infoPrimary']};
44
- border-radius: ${spacing.sp8};
42
+ border-radius: ${spacing.r8};
45
43
  transition: 0.4s;
46
- -moz-transform: rotate(0.02deg);
44
+
47
45
  &:before {
48
46
  border-radius: 100%;
49
47
  position: absolute;
50
48
  content: '';
51
- height: ${spacing.sp10};
52
- width: ${spacing.sp10};
49
+ height: ${spacing.r10};
50
+ width: ${spacing.r10};
53
51
  left: 3px;
54
52
  top: 3.5px;
55
53
  background-color: ${(props) =>
56
54
  props.theme[props.toggle ? 'textSecondary' : 'textPrimary']};
57
55
  transition: 0.4s;
58
- -moz-transform: rotate(0.02deg);
59
56
  }
60
57
  `;
61
58
  const ToggleInput = styled.input`
@@ -63,7 +60,7 @@ const ToggleInput = styled.input`
63
60
  background-color: ${(props) => props.theme.selectedActive};
64
61
  }
65
62
  &:checked + ${Slider}:before {
66
- transform: translateX(${spacing.sp10});
63
+ transform: translateX(${spacing.r10});
67
64
  }
68
65
  display: none;
69
66
  `;
@@ -0,0 +1,56 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React, { useState } from 'react';
3
+ import { Props, Toggle } from './Toggle.component';
4
+ import userEvent from '@testing-library/user-event';
5
+
6
+ describe('Toggle', () => {
7
+ const selectors = {
8
+ toggle: () => screen.getByRole('checkbox'),
9
+ label: (text: string | RegExp) => screen.getByText(text),
10
+ };
11
+ const RenderToggle = (props: Omit<Props, 'onChange' | 'toggle'>) => {
12
+ const [toggle, setToggle] = useState<boolean>(false);
13
+ const handleClick = () => {
14
+ setToggle(!toggle);
15
+ };
16
+ return <Toggle {...props} toggle={toggle} onChange={handleClick} />;
17
+ };
18
+
19
+ it('should render the Toggle component with label', () => {
20
+ render(<RenderToggle label="Test" />);
21
+ const toggle = selectors.toggle();
22
+ expect(toggle).toBeInTheDocument();
23
+ const label = selectors.label(/Test/);
24
+ expect(label).toBeInTheDocument();
25
+ });
26
+
27
+ it('should toggle the switch on click on checkbox or label', () => {
28
+ render(<RenderToggle label="Test"></RenderToggle>);
29
+ const toggle = selectors.toggle();
30
+ userEvent.click(toggle);
31
+ expect(toggle).toBeChecked();
32
+ const label = selectors.label('Test');
33
+ userEvent.click(label);
34
+ expect(toggle).not.toBeChecked();
35
+ });
36
+
37
+ it('should toggle the switch when pressing the space key or enter key', () => {
38
+ render(<RenderToggle />);
39
+ const toggle = selectors.toggle();
40
+ userEvent.tab();
41
+ userEvent.keyboard('{space}');
42
+ expect(toggle).toBeChecked();
43
+ userEvent.keyboard('{enter}');
44
+ expect(toggle).not.toBeChecked();
45
+ });
46
+
47
+ it('should not toggle the switch when disabled', () => {
48
+ render(<RenderToggle disabled={true} />);
49
+ const toggle = selectors.toggle();
50
+ // toBeDisabled is not working for some reason
51
+ userEvent.tab();
52
+ expect(toggle).not.toHaveFocus();
53
+ userEvent.click(toggle);
54
+ expect(toggle).not.toBeChecked();
55
+ });
56
+ });
@@ -594,7 +594,6 @@ export const AttachmentTable = <ENTITY_TYPE,>({
594
594
  onBlur={() => {
595
595
  setSearchInputIsFocused(false);
596
596
  }}
597
- disableToggle
598
597
  disabled={filteredEntities.status === 'error'}
599
598
  />
600
599
  <Loader />
@@ -616,7 +615,6 @@ export const AttachmentTable = <ENTITY_TYPE,>({
616
615
  onBlur={() => {
617
616
  setSearchInputIsFocused(false);
618
617
  }}
619
- disableToggle
620
618
  searchInputIsFocused={searchInputIsFocused}
621
619
  />
622
620
  )}
@@ -0,0 +1,20 @@
1
+ import {
2
+ Meta,
3
+ Story,
4
+ Canvas,
5
+ Primary,
6
+ Controls,
7
+ Unstyled,
8
+ Source,
9
+ } from '@storybook/blocks';
10
+ import { SearchInput } from '../../src/lib/components/searchinput/SearchInput.component';
11
+
12
+ import * as Stories from './searchinput.stories';
13
+
14
+ <Meta name="Guideline" of={Stories} />
15
+
16
+ # Search Input
17
+
18
+ <Story of={Stories.Debounce} />
19
+ <Controls of={Stories.Debounce} />
20
+ <Source of={Stories.Debounce} />
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { action } from '@storybook/addon-actions';
3
- import { SearchInput } from '../src/lib/components/searchinput/SearchInput.component';
4
- import { Wrapper, Title } from './common';
3
+ import { SearchInput } from '../../src/lib/components/searchinput/SearchInput.component';
4
+ import { Wrapper, Title } from '../common';
5
5
  export default {
6
6
  title: 'Components/Inputs/SearchInput',
7
7
  component: SearchInput,
@@ -21,7 +21,7 @@ export const Default = {
21
21
  placeholder="Search server..."
22
22
  onChange={action('on input change')}
23
23
  onReset={action('on input reset')}
24
- disableToggle={false}
24
+ autoComplete="off"
25
25
  />
26
26
  </div>
27
27
  <Title>Disabled</Title>
@@ -36,7 +36,6 @@ export const Default = {
36
36
  placeholder="Search server..."
37
37
  onChange={action('on input change')}
38
38
  onReset={action('on input reset')}
39
- disableToggle={true}
40
39
  />
41
40
  </div>
42
41
  <Title>Search Input filled</Title>
@@ -49,7 +48,6 @@ export const Default = {
49
48
  value="carlito"
50
49
  onChange={action('on input change')}
51
50
  onReset={action('on input reset')}
52
- disableToggle={false}
53
51
  data-cy="carlito_searchinput"
54
52
  />
55
53
  </div>
@@ -64,7 +62,6 @@ export const Default = {
64
62
  placeholder="Search and Filter…"
65
63
  onChange={action('on input change')}
66
64
  onReset={action('on input reset')}
67
- disableToggle={true}
68
65
  />
69
66
  </div>
70
67
  <Title>Disable the default toggle undefined onReset action</Title>
@@ -77,7 +74,6 @@ export const Default = {
77
74
  value=""
78
75
  placeholder="Search and Filter…"
79
76
  onChange={action('on input change')}
80
- disableToggle={true}
81
77
  />
82
78
  </div>
83
79
  </Wrapper>
@@ -88,19 +84,16 @@ export const Debounce = {
88
84
  render: (args) => {
89
85
  const [value, setValue] = useState('');
90
86
  return (
91
- <Wrapper>
92
- <SearchInput
93
- placeholder="Search"
94
- value={value}
95
- disableToggle
96
- onReset={action('on input reset')}
97
- onChange={(e) => {
98
- setValue(e.target.value);
99
- action('debounce')(`${e.target} changed`);
100
- }}
101
- {...args}
102
- />
103
- </Wrapper>
87
+ <SearchInput
88
+ placeholder="Search"
89
+ value={value}
90
+ onReset={action('on input reset')}
91
+ onChange={(e) => {
92
+ setValue(e.target.value);
93
+ action('debounce')(`${e.target} changed`);
94
+ }}
95
+ {...args}
96
+ />
104
97
  );
105
98
  },
106
99
  };
@@ -5,14 +5,15 @@ import { Modal } from '../../src/lib/components/modal/Modal.component';
5
5
  import { Select } from '../../src/lib/components/selectv2/Selectv2.component';
6
6
  import { Wrapper } from '../common';
7
7
  import { Meta, StoryObj } from '@storybook/react';
8
+ import { useArgs } from '@storybook/preview-api';
8
9
 
9
10
  type SelectStory = StoryObj<typeof Select>;
10
11
  const meta: Meta<typeof Select> = {
11
12
  title: 'Components/Inputs/Select',
12
13
  component: Select,
13
- decorators: [
14
- (story) => <Wrapper style={{ minHeight: '15rem' }}>{story()}</Wrapper>,
15
- ],
14
+ // decorators: [
15
+ // (story) => <Wrapper style={{ minHeight: '15rem' }}>{story()}</Wrapper>,
16
+ // ],
16
17
  };
17
18
 
18
19
  export default meta;
@@ -37,7 +38,7 @@ const generateOptions = (n = 10) =>
37
38
 
38
39
  const optionsWithSearchBar = generateOptions(25);
39
40
  const optionsWithoutSearchBar = generateOptions(7);
40
- const defaultOptions = generateOptions(4);
41
+ const defaultOptions = generateOptions(5);
41
42
  const thousandsOfOptions = generateOptions(1000);
42
43
  const optionsWithDisabledWithoutMessage = optionsWithSearchBar.map(
43
44
  (option, index) => {
@@ -78,7 +79,6 @@ export const WithoutOptions: SelectStory = {
78
79
  export const DisabledSelect: SelectStory = {
79
80
  args: {
80
81
  disabled: true,
81
- defaultValue: defaultOptions[0].props.value,
82
82
  children: defaultOptions,
83
83
  },
84
84
  };
@@ -167,3 +167,21 @@ export const NotEnoughPlaceAtTheBottom: SelectStory = {
167
167
  children: optionsWithSearchBar,
168
168
  },
169
169
  };
170
+
171
+ export const WithDefaultValue: SelectStory = {
172
+ render: (args) => {
173
+ const [{ value }, updateArgs] = useArgs();
174
+ return (
175
+ <Select
176
+ {...args}
177
+ onChange={(value) => updateArgs({ value })}
178
+ value={value}
179
+ ></Select>
180
+ );
181
+ },
182
+ args: {
183
+ value: defaultOptions[0].props.value,
184
+ placeholder: 'Select an option',
185
+ children: defaultOptions,
186
+ },
187
+ };
@@ -0,0 +1,20 @@
1
+ import {
2
+ Meta,
3
+ Story,
4
+ Canvas,
5
+ Primary,
6
+ Controls,
7
+ Unstyled,
8
+ Source,
9
+ } from '@storybook/blocks';
10
+
11
+ import * as Stories from './toggle.stories';
12
+
13
+ <Meta name="Guideline" of={Stories} />
14
+
15
+ <Primary>
16
+ <Stories.Playground />
17
+ </Primary>
18
+ <Controls />
19
+
20
+ <Source />
@@ -1,22 +1,29 @@
1
1
  import React, { useState } from 'react';
2
- import { Toggle } from '../src/lib/components/toggle/Toggle.component';
3
- import { Wrapper } from './common';
2
+ import {
3
+ Props,
4
+ Toggle,
5
+ } from '../../src/lib/components/toggle/Toggle.component';
4
6
  import { useArgs } from '@storybook/preview-api';
5
- export default {
7
+ import { Meta, StoryObj } from '@storybook/react';
8
+
9
+ type Story = StoryObj<Props>;
10
+ const meta: Meta = {
6
11
  title: 'Components/Inputs/Toggle',
7
12
  component: Toggle,
8
13
  args: {
9
14
  name: 'toggle',
10
15
  },
11
16
  };
12
- export const Playground = {
17
+ export default meta;
18
+
19
+ export const Playground: Story = {
13
20
  render: (args) => {
14
- const [{ toggle }, updateArgs] = useArgs();
21
+ const [{ toggle }, updateArgs] = useArgs<{ toggle: boolean }>();
15
22
  return (
16
23
  <Toggle
17
- toggle={toggle}
18
- onChange={() => updateArgs({ toggle: !toggle })}
19
24
  {...args}
25
+ onChange={() => updateArgs({ toggle: !toggle })}
26
+ toggle={toggle}
20
27
  />
21
28
  );
22
29
  },
@@ -24,18 +31,18 @@ export const Playground = {
24
31
  label: 'Playground',
25
32
  },
26
33
  };
27
- export const LabelledToggle = {
34
+ export const LabelledToggle: Story = {
28
35
  render: (args) => {
29
36
  const [toggle, setToggle] = useState(false);
30
37
  return (
31
- <Toggle toggle={toggle} onChange={() => setToggle(!toggle)} {...args} />
38
+ <Toggle {...args} toggle={toggle} onChange={() => setToggle(!toggle)} />
32
39
  );
33
40
  },
34
41
  args: {
35
42
  label: 'Airplane mode',
36
43
  },
37
44
  };
38
- export const DisabledToggle = {
45
+ export const DisabledToggle: Story = {
39
46
  ...Playground,
40
47
  args: {
41
48
  label: 'Disabled Toggle',