@qoretechnologies/reqore 0.25.9 → 0.25.10

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 (48) hide show
  1. package/__tests__/dropdown.test.tsx +133 -12
  2. package/dist/components/Collection/item.d.ts +2 -2
  3. package/dist/components/Collection/item.d.ts.map +1 -1
  4. package/dist/components/Collection/item.js +6 -3
  5. package/dist/components/Collection/item.js.map +1 -1
  6. package/dist/components/Dropdown/index.d.ts +8 -7
  7. package/dist/components/Dropdown/index.d.ts.map +1 -1
  8. package/dist/components/Dropdown/index.js +12 -5
  9. package/dist/components/Dropdown/index.js.map +1 -1
  10. package/dist/components/Dropdown/item.d.ts +2 -2
  11. package/dist/components/Dropdown/item.d.ts.map +1 -1
  12. package/dist/components/Dropdown/item.js.map +1 -1
  13. package/dist/components/Dropdown/list.d.ts +9 -2
  14. package/dist/components/Dropdown/list.d.ts.map +1 -1
  15. package/dist/components/Dropdown/list.js +13 -5
  16. package/dist/components/Dropdown/list.js.map +1 -1
  17. package/dist/components/InternalPopover/index.d.ts.map +1 -1
  18. package/dist/components/InternalPopover/index.js +0 -1
  19. package/dist/components/InternalPopover/index.js.map +1 -1
  20. package/dist/components/Panel/index.d.ts +2 -2
  21. package/dist/components/Panel/index.d.ts.map +1 -1
  22. package/dist/components/Panel/index.js +3 -11
  23. package/dist/components/Panel/index.js.map +1 -1
  24. package/dist/components/Popover/index.d.ts +1 -1
  25. package/dist/components/Popover/index.d.ts.map +1 -1
  26. package/dist/components/Popover/index.js +4 -2
  27. package/dist/components/Popover/index.js.map +1 -1
  28. package/dist/hooks/usePopover.d.ts.map +1 -1
  29. package/dist/hooks/usePopover.js +23 -9
  30. package/dist/hooks/usePopover.js.map +1 -1
  31. package/dist/hooks/useWhyDidYouUpdate.d.ts +2 -0
  32. package/dist/hooks/useWhyDidYouUpdate.d.ts.map +1 -0
  33. package/dist/hooks/useWhyDidYouUpdate.js +47 -0
  34. package/dist/hooks/useWhyDidYouUpdate.js.map +1 -0
  35. package/package.json +1 -1
  36. package/src/components/Collection/item.tsx +6 -3
  37. package/src/components/Dropdown/index.tsx +62 -36
  38. package/src/components/Dropdown/item.tsx +3 -6
  39. package/src/components/Dropdown/list.tsx +82 -56
  40. package/src/components/InternalPopover/index.tsx +0 -2
  41. package/src/components/Panel/index.tsx +59 -57
  42. package/src/components/Popover/index.tsx +53 -38
  43. package/src/hooks/usePopover.tsx +34 -20
  44. package/src/hooks/useWhyDidYouUpdate.ts +32 -0
  45. package/src/stories/Collection/Collection.stories.tsx +1 -1
  46. package/src/stories/Dropdown/Dropdown.stories.tsx +62 -34
  47. package/src/stories/Panel/Panel.stories.tsx +4 -4
  48. package/tests.json +1 -1
@@ -133,8 +133,6 @@ const InternalPopover: React.FC<IReqoreInternalPopoverProps> = ({
133
133
  ],
134
134
  });
135
135
 
