@scality/core-ui 0.135.0 → 0.137.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 (55) 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/AttachmentConfirmationModal.d.ts +4 -3
  27. package/dist/organisms/attachments/AttachmentConfirmationModal.d.ts.map +1 -1
  28. package/dist/organisms/attachments/AttachmentConfirmationModal.js +1 -0
  29. package/dist/organisms/attachments/AttachmentTable.d.ts +10 -10
  30. package/dist/organisms/attachments/AttachmentTable.d.ts.map +1 -1
  31. package/dist/organisms/attachments/AttachmentTable.js +2 -2
  32. package/dist/organisms/attachments/AttachmentTypes.d.ts +4 -3
  33. package/dist/organisms/attachments/AttachmentTypes.d.ts.map +1 -1
  34. package/package.json +2 -2
  35. package/src/lib/components/searchinput/SearchInput.component.tsx +0 -2
  36. package/src/lib/components/searchinput/SearchInput.test.tsx +88 -0
  37. package/src/lib/components/selectv2/Selectv2.component.tsx +7 -11
  38. package/src/lib/components/selectv2/selectv2.test.tsx +190 -200
  39. package/src/lib/components/tablev2/Search.tsx +1 -2
  40. package/src/lib/components/tablev2/TableCommon.tsx +5 -5
  41. package/src/lib/components/tablev2/Tablestyle.tsx +1 -1
  42. package/src/lib/components/tablev2/Tablev2.component.tsx +14 -0
  43. package/src/lib/components/tablev2/useSyncedScroll.ts +22 -24
  44. package/src/lib/components/tabsv2/StyledTabs.ts +1 -1
  45. package/src/lib/components/tabsv2/Tabsv2.component.tsx +1 -1
  46. package/src/lib/components/toggle/Toggle.component.tsx +9 -12
  47. package/src/lib/components/toggle/Toggle.test.tsx +56 -0
  48. package/src/lib/organisms/attachments/AttachmentConfirmationModal.tsx +11 -5
  49. package/src/lib/organisms/attachments/AttachmentTable.tsx +53 -31
  50. package/src/lib/organisms/attachments/AttachmentTypes.ts +10 -3
  51. package/stories/SearchInput/searchinput.guideline.mdx +20 -0
  52. package/stories/{searchinput.stories.tsx → SearchInput/searchinput.stories.tsx} +13 -20
  53. package/stories/Select/selectv2.stories.tsx +23 -5
  54. package/stories/Toggle/toggle.guideline.mdx +20 -0
  55. package/stories/{toggle.stories.tsx → Toggle/toggle.stories.tsx} +17 -10
@@ -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
@@ -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
+ });
@@ -10,7 +10,11 @@ import { Icon, LargerText, Modal, SecondaryText, Stack, Wrap } from '../..';
10
10
  type AttachmentStatus = 'Waiting for confirmation' | 'Error' | 'Success';
11
11
 
12
12
  //The entity is the "thing" you want to attach to the resource, sorry about the naming :(
