@true-engineering/true-react-common-ui-kit 4.0.0-alpha29 → 4.0.0-alpha30
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/dist/components/ControlWrapper/ControlWrapper.d.ts +3 -3
- package/dist/components/ControlWrapper/helpers.d.ts +4 -0
- package/dist/components/ControlWrapper/index.d.ts +1 -0
- package/dist/components/ControlWrapper/types.d.ts +9 -0
- package/dist/components/Input/InputBase.d.ts +1 -1
- package/dist/components/Select/Select.styles.d.ts +1 -1
- package/dist/true-react-common-ui-kit.js +76 -101
- package/dist/true-react-common-ui-kit.js.map +1 -1
- package/dist/true-react-common-ui-kit.umd.cjs +74 -99
- package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
- package/package.json +1 -1
- package/src/components/ControlWrapper/ControlWrapper.stories.tsx +7 -2
- package/src/components/ControlWrapper/ControlWrapper.tsx +24 -19
- package/src/components/ControlWrapper/helpers.ts +11 -0
- package/src/components/ControlWrapper/index.ts +1 -0
- package/src/components/ControlWrapper/types.ts +12 -0
- package/src/components/DateInput/DateInput.stories.tsx +0 -1
- package/src/components/DatePicker/DatePicker.stories.tsx +1 -10
- package/src/components/Input/Input.stories.tsx +1 -6
- package/src/components/Input/InputBase.tsx +0 -3
- package/src/components/Select/CustomSelect.stories.tsx +1 -0
- package/src/components/Select/MultiSelect.stories.tsx +5 -0
- package/src/components/Select/Select.stories.tsx +6 -0
- package/src/components/Select/Select.styles.ts +5 -40
- package/src/components/Select/Select.tsx +24 -20
- package/src/components/TextArea/TextArea.stories.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { doNothing } from '@true-engineering/true-react-platform-helpers';
|
|
2
2
|
import { ComponentStory } from '@storybook/react';
|
|
3
|
-
import { iconsList } from '../Icon';
|
|
3
|
+
import { Icon, iconsList } from '../Icon';
|
|
4
4
|
import { ControlWrapper } from './ControlWrapper';
|
|
5
5
|
|
|
6
6
|
export default {
|
|
@@ -9,7 +9,7 @@ export default {
|
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
const Template: ComponentStory<typeof ControlWrapper> = (args) => (
|
|
12
|
-
<ControlWrapper {...args} onClear={doNothing}
|
|
12
|
+
<ControlWrapper {...args} onClear={doNothing}>
|
|
13
13
|
<div style={{ minWidth: 200, height: 48 }} />
|
|
14
14
|
</ControlWrapper>
|
|
15
15
|
);
|
|
@@ -24,6 +24,11 @@ Default.args = {
|
|
|
24
24
|
isLoading: false,
|
|
25
25
|
isDisabled: false,
|
|
26
26
|
hasValue: false,
|
|
27
|
+
icon: [
|
|
28
|
+
{ iconComponent: <div>Бу</div>, onClick: () => console.log('close'), shouldResetSize: true },
|
|
29
|
+
{ iconComponent: <Icon type="question" /> },
|
|
30
|
+
{ iconComponent: 'search', onClick: () => console.log('search') },
|
|
31
|
+
],
|
|
27
32
|
};
|
|
28
33
|
|
|
29
34
|
Default.argTypes = {
|
|
@@ -4,21 +4,24 @@ import {
|
|
|
4
4
|
addClickHandler,
|
|
5
5
|
addDataAttributes,
|
|
6
6
|
addDataTestId,
|
|
7
|
+
getArray,
|
|
8
|
+
isArrayNotEmpty,
|
|
7
9
|
isNotEmpty,
|
|
8
10
|
isReactNodeNotEmpty,
|
|
9
|
-
isString,
|
|
10
11
|
} from '@true-engineering/true-react-platform-helpers';
|
|
11
12
|
import { useTweakStyles } from '../../hooks';
|
|
13
|
+
import { IMaybeArray } from '../../theme';
|
|
12
14
|
import { IClickHandlerEvent, ICommonProps } from '../../types';
|
|
13
15
|
import { Icon, IIcon, renderIcon } from '../Icon';
|
|
14
16
|
import { ThemedPreloader } from '../ThemedPreloader';
|
|
15
|
-
import {
|
|
17
|
+
import { convertToControlWrapperIcon } from './helpers';
|
|
18
|
+
import { IControlWrapperIcon, IControlWrapperSize } from './types';
|
|
16
19
|
import { IControlWrapperStyles, useStyles } from './ControlWrapper.styles';
|
|
17
20
|
|
|
18
21
|
export interface IControlWrapperProps extends ICommonProps<IControlWrapperStyles> {
|
|
19
22
|
children: ReactNode;
|
|
20
23
|
label?: ReactNode;
|
|
21
|
-
icon?: IIcon
|
|
24
|
+
icon?: IMaybeArray<IIcon | IControlWrapperIcon>;
|
|
22
25
|
size?: IControlWrapperSize;
|
|
23
26
|
groupPlacement?:
|
|
24
27
|
| 'left'
|
|
@@ -44,7 +47,6 @@ export interface IControlWrapperProps extends ICommonProps<IControlWrapperStyles
|
|
|
44
47
|
isLoading?: boolean;
|
|
45
48
|
/** @default false */
|
|
46
49
|
isDisabled?: boolean;
|
|
47
|
-
onIconClick?: (event: IClickHandlerEvent) => void;
|
|
48
50
|
onClear?: (event: IClickHandlerEvent) => void;
|
|
49
51
|
}
|
|
50
52
|
|
|
@@ -64,14 +66,15 @@ export const ControlWrapper: FC<IControlWrapperProps> = ({
|
|
|
64
66
|
children,
|
|
65
67
|
tweakStyles,
|
|
66
68
|
data,
|
|
67
|
-
onIconClick,
|
|
68
69
|
onClear,
|
|
69
70
|
}) => {
|
|
70
71
|
const classes = useStyles({ theme: tweakStyles });
|
|
71
72
|
|
|
72
|
-
const
|
|
73
|
+
const icons = getArray(icon).map(convertToControlWrapperIcon);
|
|
74
|
+
|
|
75
|
+
const hasIcons = !isLoading && isArrayNotEmpty(icons);
|
|
73
76
|
const hasClearButton = !isDisabled && !isLoading && hasValue && isNotEmpty(onClear);
|
|
74
|
-
const hasControls =
|
|
77
|
+
const hasControls = hasIcons || hasClearButton || isLoading;
|
|
75
78
|
|
|
76
79
|
const isActive = isFocused || hasValue;
|
|
77
80
|
|
|
@@ -126,18 +129,20 @@ export const ControlWrapper: FC<IControlWrapperProps> = ({
|
|
|
126
129
|
</div>
|
|
127
130
|
)}
|
|
128
131
|
|
|
129
|
-
{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
132
|
+
{hasIcons &&
|
|
133
|
+
icons.map(({ key, iconComponent, onClick, shouldResetSize = false }, index) => (
|
|
134
|
+
<div
|
|
135
|
+
key={key ?? index}
|
|
136
|
+
className={clsx(classes.icon, classes.endIcon, {
|
|
137
|
+
[classes.activeIcon]: !isDisabled && isNotEmpty(onClick),
|
|
138
|
+
[classes.customIcon]: shouldResetSize,
|
|
139
|
+
})}
|
|
140
|
+
{...addClickHandler(onClick, !isDisabled)}
|
|
141
|
+
{...addDataTestId(testId, 'icon')}
|
|
142
|
+
>
|
|
143
|
+
<div className={classes.iconInner}>{renderIcon(iconComponent)}</div>
|
|
144
|
+
</div>
|
|
145
|
+
))}
|
|
141
146
|
|
|
142
147
|
{isLoading && (
|
|
143
148
|
<div
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isObject } from 'lodash-es';
|
|
2
|
+
import { IIcon } from '../Icon';
|
|
3
|
+
import { IControlWrapperIcon } from './types';
|
|
4
|
+
|
|
5
|
+
export const isControlWrapperIcon = (
|
|
6
|
+
iconItem: IIcon | IControlWrapperIcon,
|
|
7
|
+
): iconItem is IControlWrapperIcon => isObject(iconItem) && 'iconComponent' in iconItem;
|
|
8
|
+
|
|
9
|
+
export const convertToControlWrapperIcon = (
|
|
10
|
+
iconItem: IIcon | IControlWrapperIcon,
|
|
11
|
+
): IControlWrapperIcon => (isControlWrapperIcon(iconItem) ? iconItem : { iconComponent: iconItem });
|
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import { type Key } from 'react';
|
|
2
|
+
import { IClickHandlerEvent } from '../../types';
|
|
3
|
+
import { IIcon } from '../Icon';
|
|
4
|
+
|
|
1
5
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
2
6
|
export interface IControlWrapperSizes {}
|
|
3
7
|
|
|
4
8
|
export type IControlWrapperSize = keyof IControlWrapperSizes;
|
|
9
|
+
|
|
10
|
+
// подумать над extend HTMLAttributes<HTMLDivElement>
|
|
11
|
+
export interface IControlWrapperIcon {
|
|
12
|
+
key?: Key;
|
|
13
|
+
iconComponent: IIcon;
|
|
14
|
+
onClick?: (event: IClickHandlerEvent) => void;
|
|
15
|
+
shouldResetSize?: boolean;
|
|
16
|
+
}
|
|
@@ -96,15 +96,6 @@ Default.argTypes = {
|
|
|
96
96
|
|
|
97
97
|
Default.parameters = {
|
|
98
98
|
controls: {
|
|
99
|
-
exclude: [
|
|
100
|
-
'data',
|
|
101
|
-
'testId',
|
|
102
|
-
'tabIndex',
|
|
103
|
-
'onFocus',
|
|
104
|
-
'onBlur',
|
|
105
|
-
'onPaste',
|
|
106
|
-
'onIconClick',
|
|
107
|
-
'onKeyDown',
|
|
108
|
-
],
|
|
99
|
+
exclude: ['data', 'testId', 'tabIndex', 'onFocus', 'onBlur', 'onPaste', 'onKeyDown'],
|
|
109
100
|
},
|
|
110
101
|
};
|
|
@@ -35,12 +35,7 @@ const Template: ComponentStory<typeof Input> = (args) => {
|
|
|
35
35
|
|
|
36
36
|
return (
|
|
37
37
|
<div style={{ width: 300 }}>
|
|
38
|
-
<Input
|
|
39
|
-
{...args}
|
|
40
|
-
value={value}
|
|
41
|
-
onChange={setValue}
|
|
42
|
-
onIconClick={() => console.log('icon click')}
|
|
43
|
-
/>
|
|
38
|
+
<Input {...args} value={value} onChange={setValue} />
|
|
44
39
|
</div>
|
|
45
40
|
);
|
|
46
41
|
};
|
|
@@ -39,7 +39,6 @@ export interface IInputBaseProps
|
|
|
39
39
|
| 'isRequired'
|
|
40
40
|
| 'isLoading'
|
|
41
41
|
| 'isDisabled'
|
|
42
|
-
| 'onIconClick'
|
|
43
42
|
>,
|
|
44
43
|
Pick<
|
|
45
44
|
Partial<ReactInputMaskBaseProps>,
|
|
@@ -102,7 +101,6 @@ export const InputBase = forwardRef<HTMLInputElement, IInputBaseProps>(
|
|
|
102
101
|
isLoading,
|
|
103
102
|
isRequired,
|
|
104
103
|
size,
|
|
105
|
-
onIconClick,
|
|
106
104
|
children,
|
|
107
105
|
...inputProps
|
|
108
106
|
},
|
|
@@ -241,7 +239,6 @@ export const InputBase = forwardRef<HTMLInputElement, IInputBaseProps>(
|
|
|
241
239
|
icon={icon}
|
|
242
240
|
isLoading={isLoading}
|
|
243
241
|
isRequired={isRequired}
|
|
244
|
-
onIconClick={onIconClick}
|
|
245
242
|
size={size}
|
|
246
243
|
>
|
|
247
244
|
{hasUnits || isAutoSized ? (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReactNode, useEffect, useState } from 'react';
|
|
2
2
|
import { isStringNotEmpty } from '@true-engineering/true-react-platform-helpers';
|
|
3
3
|
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
4
|
+
import { iconsList } from '../Icon';
|
|
4
5
|
import { IMultipleSelectProps, Select } from './Select';
|
|
5
6
|
|
|
6
7
|
interface ObjectValue {
|
|
@@ -54,6 +55,8 @@ const objectOptions: ObjectValue[] = [
|
|
|
54
55
|
{ name: 'Artem', age: 23 },
|
|
55
56
|
];
|
|
56
57
|
|
|
58
|
+
const icons = [undefined, ...Object.keys(iconsList)];
|
|
59
|
+
|
|
57
60
|
// Максимум не включается, минимум включается
|
|
58
61
|
const getRandomInt = (min: number, max: number) =>
|
|
59
62
|
Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min))) + Math.ceil(min);
|
|
@@ -195,6 +198,7 @@ export default {
|
|
|
195
198
|
control: 'inline-radio',
|
|
196
199
|
options: ['strings', 'objects'],
|
|
197
200
|
},
|
|
201
|
+
icon: { control: 'select', options: icons },
|
|
198
202
|
},
|
|
199
203
|
} as ComponentMeta<typeof SelectWithCustomProps>;
|
|
200
204
|
|
|
@@ -229,4 +233,5 @@ MultiSelect.args = {
|
|
|
229
233
|
shouldScrollToList: true,
|
|
230
234
|
canBeFlipped: false,
|
|
231
235
|
scrollParent: 'document',
|
|
236
|
+
size: undefined,
|
|
232
237
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ReactNode, useEffect, useState } from 'react';
|
|
2
2
|
import { isStringNotEmpty } from '@true-engineering/true-react-platform-helpers';
|
|
3
3
|
import { ComponentMeta, ComponentStory } from '@storybook/react';
|
|
4
|
+
import { iconsList } from '../Icon';
|
|
4
5
|
import { ISelectProps, Select } from './Select';
|
|
5
6
|
|
|
6
7
|
interface ObjectValue {
|
|
@@ -54,6 +55,8 @@ const objectOptions: ObjectValue[] = [
|
|
|
54
55
|
{ name: 'Artem', age: 23 },
|
|
55
56
|
];
|
|
56
57
|
|
|
58
|
+
const icons = [undefined, ...Object.keys(iconsList)];
|
|
59
|
+
|
|
57
60
|
// Максимум не включается, минимум включается
|
|
58
61
|
const getRandomInt = (min: number, max: number) =>
|
|
59
62
|
Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min))) + Math.ceil(min);
|
|
@@ -192,6 +195,7 @@ export default {
|
|
|
192
195
|
control: 'inline-radio',
|
|
193
196
|
options: ['strings', 'objects'],
|
|
194
197
|
},
|
|
198
|
+
icon: { control: 'select', options: icons },
|
|
195
199
|
},
|
|
196
200
|
} as ComponentMeta<typeof SelectWithCustomProps>;
|
|
197
201
|
|
|
@@ -213,6 +217,7 @@ Default.args = {
|
|
|
213
217
|
isClearable: false,
|
|
214
218
|
isLoading: false,
|
|
215
219
|
debounceTime: 400,
|
|
220
|
+
icon: undefined,
|
|
216
221
|
// custom options
|
|
217
222
|
shouldUseReactNodes: false,
|
|
218
223
|
valuesType: 'strings',
|
|
@@ -225,4 +230,5 @@ Default.args = {
|
|
|
225
230
|
shouldScrollToList: true,
|
|
226
231
|
canBeFlipped: false,
|
|
227
232
|
scrollParent: 'document',
|
|
233
|
+
size: undefined,
|
|
228
234
|
};
|
|
@@ -5,7 +5,7 @@ import { type ISearchInputStyles } from '../SearchInput';
|
|
|
5
5
|
import { IWithMessagesStyles } from '../WithMessages';
|
|
6
6
|
import { type ISelectListStyles } from './components';
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const { Z_INDEX } = dimensions;
|
|
9
9
|
|
|
10
10
|
export const useStyles = createThemedStyles('Select', {
|
|
11
11
|
root: {
|
|
@@ -17,7 +17,6 @@ export const useStyles = createThemedStyles('Select', {
|
|
|
17
17
|
inputWrapper: {
|
|
18
18
|
width: '100%',
|
|
19
19
|
cursor: 'text',
|
|
20
|
-
position: 'relative',
|
|
21
20
|
},
|
|
22
21
|
|
|
23
22
|
listWrapper: {
|
|
@@ -40,20 +39,16 @@ export const useStyles = createThemedStyles('Select', {
|
|
|
40
39
|
},
|
|
41
40
|
|
|
42
41
|
arrow: {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
top: '50%',
|
|
46
|
-
width: 20,
|
|
47
|
-
height: 20,
|
|
42
|
+
width: 'var(--icon-inner-size, 20px)',
|
|
43
|
+
height: 'var(--icon-inner-size, 20px)',
|
|
48
44
|
cursor: 'pointer',
|
|
49
|
-
transform: 'translateY(-50%)',
|
|
50
45
|
transition: animations.defaultTransition,
|
|
51
46
|
transitionProperty: 'transform',
|
|
52
47
|
zIndex: Z_INDEX.CONTROL_FOCUS + 1,
|
|
53
48
|
},
|
|
54
49
|
|
|
55
50
|
activeArrow: {
|
|
56
|
-
transform: '
|
|
51
|
+
transform: 'rotate(180deg)',
|
|
57
52
|
},
|
|
58
53
|
|
|
59
54
|
disabled: {
|
|
@@ -62,45 +57,15 @@ export const useStyles = createThemedStyles('Select', {
|
|
|
62
57
|
},
|
|
63
58
|
},
|
|
64
59
|
|
|
65
|
-
counter: {
|
|
66
|
-
'&:not(:last-child)': {
|
|
67
|
-
paddingRight: 8,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
icon: {
|
|
72
|
-
width: CONTROL.ICON_INNER_SIZE,
|
|
73
|
-
height: CONTROL.ICON_INNER_SIZE,
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
iconWrapper: {
|
|
77
|
-
display: 'flex',
|
|
78
|
-
alignItems: 'center',
|
|
79
|
-
},
|
|
60
|
+
counter: {},
|
|
80
61
|
});
|
|
81
62
|
|
|
82
63
|
const baseInputStyles: IInputStyles = {
|
|
83
|
-
inputContent: {
|
|
84
|
-
paddingRight: 32,
|
|
85
|
-
},
|
|
86
|
-
|
|
87
64
|
input: {
|
|
88
65
|
'&[readonly]': {
|
|
89
66
|
cursor: 'pointer',
|
|
90
67
|
},
|
|
91
68
|
},
|
|
92
|
-
|
|
93
|
-
tweakControlWrapper: {
|
|
94
|
-
controls: {
|
|
95
|
-
paddingRight: 40,
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
icon: {
|
|
99
|
-
'&:last-child': {
|
|
100
|
-
paddingRight: 0,
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
69
|
};
|
|
105
70
|
|
|
106
71
|
const readonlyInputBaseStyles: IInputStyles = {
|
|
@@ -18,6 +18,7 @@ import clsx from 'clsx';
|
|
|
18
18
|
import { debounce } from 'ts-debounce';
|
|
19
19
|
import {
|
|
20
20
|
createFilter,
|
|
21
|
+
getArray,
|
|
21
22
|
getTestId,
|
|
22
23
|
isNotEmpty,
|
|
23
24
|
isReactNodeNotEmpty,
|
|
@@ -575,16 +576,6 @@ export function Select<Value>(
|
|
|
575
576
|
</div>
|
|
576
577
|
);
|
|
577
578
|
|
|
578
|
-
const multiSelectCounterWithIcon =
|
|
579
|
-
shouldShowMultiSelectCounter || isNotEmpty(icon) ? (
|
|
580
|
-
<div className={classes.iconWrapper}>
|
|
581
|
-
{shouldShowMultiSelectCounter && (
|
|
582
|
-
<div className={classes.counter}>(+{value.length - 1})</div>
|
|
583
|
-
)}
|
|
584
|
-
{isNotEmpty(icon) && <div className={classes.icon}>{renderIcon(icon)}</div>}
|
|
585
|
-
</div>
|
|
586
|
-
) : undefined;
|
|
587
|
-
|
|
588
579
|
return (
|
|
589
580
|
<WithMessages
|
|
590
581
|
errorMessage={errorMessage}
|
|
@@ -612,18 +603,31 @@ export function Select<Value>(
|
|
|
612
603
|
isLoading={areOptionsLoading}
|
|
613
604
|
tweakStyles={tweakInputStyles}
|
|
614
605
|
testId={testId}
|
|
615
|
-
icon={
|
|
606
|
+
icon={[
|
|
607
|
+
isMultiSelect && shouldShowMultiSelectCounter
|
|
608
|
+
? {
|
|
609
|
+
key: 'counter',
|
|
610
|
+
iconComponent: (
|
|
611
|
+
<div key="counter" className={classes.counter}>
|
|
612
|
+
(+{value.length - 1})
|
|
613
|
+
</div>
|
|
614
|
+
),
|
|
615
|
+
shouldResetSize: true,
|
|
616
|
+
}
|
|
617
|
+
: undefined,
|
|
618
|
+
|
|
619
|
+
...getArray(icon),
|
|
620
|
+
|
|
621
|
+
<div
|
|
622
|
+
key="arrow"
|
|
623
|
+
className={clsx(classes.arrow, isOpen && classes.activeArrow)}
|
|
624
|
+
onClick={onArrowClick} // клик тут, потому что onClick в ControlWrapper добавляет tabIndex={0}
|
|
625
|
+
>
|
|
626
|
+
{renderIcon(dropdownIcon)}
|
|
627
|
+
</div>,
|
|
628
|
+
].filter(isNotEmpty)}
|
|
616
629
|
{...inputProps}
|
|
617
630
|
/>
|
|
618
|
-
<div
|
|
619
|
-
onMouseDown={(event: MouseEvent) => {
|
|
620
|
-
event.preventDefault();
|
|
621
|
-
}}
|
|
622
|
-
onClick={onArrowClick}
|
|
623
|
-
className={clsx(classes.arrow, isOpen && classes.activeArrow)}
|
|
624
|
-
>
|
|
625
|
-
{renderIcon(dropdownIcon)}
|
|
626
|
-
</div>
|
|
627
631
|
</div>
|
|
628
632
|
{shouldUsePopper ? (
|
|
629
633
|
<Portal container={shouldRenderInBody ? document.body : inputWrapper.current}>
|