136
- console.log(opaque);
137
-
138
136
  useEffect(() => {
139
137
  if (popperRef.current) {
140
138
  updatePopover?.(id, { popperRef });
@@ -31,13 +31,13 @@ import ReqoreButton, { IReqoreButtonProps } from '../Button';
31
31
  import { StyledCollectionItemContent } from '../Collection/item';
32
32
  import ReqoreControlGroup from '../ControlGroup';
33
33
  import ReqoreDropdown from '../Dropdown';
34
- import { IReqoreDropdownItemProps } from '../Dropdown/item';
34
+ import { IReqoreDropdownItem } from '../Dropdown/list';
35
35
  import ReqoreIcon from '../Icon';
36
36
 
37
37
  export interface IReqorePanelAction extends IReqoreButtonProps, IWithReqoreTooltip, IReqoreIntent {
38
38
  label?: string | number;
39
39
  onClick?: () => void;
40
- actions?: IReqoreDropdownItemProps[];
40
+ actions?: IReqoreDropdownItem[];
41
41
  customContent?: () => string | React.ReactNode;
42
42
  }
43
43
 
@@ -267,66 +267,68 @@ export const ReqorePanel = forwardRef(
267
267
  [leftBottomActions, rightBottomActions]
268
268
  );
269
269
 
270
- const renderActions = (
271
- actionOrActions: IReqorePanelAction | IReqorePanelAction[],
272
- index: number
273
- ) => {
274
- if (Array.isArray(actionOrActions)) {
275
- return (
276
- <ReqoreControlGroup stack minimal>
277
- {actionOrActions.map(renderActions)}
278
- </ReqoreControlGroup>
279
- );
280
- }
281
-
282
- const { id, actions, label, intent, className, customContent, ...rest }: IReqorePanelAction =
283
- actionOrActions;
270
+ const renderActions = useCallback(
271
+ (actionOrActions: IReqorePanelAction | IReqorePanelAction[], index: number) => {
272
+ if (Array.isArray(actionOrActions)) {
273
+ return (
274
+ <ReqoreControlGroup stack minimal>
275
+ {actionOrActions.map(renderActions)}
276
+ </ReqoreControlGroup>
277
+ );
278
+ }
279
+
280
+ const {
281
+ id,
282
+ actions,
283
+ label,
284
+ intent,
285
+ className,
286
+ customContent,
287
+ ...rest
288
+ }: IReqorePanelAction = actionOrActions;
289
+
290
+ if (size(actions)) {
291
+ return (
292
+ <ReqoreDropdown<IReqoreButtonProps>
293
+ {...rest}
294
+ key={index}
295
+ label={label}
296
+ items={actions}
297
+ intent={intent}
298
+ className={className}
299
+ onClick={(e: React.MouseEvent<HTMLButtonElement>) => e.stopPropagation()}
300
+ id={id}
301
+ />
302
+ );
303
+ }
304
+
305
+ if (customContent) {
306
+ return customContent();
307
+ }
284
308
 
285
- if (size(actions)) {
286
309
  return (
287
- <ReqoreDropdown
310
+ <ReqoreButton
288
311
  {...rest}
312
+ id={id}
289
313
  key={index}
290
- label={label}
291
- componentProps={{
292
- intent,
293
- id,
294
- minimal: true,
295
- className,
296
- onClick: (e: React.MouseEvent<HTMLButtonElement>) => {
297
- e.stopPropagation();
298
- },
299
- }}
300
- items={actions}
301
- />
314
+ className={className}
315
+ customTheme={theme}
316
+ intent={intent}
317
+ onClick={
318
+ rest.onClick
319
+ ? (e: React.MouseEvent<HTMLButtonElement>) => {
320
+ e.stopPropagation();
321
+ rest.onClick?.();
322
+ }
323
+ : undefined
324
+ }
325
+ >
326
+ {label}
327
+ </ReqoreButton>
302
328
  );
303
- }
304
-
305
- if (customContent) {
306
- return customContent();
307
- }
308
-
309
- return (
310
- <ReqoreButton
311
- {...rest}
312
- id={id}
313
- key={index}
314
- className={className}
315
- customTheme={theme}
316
- intent={intent}
317
- onClick={
318
- rest.onClick
319
- ? (e: React.MouseEvent<HTMLButtonElement>) => {
320
- e.stopPropagation();
321
- rest.onClick?.();
322
- }
323
- : undefined
324
- }
325
- >
326
- {label}
327
- </ReqoreButton>
328
- );
329
- };
329
+ },
330
+ [actions, theme]
331
+ );
330
332
 
331
333
  const HTMLheaderElement = useMemo(() => {
332
334
  return `h${headerSize}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
@@ -1,6 +1,7 @@
1
- import React, { useState } from 'react';
1
+ import React, { memo, useState } from 'react';
2
2
  import styled from 'styled-components';
3
3
  import usePopover, { IPopoverOptions } from '../../hooks/usePopover';
4
+ import { useWhyDidYouUpdate } from '../../hooks/useWhyDidYouUpdate';
4
5
  import { IReqoreComponent } from '../../types/global';
5
6
 
6
7
  export interface IReqorePopoverProps extends IReqoreComponent, IPopoverOptions {
@@ -17,49 +18,63 @@ export const StyledPopover = styled.span`
17
18
  overflow: hidden;
18
19
  `;
19
20
 
20
- const Popover = ({
21
- component: Component,
22
- componentProps,
23
- children,
24
- isReqoreComponent,
25
- noWrapper,
26
- wrapperTag = 'span',
27
- wrapperStyle = {},
28
- _insidePopover,
29
- _popoverId,
30
- ...rest
31
- }: IReqorePopoverProps) => {
32
- const [ref, setRef] = useState(undefined);
21
+ const Popover = memo(
22
+ ({
23
+ component: Component,
24
+ componentProps,
25
+ children,
26
+ isReqoreComponent,
27
+ noWrapper,
28
+ wrapperTag = 'span',
29
+ wrapperStyle = {},
30
+ _insidePopover,
31
+ _popoverId,
32
+ ...rest
33
+ }: IReqorePopoverProps) => {
34
+ const [ref, setRef] = useState(undefined);
33
35
 
34
- usePopover({ targetElement: ref, ...rest });
36
+ useWhyDidYouUpdate('popover', {
37
+ component: Component,
38
+ componentProps,
39
+ children,
40
+ isReqoreComponent,
41
+ noWrapper,
42
+ wrapperTag,
43
+ wrapperStyle,
44
+ _insidePopover,
45
+ _popoverId,
46
+ ...rest,
47
+ });
48
+ usePopover({ targetElement: ref, ...rest });
49
+
50
+ if (isReqoreComponent || noWrapper) {
51
+ return (
52
+ <Component
53
+ {...componentProps}
54
+ _insidePopover={_insidePopover}
55
+ _popoverId={_popoverId}
56
+ ref={setRef}
57
+ >
58
+ {children}
59
+ </Component>
60
+ );
61
+ }
35
62
 
36
- if (isReqoreComponent || noWrapper) {
37
63
  return (
38
- <Component
39
- {...componentProps}
40
- _insidePopover={_insidePopover}
41
- _popoverId={_popoverId}
64
+ // @ts-ignore
65
+ <StyledPopover
66
+ // @ts-ignore
67
+ as={wrapperTag}
68
+ className='reqore-popover-wrapper'
42
69
  ref={setRef}
70
+ style={wrapperStyle}
43
71
  >
44
- {children}
45
- </Component>
72
+ <Component {...componentProps} _insidePopover={_insidePopover} _popoverId={_popoverId}>
73
+ {children}
74
+ </Component>
75
+ </StyledPopover>
46
76
  );
47
77
  }
48
-
49
- return (
50
- // @ts-ignore
51
- <StyledPopover
52
- // @ts-ignore
53
- as={wrapperTag}
54
- className='reqore-popover-wrapper'
55
- ref={setRef}
56
- style={wrapperStyle}
57
- >
58
- <Component {...componentProps} _insidePopover={_insidePopover} _popoverId={_popoverId}>
59
- {children}
60
- </Component>
61
- </StyledPopover>
62
- );
63
- };
78
+ );
64
79
 
65
80
  export default Popover;
@@ -63,30 +63,38 @@ const usePopover = ({
63
63
  [popovers, current]
64
64
  );
65
65
 
66
+ const openPopover = () => {
67
+ addPopover?.({
68
+ id: current,
69
+ content,
70
+ targetElement,
71
+ placement,
72
+ noArrow,
73
+ useTargetWidth,
74
+ closeOnOutsideClick,
75
+ closeOnAnyClick: handler === 'hover' || handler === 'hoverStay',
76
+ ...rest,
77
+ });
78
+
79
+ if (rest?.blur > 0) {
80
+ targetElement.style.position = 'relative';
81
+ targetElement.style.zIndex = '999999';
82
+ }
83
+ };
84
+
66
85
  const _addPopover = () => {
67
86
  if (currentPopover) {
68
87
  if (handler !== 'hoverStay') {
69
88
  _removePopover?.();
70
89
  }
71
90
  } else if (show) {
72
- timeout = setTimeout(() => {
73
- addPopover?.({
74
- id: current,
75
- content,
76
- targetElement,
77
- placement,
78
- noArrow,
79
- useTargetWidth,
80
- closeOnOutsideClick,
81
- closeOnAnyClick: handler === 'hover' || handler === 'hoverStay',
82
- ...rest,
83
- });
84
-
85
- if (rest?.blur > 0) {
86
- targetElement.style.position = 'relative';
87
- targetElement.style.zIndex = '999999';
88
- }
89
- }, delay || 0);
91
+ if (delay) {
92
+ timeout = setTimeout(() => {
93
+ openPopover();
94
+ }, delay);
95
+ } else {
96
+ openPopover();
97
+ }
90
98
  }
91
99
  };
92
100
 
@@ -119,7 +127,7 @@ const usePopover = ({
119
127
  ...rest,
120
128
  });
121
129
  }
122
- }, [content?.toString()]);
130
+ }, [content]);
123
131
 
124
132
  useEffect(() => {
125
133
  if (openOnMount && targetElement) {
@@ -155,7 +163,13 @@ const usePopover = ({
155
163
  }
156
164
  }
157
165
  };
158
- }, [targetElement?.toString(), content?.toString(), current, currentPopover]);
166
+ }, [
167
+ targetElement?.toString(),
168
+ //@ts-ignore
169
+ content,
170
+ current,
171
+ currentPopover,
172
+ ]);
159
173
 
160
174
  useUnmount(() => {
161
175
  cancelTimeout();
@@ -0,0 +1,32 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ export function useWhyDidYouUpdate(name, props) {
4
+ // Get a mutable ref object where we can store props ...
5
+ // ... for comparison next time this hook runs.
6
+ const previousProps: any = useRef();
7
+ useEffect(() => {
8
+ if (previousProps.current) {
9
+ // Get all keys from previous and current props
10
+ const allKeys = Object.keys({ ...previousProps.current, ...props });
11
+ // Use this object to keep track of changed props
12
+ const changesObj = {};
13
+ // Iterate through keys
14
+ allKeys.forEach((key) => {
15
+ // If previous is different from current
16
+ if (previousProps.current[key] !== props[key]) {
17
+ // Add to changesObj
18
+ changesObj[key] = {
19
+ from: previousProps.current[key],
20
+ to: props[key],
21
+ };
22
+ }
23
+ });
24
+ // If changesObj not empty then output to console
25
+ if (Object.keys(changesObj).length) {
26
+ console.log('[why-did-you-update]', name, changesObj);
27
+ }
28
+ }
29
+ // Finally update previousProps with current props for next hook call
30
+ previousProps.current = props;
31
+ });
32
+ }
@@ -72,7 +72,7 @@ const Template: Story<IReqoreCollectionProps> = (args) => {
72
72
  return (
73
73
  <ReqoreCollection
74
74
  {...args}
75
- actions={[{ label: 'Custom action', icon: 'Home7Line' }, { actions: [{ label: 'Test' }] }]}
75
+ actions={[{ label: 'Custom action', icon: 'Home7Line' }, { actions: [{ value: 'Test' }] }]}
76
76
  />
77
77
  );
78
78
  };
@@ -1,26 +1,27 @@
1
1
  import { Meta, Story } from '@storybook/react/types-6-0';
2
+ import { useState } from 'react';
2
3
  import ReqoreButton from '../../components/Button';
3
4
  import { IReqoreDropdownProps } from '../../components/Dropdown';
4
- import { IReqoreInputProps } from '../../components/Input';
5
- import { ReqoreControlGroup, ReqoreDropdown, ReqoreInput } from '../../index';
5
+ import { ReqoreControlGroup, ReqoreDropdown, ReqoreInput, ReqoreTag } from '../../index';
6
6
  import { argManager } from '../utils/args';
7
7
 
8
- const { createArg } = argManager<IReqoreDropdownProps<IReqoreInputProps>>();
8
+ const { createArg, disableArg } = argManager<IReqoreDropdownProps>();
9
9
 
10
10
  export default {
11
11
  title: 'Components/Dropdown',
12
+ parameters: {
13
+ chromatic: {
14
+ delay: 500,
15
+ },
16
+ },
12
17
  argTypes: {
18
+ ...disableArg('multiSelect'),
13
19
  ...createArg('component', {
14
20
  defaultValue: ReqoreButton,
15
21
  table: {
16
22
  disable: true,
17
23
  },
18
24
  }),
19
- ...createArg('componentProps', {
20
- table: {
21
- disable: true,
22
- },
23
- }),
24
25
  ...createArg('filterable', {
25
26
  defaultValue: true,
26
27
  name: 'Filterable',
@@ -34,96 +35,121 @@ export default {
34
35
  defaultValue: [
35
36
  {
36
37
  selected: true,
37
- label: 'Hello',
38
+ value: 'Hello',
38
39
  icon: 'SunCloudyLine',
39
40
  },
40
41
  {
41
- label: 'How are ya, I am super long item and I am not going to fit in the dropdown',
42
+ value: 'How are ya, I am super long item and I am not going to fit in the dropdown',
42
43
  icon: 'BatteryChargeFill',
43
44
  },
44
45
  {
45
46
  disabled: true,
46
- label: 'i aM diSAblEd',
47
+ value: 'i aM diSAblEd',
47
48
  icon: 'StopCircleLine',
48
49
  },
49
50
  {
50
51
  selected: true,
51
- label: 'Hello',
52
+ value: 'Hello',
52
53
  icon: 'SunCloudyLine',
53
54
  },
54
55
  {
55
- label: 'How are ya',
56
+ value: 'How are ya',
56
57
  icon: 'BatteryChargeFill',
57
58
  },
58
59
  {
59
60
  disabled: true,
60
- label: 'i aM diSAblEd',
61
+ value: 'i aM diSAblEd',
61
62
  icon: 'StopCircleLine',
62
63
  },
63
64
  {
64
65
  selected: true,
65
- label: 'Hello',
66
+ value: 'Hello',
66
67
  icon: 'SunCloudyLine',
67
68
  },
68
69
  {
69
- label: 'How are ya',
70
+ value: 'How are ya',
70
71
  icon: 'BatteryChargeFill',
71
72
  },
72
73
  {
73
74
  disabled: true,
74
- label: 'i aM diSAblEd',
75
+ value: 'i aM diSAblEd',
75
76
  icon: 'StopCircleLine',
76
77
  },
77
78
  {
78
79
  selected: true,
79
- label: 'Hello',
80
+ value: 'Hello',
80
81
  icon: 'SunCloudyLine',
81
82
  },
82
83
  {
83
- label: 'How are ya',
84
+ value: 'How are ya',
84
85
  icon: 'BatteryChargeFill',
85
86
  },
86
87
  {
87
88
  disabled: true,
88
- label: 'i aM diSAblEd',
89
+ value: 'i aM diSAblEd',
89
90
  icon: 'StopCircleLine',
90
91
  },
91
92
  {
92
93
  selected: true,
93
- label: 'Hello',
94
+ value: 'Hello',
94
95
  icon: 'SunCloudyLine',
95
96
  },
96
97
  {
97
- label: 'How are ya',
98
+ value: 'How are ya',
98
99
  icon: 'BatteryChargeFill',
99
100
  },
100
101
  {
101
102
  disabled: true,
102
- label: 'i aM diSAblEd',
103
+ value: 'i aM diSAblEd',
103
104
  icon: 'StopCircleLine',
104
105
  },
105
106
  {
106
107
  selected: true,
107
- label: 'Hello',
108
+ value: 'Hello',
108
109
  icon: 'SunCloudyLine',
109
110
  },
110
111
  {
111
- label: 'How are ya',
112
+ value: 'How are ya',
112
113
  icon: 'BatteryChargeFill',
113
114
  },
114
115
  {
115
116
  disabled: true,
116
- label: 'i aM diSAblEd',
117
+ value: 'i aM diSAblEd',
117
118
  icon: 'StopCircleLine',
118
119
  },
119
120
  ],
120
121
  }),
121
122
  },
122
- } as Meta<IReqoreDropdownProps<IReqoreInputProps>>;
123
+ } as Meta<IReqoreDropdownProps>;
124
+
125
+ const Template: Story<IReqoreDropdownProps> = (args: IReqoreDropdownProps) => {
126
+ const [selected, setSelected] = useState<string[]>(['Item 3', 'Item 6']);
127
+
128
+ if (args.multiSelect) {
129
+ return (
130
+ <>
131
+ <ReqoreControlGroup>
132
+ <ReqoreDropdown
133
+ label='Multi Select'
134
+ multiSelect
135
+ isDefaultOpen
136
+ onItemSelect={({ label }) => setSelected([...selected, label])}
137
+ items={Array(13)
138
+ .fill(null)
139
+ .map((_, i) => ({
140
+ label: `Item ${i}`,
141
+ value: `item-${i}`,
142
+ selected: selected.includes(`Item ${i}`),
143
+ }))}
144
+ />
145
+ {selected.map((item, index) => (
146
+ <ReqoreTag label={item} key={index} />
147
+ ))}
148
+ </ReqoreControlGroup>
149
+ </>
150
+ );
151
+ }
123
152
 
124
- const Template: Story<IReqoreDropdownProps<IReqoreInputProps>> = (
125
- args: IReqoreDropdownProps<IReqoreInputProps>
126
- ) => {
127
153
  return (
128
154
  <>
129
155
  <ReqoreControlGroup>
@@ -141,7 +167,7 @@ const Template: Story<IReqoreDropdownProps<IReqoreInputProps>> = (
141
167
  caretPosition='right'
142
168
  label='Open By Default'
143
169
  {...args}
144
- componentProps={{ placeholder: 'Fluid component' }}
170
+ placeholder='Fluid component'
145
171
  isDefaultOpen
146
172
  useTargetWidth
147
173
  />
@@ -154,7 +180,9 @@ export const Basic = Template.bind({});
154
180
  export const CustomComponent = Template.bind({});
155
181
  CustomComponent.args = {
156
182
  component: ReqoreInput,
157
- componentProps: {
158
- placeholder: 'Custom component',
159
- },
183
+ placeholder: 'Custom component',
184
+ };
185
+ export const MultiSelect = Template.bind({});
186
+ MultiSelect.args = {
187
+ multiSelect: true,
160
188
  };
@@ -68,8 +68,8 @@ const Template: Story<IReqorePanelProps> = (args: IReqorePanelProps) => {
68
68
  {
69
69
  label: 'More actions',
70
70
  actions: [
71
- { label: 'Sub Test', icon: 'FileDownloadLine' },
72
- { label: 'Sub Test 2', icon: 'FileDownloadLine', intent: 'success' },
71
+ { value: 'Sub Test', icon: 'FileDownloadLine' },
72
+ { value: 'Sub Test 2', icon: 'FileDownloadLine', intent: 'success' },
73
73
  ],
74
74
  intent: 'info',
75
75
  },
@@ -80,8 +80,8 @@ const Template: Story<IReqorePanelProps> = (args: IReqorePanelProps) => {
80
80
  label: 'More actions',
81
81
  position: 'right',
82
82
  actions: [
83
- { label: 'Sub Test', icon: 'FileDownloadLine', intent: 'success' },
84
- { label: 'Sub Test 2', icon: 'FileDownloadLine' },
83
+ { value: 'Sub Test', icon: 'FileDownloadLine', intent: 'success' },
84
+ { value: 'Sub Test 2', icon: 'FileDownloadLine' },
85
85
  ],
86
86
  },
87
87
  ]}