13
- export function AttachmentConfirmationModal<ENTITY_TYPE, RESOURCE_TYPE>({
13
+ export function AttachmentConfirmationModal<
14
+ ENTITY_TYPE,
15
+ RESOURCE_TYPE,
16
+ ENTITY extends Record<string, unknown> = Record<string, unknown>,
17
+ >({
14
18
  attachmentOperations,
15
19
  getAttachmentMutationOptions,
16
20
  resourceType,
@@ -21,7 +25,7 @@ export function AttachmentConfirmationModal<ENTITY_TYPE, RESOURCE_TYPE>({
21
25
  onCancel,
22
26
  onExit,
23
27
  }: {
24
- attachmentOperations: AttachmentOperation<ENTITY_TYPE>[];
28
+ attachmentOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[];
25
29
  getAttachmentMutationOptions: () => UseMutationOptions<
26
30
  unknown,
27
31
  unknown,
@@ -30,6 +34,7 @@ export function AttachmentConfirmationModal<ENTITY_TYPE, RESOURCE_TYPE>({
30
34
  type: ENTITY_TYPE;
31
35
  entityName: string;
32
36
  id: string;
37
+ completeEntity?: ENTITY;
33
38
  }
34
39
  >;
35
40
  resourceName: string;
@@ -39,8 +44,8 @@ export function AttachmentConfirmationModal<ENTITY_TYPE, RESOURCE_TYPE>({
39
44
  cancelButtonDisabled?: boolean;
40
45
  onCancel?: () => void;
41
46
  onExit?: (
42
- successfullOperations: AttachmentOperation<ENTITY_TYPE>[],
43
- failedOperations: AttachmentOperation<ENTITY_TYPE>[],
47
+ successfullOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
48
+ failedOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
44
49
  ) => void;
45
50
  }) {
46
51
  const history = useHistory();
@@ -70,12 +75,13 @@ export function AttachmentConfirmationModal<ENTITY_TYPE, RESOURCE_TYPE>({
70
75
  entityName: string;
71
76
  id: string;
72
77
  }[] = attachmentOperations.map(
73
- (attachmentOperation: AttachmentOperation<ENTITY_TYPE>) => {
78
+ (attachmentOperation: AttachmentOperation<ENTITY_TYPE, ENTITY>) => {
74
79
  return {
75
80
  action: attachmentOperation.action,
76
81
  type: attachmentOperation.entity.type,
77
82
  entityName: attachmentOperation.entity.name,
78
83
  id: attachmentOperation.entity.id,
84
+ completeEntity: attachmentOperation.entity.completeEntity,
79
85
  };
80
86
  },
81
87
  );
@@ -38,27 +38,36 @@ type AttachableEntityWithPendingStatus<ENTITY_TYPE> = {
38
38
  isPending?: boolean;
39
39
  } & AttachableEntity<ENTITY_TYPE>;
40
40
 
41
- export type AttachmentTableProps<ENTITY_TYPE> = {
42
- initiallyAttachedEntities: AttachableEntity<ENTITY_TYPE>[];
41
+ export type AttachmentTableProps<
42
+ ENTITY_TYPE,
43
+ ENTITY extends Record<string, unknown> = Record<string, unknown>,
44
+ > = {
45
+ initiallyAttachedEntities: AttachableEntity<ENTITY_TYPE, ENTITY>[];
43
46
  initiallyAttachedEntitiesStatus: 'idle' | 'loading' | 'success' | 'error';
44
- initialAttachmentOperations: AttachmentOperation<ENTITY_TYPE>[];
47
+ initialAttachmentOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[];
45
48
  entityName: { plural: string; singular: string };
46
49
  getNameQuery?: (
47
- entity: AttachableEntity<ENTITY_TYPE>,
50
+ entity: AttachableEntity<ENTITY_TYPE, ENTITY>,
48
51
  ) => UseQueryOptions<unknown, unknown, string>;
49
52
  searchEntityPlaceholder: string;
50
53
  onAttachmentsOperationsChanged: (
51
- attachmentOperations: AttachmentOperation<ENTITY_TYPE>[],
54
+ attachmentOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
52
55
  ) => void;
53
56
  filteredEntities:
54
57
  | { status: 'idle' }
55
58
  | {
56
59
  status: 'loading' | 'error';
57
- data?: { number: number; entities: AttachableEntity<ENTITY_TYPE>[] };
60
+ data?: {
61
+ number: number;
62
+ entities: AttachableEntity<ENTITY_TYPE, ENTITY>[];
63
+ };
58
64
  }
59
65
  | {
60
66
  status: 'success';
61
- data: { number: number; entities: AttachableEntity<ENTITY_TYPE>[] };
67
+ data: {
68
+ number: number;
69
+ entities: AttachableEntity<ENTITY_TYPE, ENTITY>[];
70
+ };
62
71
  };
63
72
  onEntitySearchChange: (search?: string) => void;
64
73
  };
@@ -131,31 +140,34 @@ const PrivateAttachmentContext = createContext<{
131
140
  setResetAttachementTable: Dispatch<
132
141
  SetStateAction<
133
142
  (
134
- initiallyAttachedEntities: AttachableEntity<any>[], //Deliberately using any here because we can't use generics
135
- initialAttachmentOperations: AttachmentOperation<any>[],
143
+ initiallyAttachedEntities: AttachableEntity<any, any>[], //Deliberately using any here because we can't use generics
144
+ initialAttachmentOperations: AttachmentOperation<any, any>[],
136
145
  ) => void
137
146
  >
138
147
  >;
139
148
  } | null>(null);
140
149
  const AttachmentContext = createContext<{
141
150
  resetAttachmentTable: (
142
- initiallyAttachedEntities: AttachableEntity<any>[], //Deliberately using any here because we can't use generics
143
- initialAttachmentOperations: AttachmentOperation<any>[],
151
+ initiallyAttachedEntities: AttachableEntity<any, any>[], //Deliberately using any here because we can't use generics
152
+ initialAttachmentOperations: AttachmentOperation<any, any>[],
144
153
  ) => void;
145
154
  } | null>(null);
146
155
 
147
- export const AttachmentProvider = <ENTITY_TYPE extends unknown>({
156
+ export const AttachmentProvider = <
157
+ ENTITY_TYPE extends unknown,
158
+ ENTITY extends Record<string, unknown> = Record<string, unknown>,
159
+ >({
148
160
  children,
149
161
  }: PropsWithChildren<{}>) => {
150
162
  const [resetAttachmentTable, setResetAttachementTable] = useState<
151
163
  (
152
- initiallyAttachedEntities: AttachableEntity<ENTITY_TYPE>[],
153
- initialAttachmentOperations: AttachmentOperation<ENTITY_TYPE>[],
164
+ initiallyAttachedEntities: AttachableEntity<ENTITY_TYPE, ENTITY>[],
165
+ initialAttachmentOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
154
166
  ) => void
155
167
  >(
156
168
  (
157
- _: AttachableEntity<ENTITY_TYPE>[],
158
- __: AttachmentOperation<ENTITY_TYPE>[],
169
+ _: AttachableEntity<ENTITY_TYPE, ENTITY>[],
170
+ __: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
159
171
  ) => {},
160
172
  );
161
173
  return (
@@ -177,7 +189,10 @@ export const useAttachmentOperations = () => {
177
189
  return ctx;
178
190
  };
179
191
 
180
- export const AttachmentTable = <ENTITY_TYPE,>({
192
+ export const AttachmentTable = <
193
+ ENTITY_TYPE,
194
+ ENTITY extends Record<string, unknown> = Record<string, unknown>,
195
+ >({
181
196
  initiallyAttachedEntities,
182
197
  initiallyAttachedEntitiesStatus,
183
198
  initialAttachmentOperations,
@@ -187,7 +202,7 @@ export const AttachmentTable = <ENTITY_TYPE,>({
187
202
  getNameQuery,
188
203
  filteredEntities,
189
204
  onEntitySearchChange,
190
- }: AttachmentTableProps<ENTITY_TYPE>) => {
205
+ }: AttachmentTableProps<ENTITY_TYPE, ENTITY>) => {
191
206
  const privateAttachmentContext = useContext(PrivateAttachmentContext);
192
207
  const exposedAttachmentContext = useContext(AttachmentContext);
193
208
 
@@ -198,8 +213,11 @@ export const AttachmentTable = <ENTITY_TYPE,>({
198
213
  //Desired attached entities and onAttachmentsOperationsChanged handling
199
214
  const convertInitiallyAttachedEntitiesToDesiredAttachedEntities = useCallback(
200
215
  (
201
- initiallyAttachedEntities: AttachableEntity<ENTITY_TYPE>[],
202
- operations: AttachmentOperation<ENTITY_TYPE>[] = initialAttachmentOperations,
216
+ initiallyAttachedEntities: AttachableEntity<ENTITY_TYPE, ENTITY>[],
217
+ operations: AttachmentOperation<
218
+ ENTITY_TYPE,
219
+ ENTITY
220
+ >[] = initialAttachmentOperations,
203
221
  ) => {
204
222
  return initiallyAttachedEntities
205
223
  .filter(
@@ -216,7 +234,9 @@ export const AttachmentTable = <ENTITY_TYPE,>({
216
234
  );
217
235
  const convertInitiallyAttachementOperationsToDesiredAttachedEntities =
218
236
  useCallback(
219
- (initialAttachmentOperations: AttachmentOperation<ENTITY_TYPE>[]) => {
237
+ (
238
+ initialAttachmentOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
239
+ ) => {
220
240
  return initialAttachmentOperations
221
241
  .filter((op) => op.action !== AttachmentAction.REMOVE)
222
242
  .map((op) => ({
@@ -232,21 +252,21 @@ export const AttachmentTable = <ENTITY_TYPE,>({
232
252
  (
233
253
  state: {
234
254
  desiredAttachedEntities: AttachableEntityWithPendingStatus<ENTITY_TYPE>[];
235
- attachmentsOperations: AttachmentOperation<ENTITY_TYPE>[];
255
+ attachmentsOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[];
236
256
  },
237
257
  action:
238
258
  | {
239
259
  action: AttachmentAction.ADD;
240
- entity: AttachableEntity<ENTITY_TYPE>;
260
+ entity: AttachableEntity<ENTITY_TYPE, ENTITY>;
241
261
  }
242
262
  | {
243
263
  action: AttachmentAction.REMOVE;
244
- entity: AttachableEntity<ENTITY_TYPE>;
264
+ entity: AttachableEntity<ENTITY_TYPE, ENTITY>;
245
265
  }
246
266
  | {
247
267
  action: 'RESET_DESIRED_ATTACHED_ENTITIES';
248
268
  entities: AttachableEntityWithPendingStatus<ENTITY_TYPE>[];
249
- operations: AttachmentOperation<ENTITY_TYPE>[];
269
+ operations: AttachmentOperation<ENTITY_TYPE, ENTITY>[];
250
270
  },
251
271
  ) => {
252
272
  switch (action.action) {
@@ -401,8 +421,8 @@ export const AttachmentTable = <ENTITY_TYPE,>({
401
421
  useEffect(() => {
402
422
  privateAttachmentContext.setResetAttachementTable(() => {
403
423
  return (
404
- newlyAttachedEntities: AttachableEntity<ENTITY_TYPE>[],
405
- newAttachmentOperations: AttachmentOperation<ENTITY_TYPE>[],
424
+ newlyAttachedEntities: AttachableEntity<ENTITY_TYPE, ENTITY>[],
425
+ newAttachmentOperations: AttachmentOperation<ENTITY_TYPE, ENTITY>[],
406
426
  ) => {
407
427
  dispatch({
408
428
  action: 'RESET_DESIRED_ATTACHED_ENTITIES',
@@ -429,7 +449,11 @@ export const AttachmentTable = <ENTITY_TYPE,>({
429
449
  const searchInputRef = useRef<HTMLInputElement | null>(null);
430
450
 
431
451
  const onSelectedItemChange = useCallback(
432
- (onChangeParams: UseComboboxStateChange<AttachableEntity<ENTITY_TYPE>>) => {
452
+ (
453
+ onChangeParams: UseComboboxStateChange<
454
+ AttachableEntity<ENTITY_TYPE, ENTITY>
455
+ >,
456
+ ) => {
433
457
  if (onChangeParams.selectedItem) {
434
458
  dispatch({
435
459
  action: AttachmentAction.ADD,
@@ -478,7 +502,7 @@ export const AttachmentTable = <ENTITY_TYPE,>({
478
502
  row: { original: entity },
479
503
  }: {
480
504
  value: string;
481
- row: { original: AttachableEntity<ENTITY_TYPE> };
505
+ row: { original: AttachableEntity<ENTITY_TYPE, ENTITY> };
482
506
  }) => {
483
507
  const { data: asyncName, status } = useQuery({
484
508
  ...(getNameQuery
@@ -594,7 +618,6 @@ export const AttachmentTable = <ENTITY_TYPE,>({
594
618
  onBlur={() => {
595
619
  setSearchInputIsFocused(false);
596
620
  }}
597
- disableToggle
598
621
  disabled={filteredEntities.status === 'error'}
599
622
  />
600
623
  <Loader />
@@ -616,7 +639,6 @@ export const AttachmentTable = <ENTITY_TYPE,>({
616
639
  onBlur={() => {
617
640
  setSearchInputIsFocused(false);
618
641
  }}
619
- disableToggle
620
642
  searchInputIsFocused={searchInputIsFocused}
621
643
  />
622
644
  )}
@@ -1,8 +1,12 @@
1
- export type AttachableEntity<ENTITY_TYPE> = {
1
+ export type AttachableEntity<
2
+ ENTITY_TYPE,
3
+ ENTITY extends Record<string, unknown> = Record<string, unknown>,
4
+ > = {
2
5
  name: string;
3
6
  id: string;
4
7
  type: ENTITY_TYPE;
5
8
  disableDetach?: boolean;
9
+ completeEntity?: ENTITY;
6
10
  };
7
11
 
8
12
  export enum AttachmentAction {
@@ -10,7 +14,10 @@ export enum AttachmentAction {
10
14
  REMOVE,
11
15
  }
12
16
 
13
- export type AttachmentOperation<ENTITY_TYPE> = {
17
+ export type AttachmentOperation<
18
+ ENTITY_TYPE,
19
+ ENTITY extends Record<string, unknown> = Record<string, unknown>,
20
+ > = {
14
21
  action: AttachmentAction;
15
- entity: AttachableEntity<ENTITY_TYPE>;
22
+ entity: AttachableEntity<ENTITY_TYPE, ENTITY>;
16
23
  };
@@ -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} />