@qoretechnologies/reqore 0.29.0 → 0.29.1
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/__tests__/checkbox.test.tsx +7 -12
- package/__tests__/multiselect.test.tsx +46 -0
- package/dist/components/Button/index.js +1 -1
- package/dist/components/Button/index.js.map +1 -1
- package/dist/components/Checkbox/index.d.ts +7 -2
- package/dist/components/Checkbox/index.d.ts.map +1 -1
- package/dist/components/Checkbox/index.js +60 -26
- package/dist/components/Checkbox/index.js.map +1 -1
- package/dist/components/Effect/index.d.ts +12 -1
- package/dist/components/Effect/index.d.ts.map +1 -1
- package/dist/components/Effect/index.js +39 -7
- package/dist/components/Effect/index.js.map +1 -1
- package/dist/components/Icon/index.d.ts +2 -9
- package/dist/components/Icon/index.d.ts.map +1 -1
- package/dist/components/Icon/index.js +4 -28
- package/dist/components/Icon/index.js.map +1 -1
- package/dist/components/InternalPopover/index.d.ts.map +1 -1
- package/dist/components/InternalPopover/index.js +16 -2
- package/dist/components/InternalPopover/index.js.map +1 -1
- package/dist/components/MultiSelect/index.d.ts +4 -2
- package/dist/components/MultiSelect/index.d.ts.map +1 -1
- package/dist/components/MultiSelect/index.js +15 -14
- package/dist/components/MultiSelect/index.js.map +1 -1
- package/dist/components/RadioGroup/index.d.ts +3 -1
- package/dist/components/RadioGroup/index.d.ts.map +1 -1
- package/dist/components/RadioGroup/index.js +2 -2
- package/dist/components/RadioGroup/index.js.map +1 -1
- package/dist/components/Tag/index.d.ts +1 -1
- package/dist/components/Tag/index.d.ts.map +1 -1
- package/dist/components/Tag/index.js +17 -14
- package/dist/components/Tag/index.js.map +1 -1
- package/dist/components/Textarea/index.js +3 -3
- package/dist/components/Textarea/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Button/index.tsx +1 -1
- package/src/components/Checkbox/index.tsx +189 -34
- package/src/components/Effect/index.tsx +68 -7
- package/src/components/Icon/index.tsx +4 -52
- package/src/components/InternalPopover/index.tsx +3 -0
- package/src/components/MultiSelect/index.tsx +20 -11
- package/src/components/RadioGroup/index.tsx +6 -0
- package/src/components/Tag/index.tsx +19 -13
- package/src/components/Textarea/index.tsx +3 -3
- package/src/mock/collectionData.tsx +6 -6
- package/src/mock/multiSelect.ts +8 -0
- package/src/stories/Checkbox/Checkbox.stories.tsx +42 -7
- package/src/stories/Icon/Icon.stories.tsx +42 -12
- package/src/stories/Menu/Menu.stories.tsx +2 -1
- package/src/stories/MultiSelect/MultiSelect.stories.tsx +9 -2
- package/src/stories/Popover/Popover.stories.tsx +19 -2
- package/src/stories/RadioGroup/RadioGroup.stories.tsx +51 -1
- package/src/stories/Tag/Tag.stories.tsx +2 -2
- package/src/stories/utils/args.ts +1 -1
- package/tests.json +1 -1
|
@@ -1,27 +1,40 @@
|
|
|
1
1
|
import { rgba } from 'polished';
|
|
2
|
-
import React, { forwardRef } from 'react';
|
|
2
|
+
import React, { forwardRef, useMemo } from 'react';
|
|
3
|
+
import { useMeasure } from 'react-use';
|
|
3
4
|
import styled, { css } from 'styled-components';
|
|
4
5
|
import { PADDING_FROM_SIZE, SIZE_TO_PX, TEXT_FROM_SIZE, TSizes } from '../../constants/sizes';
|
|
5
6
|
import { IReqoreTheme } from '../../constants/theme';
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
changeLightness,
|
|
9
|
+
getNthGradientColor,
|
|
10
|
+
getReadableColor,
|
|
11
|
+
getReadableColorFrom,
|
|
12
|
+
} from '../../helpers/colors';
|
|
13
|
+
import { getOneLessSize } from '../../helpers/utils';
|
|
7
14
|
import { useCombinedRefs } from '../../hooks/useCombinedRefs';
|
|
15
|
+
import { useReqoreTheme } from '../../hooks/useTheme';
|
|
8
16
|
import { useTooltip } from '../../hooks/useTooltip';
|
|
9
17
|
import { DisabledElement, ReadOnlyElement } from '../../styles';
|
|
10
18
|
import {
|
|
11
19
|
IReqoreDisabled,
|
|
20
|
+
IReqoreIntent,
|
|
12
21
|
IReqoreReadOnly,
|
|
22
|
+
IWithReqoreCustomTheme,
|
|
13
23
|
IWithReqoreEffect,
|
|
14
24
|
TReqoreTooltipProp,
|
|
15
25
|
} from '../../types/global';
|
|
16
26
|
import { IReqoreIconName } from '../../types/icons';
|
|
17
|
-
import { ReqoreTextEffect } from '../Effect';
|
|
18
|
-
import ReqoreIcon from '../Icon';
|
|
27
|
+
import { IReqoreEffect, ReqoreTextEffect, StyledEffect, StyledTextEffect } from '../Effect';
|
|
28
|
+
import ReqoreIcon, { StyledIconWrapper } from '../Icon';
|
|
29
|
+
import { ReqoreSpacer } from '../Spacer';
|
|
19
30
|
|
|
20
31
|
export interface IReqoreCheckboxProps
|
|
21
32
|
extends React.HTMLAttributes<HTMLDivElement>,
|
|
22
33
|
IReqoreDisabled,
|
|
23
34
|
IReqoreReadOnly,
|
|
24
|
-
IWithReqoreEffect
|
|
35
|
+
IWithReqoreEffect,
|
|
36
|
+
IReqoreIntent,
|
|
37
|
+
IWithReqoreCustomTheme {
|
|
25
38
|
label?: string;
|
|
26
39
|
labelDetail?: any;
|
|
27
40
|
labelDetailPosition?: 'left' | 'right';
|
|
@@ -35,6 +48,10 @@ export interface IReqoreCheckboxProps
|
|
|
35
48
|
uncheckedIcon?: IReqoreIconName;
|
|
36
49
|
checkedIcon?: IReqoreIconName;
|
|
37
50
|
image?: string;
|
|
51
|
+
onText?: string | number;
|
|
52
|
+
offText?: string | number;
|
|
53
|
+
switchTextEffect?: IReqoreEffect;
|
|
54
|
+
labelEffect?: IReqoreEffect;
|
|
38
55
|
}
|
|
39
56
|
|
|
40
57
|
export interface IReqoreCheckboxStyle extends IReqoreCheckboxProps {
|
|
@@ -48,38 +65,65 @@ const StyledSwitchToggle = styled.div`
|
|
|
48
65
|
align-items: center;
|
|
49
66
|
justify-content: center;
|
|
50
67
|
position: absolute;
|
|
51
|
-
height: ${({ size }) => SIZE_TO_PX[size] -
|
|
52
|
-
width: ${({ size }) => SIZE_TO_PX[size] -
|
|
68
|
+
height: ${({ size }) => SIZE_TO_PX[size] - 4}px;
|
|
69
|
+
width: ${({ size, width }) => width || SIZE_TO_PX[size] - 4}px;
|
|
53
70
|
top: 50%;
|
|
54
71
|
transform: translateY(-50%);
|
|
55
|
-
left: ${({ checked, size }) =>
|
|
56
|
-
!checked ? '
|
|
57
|
-
border-radius:
|
|
58
|
-
background-color: ${({ theme, checked, transparent }) =>
|
|
72
|
+
left: ${({ checked, size, width }) =>
|
|
73
|
+
!checked ? '1px' : `calc(100% - ${width || SIZE_TO_PX[size] - 4}px - 1px)`};
|
|
74
|
+
border-radius: 50px;
|
|
75
|
+
background-color: ${({ theme, checked, transparent, parentEffect }) =>
|
|
59
76
|
transparent
|
|
60
77
|
? 'transparent'
|
|
61
78
|
: !checked
|
|
62
|
-
?
|
|
63
|
-
|
|
79
|
+
? parentEffect?.gradient
|
|
80
|
+
? changeLightness(getNthGradientColor(theme, parentEffect?.gradient?.colors, 1), 0.2)
|
|
81
|
+
: theme.main
|
|
82
|
+
: parentEffect?.gradient
|
|
83
|
+
? changeLightness(getNthGradientColor(theme, parentEffect?.gradient?.colors, 2), 0.2)
|
|
84
|
+
: theme.main};
|
|
64
85
|
`;
|
|
65
86
|
|
|
66
|
-
const StyledSwitch = styled
|
|
87
|
+
const StyledSwitch = styled(StyledEffect)<IReqoreCheckboxStyle>`
|
|
67
88
|
transition: all 0.2s ease-out;
|
|
68
89
|
position: relative;
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
69
93
|
|
|
70
|
-
height: ${({ size }) => SIZE_TO_PX[size]
|
|
71
|
-
width: ${({ size }) => SIZE_TO_PX[size] * 1.8}px;
|
|
94
|
+
height: ${({ size }) => SIZE_TO_PX[size]}px;
|
|
95
|
+
min-width: ${({ size }) => SIZE_TO_PX[size] * 1.8}px;
|
|
72
96
|
|
|
73
|
-
border: 1px solid
|
|
74
|
-
${({ theme, checked }) =>
|
|
75
|
-
rgba(getReadableColor(theme, undefined, undefined), checked ? 0.8 : 0.2)};
|
|
97
|
+
border: 1px solid ${({ theme, checked }) => changeLightness(theme.main, checked ? 0.25 : 0.2)};
|
|
76
98
|
border-radius: 50px;
|
|
77
99
|
|
|
78
100
|
margin-right: ${({ size }) => PADDING_FROM_SIZE[size]}px;
|
|
79
101
|
margin-left: ${({ size }) => PADDING_FROM_SIZE[size]}px;
|
|
80
102
|
|
|
81
103
|
background-color: ${({ theme, checked }) =>
|
|
82
|
-
checked ? rgba(
|
|
104
|
+
checked ? rgba(changeLightness(theme.main, 0.15), 0.5) : 'transparent'};
|
|
105
|
+
|
|
106
|
+
${StyledIconWrapper} {
|
|
107
|
+
z-index: 1;
|
|
108
|
+
}
|
|
109
|
+
`;
|
|
110
|
+
|
|
111
|
+
const StyledSwitchTextWrapper = styled(StyledTextEffect)`
|
|
112
|
+
margin: 0 ${({ size }) => PADDING_FROM_SIZE[size]}px;
|
|
113
|
+
display: flex;
|
|
114
|
+
align-items: center;
|
|
115
|
+
justify-content: center;
|
|
116
|
+
z-index: 1;
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
const StyledOnSwitchText = styled(StyledSwitchTextWrapper)<IReqoreCheckboxStyle>`
|
|
120
|
+
color: ${({ theme, checked }) =>
|
|
121
|
+
getReadableColorFrom(!checked ? theme.originalMain : theme.main)};
|
|
122
|
+
`;
|
|
123
|
+
|
|
124
|
+
const StyledOffSwitchText = styled(StyledSwitchTextWrapper)<IReqoreCheckboxStyle>`
|
|
125
|
+
color: ${({ theme, checked }) =>
|
|
126
|
+
getReadableColorFrom(!checked ? theme.main : changeLightness(theme.main, 0.1))};
|
|
83
127
|
`;
|
|
84
128
|
|
|
85
129
|
const StyledCheckbox = styled.div<IReqoreCheckboxStyle>`
|
|
@@ -106,14 +150,15 @@ const StyledCheckbox = styled.div<IReqoreCheckboxStyle>`
|
|
|
106
150
|
${ReadOnlyElement};
|
|
107
151
|
`}
|
|
108
152
|
|
|
109
|
-
color: ${({ theme, checked }) =>
|
|
153
|
+
color: ${({ theme, checked }) =>
|
|
154
|
+
getReadableColor(theme, undefined, undefined, !checked, theme.originalMain)};
|
|
110
155
|
|
|
111
156
|
&:hover {
|
|
112
|
-
color: ${({ theme }) =>
|
|
157
|
+
color: ${({ theme }) =>
|
|
158
|
+
getReadableColor(theme, undefined, undefined, false, theme.originalMain)};
|
|
113
159
|
|
|
114
160
|
> ${StyledSwitch} {
|
|
115
|
-
border-color: ${({ theme, checked }) =>
|
|
116
|
-
rgba(getReadableColor(theme, undefined, undefined, false), checked ? 0.8 : 0.5)};
|
|
161
|
+
border-color: ${({ theme, checked }) => changeLightness(theme.main, checked ? 0.3 : 0.25)};
|
|
117
162
|
}
|
|
118
163
|
}
|
|
119
164
|
`;
|
|
@@ -131,23 +176,45 @@ const Checkbox = forwardRef<HTMLDivElement, IReqoreCheckboxProps>(
|
|
|
131
176
|
labelPosition = 'right',
|
|
132
177
|
tooltip,
|
|
133
178
|
asSwitch,
|
|
134
|
-
uncheckedIcon
|
|
135
|
-
checkedIcon
|
|
179
|
+
uncheckedIcon,
|
|
180
|
+
checkedIcon,
|
|
136
181
|
readOnly,
|
|
137
|
-
|
|
182
|
+
labelEffect,
|
|
183
|
+
switchTextEffect,
|
|
138
184
|
image,
|
|
185
|
+
onText,
|
|
186
|
+
offText,
|
|
187
|
+
intent,
|
|
188
|
+
effect,
|
|
189
|
+
customTheme,
|
|
139
190
|
...rest
|
|
140
191
|
}: IReqoreCheckboxProps,
|
|
141
192
|
ref
|
|
142
193
|
) => {
|
|
143
194
|
const { targetRef } = useCombinedRefs(ref);
|
|
195
|
+
const [offRef, { width: offWidth }] = useMeasure();
|
|
196
|
+
const [onRef, { width: onWidth }] = useMeasure();
|
|
197
|
+
const theme = useReqoreTheme('main', customTheme, intent);
|
|
144
198
|
|
|
145
199
|
useTooltip(targetRef.current, tooltip);
|
|
146
200
|
|
|
201
|
+
const width = useMemo(() => {
|
|
202
|
+
if ((!image && !onText) || !offText) return undefined;
|
|
203
|
+
|
|
204
|
+
const selectedWidth = checked ? onWidth : offWidth;
|
|
205
|
+
|
|
206
|
+
return selectedWidth + PADDING_FROM_SIZE[size] * 2;
|
|
207
|
+
}, [checked, offWidth, onWidth, size]);
|
|
208
|
+
|
|
209
|
+
const hasText = useMemo(() => {
|
|
210
|
+
return !!onText || !!offText;
|
|
211
|
+
}, [onText, offText]);
|
|
212
|
+
|
|
147
213
|
return (
|
|
148
214
|
<StyledCheckbox
|
|
149
215
|
{...rest}
|
|
150
216
|
ref={targetRef}
|
|
217
|
+
theme={theme}
|
|
151
218
|
size={size}
|
|
152
219
|
disabled={disabled}
|
|
153
220
|
checked={checked}
|
|
@@ -156,9 +223,11 @@ const Checkbox = forwardRef<HTMLDivElement, IReqoreCheckboxProps>(
|
|
|
156
223
|
>
|
|
157
224
|
{label && labelPosition === 'left' ? (
|
|
158
225
|
<>
|
|
226
|
+
<ReqoreSpacer width={PADDING_FROM_SIZE[size]} />
|
|
159
227
|
{labelDetailPosition === 'left' && labelDetail}
|
|
160
228
|
<ReqoreTextEffect
|
|
161
|
-
|
|
229
|
+
active={checked}
|
|
230
|
+
effect={{ ...labelEffect, interactive: !disabled && !readOnly && !checked }}
|
|
162
231
|
>
|
|
163
232
|
{label}
|
|
164
233
|
</ReqoreTextEffect>
|
|
@@ -166,25 +235,111 @@ const Checkbox = forwardRef<HTMLDivElement, IReqoreCheckboxProps>(
|
|
|
166
235
|
</>
|
|
167
236
|
) : null}
|
|
168
237
|
{asSwitch ? (
|
|
169
|
-
<StyledSwitch
|
|
170
|
-
|
|
171
|
-
|
|
238
|
+
<StyledSwitch
|
|
239
|
+
size={size}
|
|
240
|
+
labelPosition={labelPosition}
|
|
241
|
+
checked={checked}
|
|
242
|
+
theme={theme}
|
|
243
|
+
as='div'
|
|
244
|
+
effect={effect}
|
|
245
|
+
>
|
|
246
|
+
<>
|
|
247
|
+
{offText || offText === 0 ? (
|
|
248
|
+
<StyledOffSwitchText
|
|
249
|
+
ref={offRef}
|
|
250
|
+
size={size}
|
|
251
|
+
theme={theme}
|
|
252
|
+
checked={checked}
|
|
253
|
+
effect={
|
|
254
|
+
{
|
|
255
|
+
uppercase: true,
|
|
256
|
+
textSize: getOneLessSize(size),
|
|
257
|
+
weight: 'bold',
|
|
258
|
+
...switchTextEffect,
|
|
259
|
+
opacity: checked ? 0.8 : 1,
|
|
260
|
+
} as IReqoreEffect
|
|
261
|
+
}
|
|
262
|
+
>
|
|
263
|
+
{image || uncheckedIcon ? (
|
|
264
|
+
<ReqoreIcon
|
|
265
|
+
size={size}
|
|
266
|
+
image={image}
|
|
267
|
+
icon={uncheckedIcon}
|
|
268
|
+
effect={{ grayscale: true }}
|
|
269
|
+
margin={offText ? 'right' : undefined}
|
|
270
|
+
/>
|
|
271
|
+
) : null}
|
|
272
|
+
{offText}
|
|
273
|
+
</StyledOffSwitchText>
|
|
274
|
+
) : null}
|
|
275
|
+
{onText || onText === 0 ? (
|
|
276
|
+
<StyledOnSwitchText
|
|
277
|
+
ref={onRef}
|
|
278
|
+
size={size}
|
|
279
|
+
theme={theme}
|
|
280
|
+
checked={checked}
|
|
281
|
+
effect={
|
|
282
|
+
{
|
|
283
|
+
uppercase: true,
|
|
284
|
+
textSize: getOneLessSize(size),
|
|
285
|
+
weight: 'thick',
|
|
286
|
+
...switchTextEffect,
|
|
287
|
+
opacity: checked ? 1 : 0.5,
|
|
288
|
+
} as IReqoreEffect
|
|
289
|
+
}
|
|
290
|
+
>
|
|
291
|
+
{image || checkedIcon ? (
|
|
292
|
+
<ReqoreIcon
|
|
293
|
+
size={size}
|
|
294
|
+
image={image}
|
|
295
|
+
margin={onText ? 'right' : undefined}
|
|
296
|
+
icon={checkedIcon}
|
|
297
|
+
/>
|
|
298
|
+
) : null}
|
|
299
|
+
{onText}
|
|
300
|
+
</StyledOnSwitchText>
|
|
301
|
+
) : null}
|
|
302
|
+
</>
|
|
303
|
+
<StyledSwitchToggle
|
|
304
|
+
size={size}
|
|
305
|
+
checked={checked}
|
|
306
|
+
width={width}
|
|
307
|
+
theme={theme}
|
|
308
|
+
parentEffect={effect}
|
|
309
|
+
transparent={(image || checkedIcon) && !hasText}
|
|
310
|
+
>
|
|
311
|
+
{!onText && !offText ? (
|
|
312
|
+
<ReqoreIcon
|
|
313
|
+
size={size}
|
|
314
|
+
image={image}
|
|
315
|
+
icon={checked ? checkedIcon : uncheckedIcon}
|
|
316
|
+
effect={{ grayscale: !checked, opacity: checked ? 1 : 0.5 }}
|
|
317
|
+
/>
|
|
318
|
+
) : null}
|
|
172
319
|
</StyledSwitchToggle>
|
|
173
320
|
</StyledSwitch>
|
|
174
321
|
) : (
|
|
175
322
|
<ReqoreIcon
|
|
176
323
|
size={size}
|
|
177
|
-
icon={
|
|
324
|
+
icon={
|
|
325
|
+
!image
|
|
326
|
+
? checked
|
|
327
|
+
? checkedIcon || 'CheckboxCircleFill'
|
|
328
|
+
: uncheckedIcon || 'CheckboxBlankCircleLine'
|
|
329
|
+
: undefined
|
|
330
|
+
}
|
|
178
331
|
image={image}
|
|
179
|
-
|
|
332
|
+
effect={{ grayscale: image ? !checked : undefined, opacity: checked ? 1 : 0.5 }}
|
|
180
333
|
margin='both'
|
|
334
|
+
intent={intent}
|
|
181
335
|
/>
|
|
182
336
|
)}
|
|
183
337
|
{label && labelPosition === 'right' ? (
|
|
184
338
|
<>
|
|
185
339
|
{labelDetailPosition === 'left' && labelDetail}
|
|
186
340
|
<ReqoreTextEffect
|
|
187
|
-
|
|
341
|
+
active={checked}
|
|
342
|
+
effect={{ ...labelEffect, interactive: !disabled && !readOnly && !checked }}
|
|
188
343
|
>
|
|
189
344
|
{label}
|
|
190
345
|
</ReqoreTextEffect>
|
|
@@ -30,7 +30,18 @@ export type TReqoreEffectColorList = [
|
|
|
30
30
|
TReqoreEffectColorManipulationMultiplier | undefined
|
|
31
31
|
];
|
|
32
32
|
|
|
33
|
-
export interface
|
|
33
|
+
export interface IReqoreEffectFilters {
|
|
34
|
+
grayscale?: boolean;
|
|
35
|
+
blur?: number;
|
|
36
|
+
sepia?: boolean;
|
|
37
|
+
invert?: boolean;
|
|
38
|
+
opacity?: number;
|
|
39
|
+
brightness?: number;
|
|
40
|
+
contrast?: number;
|
|
41
|
+
saturate?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface IReqoreEffect extends IReqoreEffectFilters {
|
|
34
45
|
gradient?: {
|
|
35
46
|
type?: 'linear' | 'radial';
|
|
36
47
|
shape?: 'circle' | 'ellipse';
|
|
@@ -63,13 +74,14 @@ export interface IReqoreTextEffectProps
|
|
|
63
74
|
as?: React.ElementType;
|
|
64
75
|
theme?: IReqoreTheme;
|
|
65
76
|
active?: boolean;
|
|
77
|
+
isText?: boolean;
|
|
66
78
|
}
|
|
67
79
|
|
|
68
80
|
export const StyledEffect = styled.span`
|
|
69
81
|
transition: all 0.2s ease-in-out;
|
|
70
82
|
|
|
71
83
|
// If gradient was supplied
|
|
72
|
-
${({ effect, theme, minimal, active }: IReqoreTextEffectProps) => {
|
|
84
|
+
${({ effect, theme, minimal, active, isText }: IReqoreTextEffectProps) => {
|
|
73
85
|
if (!effect || !effect.gradient) {
|
|
74
86
|
return undefined;
|
|
75
87
|
}
|
|
@@ -79,7 +91,7 @@ export const StyledEffect = styled.span`
|
|
|
79
91
|
theme,
|
|
80
92
|
effect.gradient.colors,
|
|
81
93
|
0,
|
|
82
|
-
minimal && !active
|
|
94
|
+
!isText && minimal && !active
|
|
83
95
|
);
|
|
84
96
|
const gradientColorsActive = createEffectGradient(theme, effect.gradient.colors, 0.05);
|
|
85
97
|
|
|
@@ -107,7 +119,7 @@ export const StyledEffect = styled.span`
|
|
|
107
119
|
getColorFromMaybeString(theme, effect.gradient.borderColor),
|
|
108
120
|
0.15
|
|
109
121
|
)}`;
|
|
110
|
-
} else {
|
|
122
|
+
} else if (!isText) {
|
|
111
123
|
// We will use border-image and create a gradient border
|
|
112
124
|
borderColor = 'transparent';
|
|
113
125
|
borderHoverColor = 'transparent';
|
|
@@ -231,16 +243,65 @@ export const StyledEffect = styled.span`
|
|
|
231
243
|
text-align: ${effect.textAlign};
|
|
232
244
|
`
|
|
233
245
|
: undefined}
|
|
246
|
+
|
|
247
|
+
${({ effect }) =>
|
|
248
|
+
effect &&
|
|
249
|
+
effect.grayscale &&
|
|
250
|
+
css`
|
|
251
|
+
filter: grayscale(100%);
|
|
252
|
+
`};
|
|
253
|
+
${({ effect }) =>
|
|
254
|
+
effect &&
|
|
255
|
+
effect.blur &&
|
|
256
|
+
css`
|
|
257
|
+
filter: blur(${effect.blur}px);
|
|
258
|
+
`};
|
|
259
|
+
${({ effect }) =>
|
|
260
|
+
effect &&
|
|
261
|
+
effect.sepia &&
|
|
262
|
+
css`
|
|
263
|
+
filter: sepia(100%);
|
|
264
|
+
`};
|
|
265
|
+
${({ effect }) =>
|
|
266
|
+
effect &&
|
|
267
|
+
effect.invert &&
|
|
268
|
+
css`
|
|
269
|
+
filter: invert(100%);
|
|
270
|
+
`};
|
|
271
|
+
${({ effect }) =>
|
|
272
|
+
effect && (effect.opacity || effect.opacity === 0)
|
|
273
|
+
? css`
|
|
274
|
+
opacity: ${effect.opacity};
|
|
275
|
+
`
|
|
276
|
+
: undefined};
|
|
277
|
+
${({ effect }) =>
|
|
278
|
+
effect &&
|
|
279
|
+
effect.brightness &&
|
|
280
|
+
css`
|
|
281
|
+
filter: brightness(${effect.brightness}%);
|
|
282
|
+
`};
|
|
283
|
+
${({ effect }) =>
|
|
284
|
+
effect &&
|
|
285
|
+
effect.contrast &&
|
|
286
|
+
css`
|
|
287
|
+
filter: contrast(${effect.contrast}%);
|
|
288
|
+
`};
|
|
289
|
+
${({ effect }) =>
|
|
290
|
+
effect &&
|
|
291
|
+
effect.saturate &&
|
|
292
|
+
css`
|
|
293
|
+
filter: saturate(${effect.saturate}%);
|
|
294
|
+
`};
|
|
234
295
|
`;
|
|
235
296
|
|
|
236
|
-
export const StyledTextEffect = styled(StyledEffect)`
|
|
297
|
+
export const StyledTextEffect = styled(StyledEffect).attrs((props) => ({ ...props, isText: true }))`
|
|
237
298
|
display: inline-block;
|
|
238
299
|
|
|
239
300
|
${({ effect }: IReqoreTextEffectProps) =>
|
|
240
301
|
effect && effect.gradient
|
|
241
302
|
? css`
|
|
242
|
-
-webkit-background-clip: text;
|
|
243
|
-
-webkit-text-fill-color: transparent;
|
|
303
|
+
-webkit-background-clip: text !important;
|
|
304
|
+
-webkit-text-fill-color: transparent !important;
|
|
244
305
|
`
|
|
245
306
|
: undefined}
|
|
246
307
|
`;
|
|
@@ -7,9 +7,11 @@ import { ReqoreThemeContext } from '../..';
|
|
|
7
7
|
import { ICON_FROM_SIZE, PADDING_FROM_SIZE, TSizes } from '../../constants/sizes';
|
|
8
8
|
import { TReqoreIntent } from '../../constants/theme';
|
|
9
9
|
import { isStringSize } from '../../helpers/utils';
|
|
10
|
+
import { IWithReqoreEffect } from '../../types/global';
|
|
10
11
|
import { IReqoreIconName } from '../../types/icons';
|
|
12
|
+
import { StyledEffect } from '../Effect';
|
|
11
13
|
|
|
12
|
-
export interface IReqoreIconProps extends React.HTMLAttributes<HTMLSpanElement
|
|
14
|
+
export interface IReqoreIconProps extends React.HTMLAttributes<HTMLSpanElement>, IWithReqoreEffect {
|
|
13
15
|
icon?: IReqoreIconName;
|
|
14
16
|
color?: string;
|
|
15
17
|
size?: TSizes | string;
|
|
@@ -18,17 +20,9 @@ export interface IReqoreIconProps extends React.HTMLAttributes<HTMLSpanElement>
|
|
|
18
20
|
margin?: 'right' | 'left' | 'both';
|
|
19
21
|
image?: string;
|
|
20
22
|
rounded?: boolean;
|
|
21
|
-
grayscale?: boolean;
|
|
22
|
-
blur?: number;
|
|
23
|
-
sepia?: boolean;
|
|
24
|
-
invert?: boolean;
|
|
25
|
-
opacity?: number;
|
|
26
|
-
brightness?: number;
|
|
27
|
-
contrast?: number;
|
|
28
|
-
saturate?: number;
|
|
29
23
|
}
|
|
30
24
|
|
|
31
|
-
export const StyledIconWrapper = styled
|
|
25
|
+
export const StyledIconWrapper = styled(StyledEffect)<{ margin: 'right' | 'left' | 'both' }>`
|
|
32
26
|
display: inline-block;
|
|
33
27
|
flex: 0 0 auto;
|
|
34
28
|
vertical-align: text-bottom;
|
|
@@ -37,48 +31,6 @@ export const StyledIconWrapper = styled.span<{ margin: 'right' | 'left' | 'both'
|
|
|
37
31
|
|
|
38
32
|
border-radius: ${({ rounded }) => (rounded ? '50%' : undefined)};
|
|
39
33
|
|
|
40
|
-
${({ grayscale }) =>
|
|
41
|
-
grayscale &&
|
|
42
|
-
css`
|
|
43
|
-
filter: grayscale(100%);
|
|
44
|
-
`};
|
|
45
|
-
${({ blur }) =>
|
|
46
|
-
blur &&
|
|
47
|
-
css`
|
|
48
|
-
filter: blur(${blur}px);
|
|
49
|
-
`};
|
|
50
|
-
${({ sepia }) =>
|
|
51
|
-
sepia &&
|
|
52
|
-
css`
|
|
53
|
-
filter: sepia(100%);
|
|
54
|
-
`};
|
|
55
|
-
${({ invert }) =>
|
|
56
|
-
invert &&
|
|
57
|
-
css`
|
|
58
|
-
filter: invert(100%);
|
|
59
|
-
`};
|
|
60
|
-
${({ opacity }) =>
|
|
61
|
-
opacity || opacity === 0
|
|
62
|
-
? css`
|
|
63
|
-
opacity: ${opacity};
|
|
64
|
-
`
|
|
65
|
-
: undefined};
|
|
66
|
-
${({ brightness }) =>
|
|
67
|
-
brightness &&
|
|
68
|
-
css`
|
|
69
|
-
filter: brightness(${brightness}%);
|
|
70
|
-
`};
|
|
71
|
-
${({ contrast }) =>
|
|
72
|
-
contrast &&
|
|
73
|
-
css`
|
|
74
|
-
filter: contrast(${contrast}%);
|
|
75
|
-
`};
|
|
76
|
-
${({ saturate }) =>
|
|
77
|
-
saturate &&
|
|
78
|
-
css`
|
|
79
|
-
filter: saturate(${saturate}%);
|
|
80
|
-
`};
|
|
81
|
-
|
|
82
34
|
${({ margin, size }) =>
|
|
83
35
|
margin &&
|
|
84
36
|
css`
|
|
@@ -62,6 +62,8 @@ const StyledPopoverWrapper = styled.div<{ theme: IReqoreTheme }>`
|
|
|
62
62
|
max-height: ${({ maxHeight = '80vh' }) => maxHeight};
|
|
63
63
|
z-index: 999999;
|
|
64
64
|
border-radius: ${RADIUS_FROM_SIZE.normal}px;
|
|
65
|
+
border: ${({ flat, isString, ...rest }: any) =>
|
|
66
|
+
!flat && !isString ? `1px solid ${getPopoverArrowColor({ ...rest, flat })}` : undefined};
|
|
65
67
|
|
|
66
68
|
${({ transparent }) =>
|
|
67
69
|
!transparent &&
|
|
@@ -217,6 +219,7 @@ const InternalPopover: React.FC<IReqoreInternalPopoverProps> = ({
|
|
|
217
219
|
isOpaque={!transparent && !minimal}
|
|
218
220
|
intent={intent}
|
|
219
221
|
flat={flat}
|
|
222
|
+
isString={isString(content)}
|
|
220
223
|
dim={flat && !transparent && !effect && minimal}
|
|
221
224
|
className='reqore-popover-content'
|
|
222
225
|
ref={(el) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { size } from 'lodash';
|
|
1
|
+
import { omit, size } from 'lodash';
|
|
2
2
|
import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { useUpdateEffect } from 'react-use';
|
|
4
4
|
import { ReqoreDropdown, ReqoreInput } from '../..';
|
|
@@ -13,7 +13,7 @@ import ReqoreTag, { IReqoreTagProps } from '../Tag';
|
|
|
13
13
|
import ReqoreTagGroup from '../Tag/group';
|
|
14
14
|
|
|
15
15
|
export type TReqoreMultiSelectItem = Omit<IReqoreDropdownItem, 'color'> &
|
|
16
|
-
Pick<IReqoreTagProps, '
|
|
16
|
+
Pick<IReqoreTagProps, 'asBadge' | 'rightIcon' | 'actions'> & { isNew?: boolean };
|
|
17
17
|
|
|
18
18
|
export interface IReqoreMultiSelectProps
|
|
19
19
|
extends Omit<IReqoreControlGroupProps, 'children' | 'vertical' | 'stack'> {
|
|
@@ -21,6 +21,7 @@ export interface IReqoreMultiSelectProps
|
|
|
21
21
|
onValueChange?: (value: string[]) => void;
|
|
22
22
|
items?: TReqoreMultiSelectItem[];
|
|
23
23
|
onItemClick?: (item: IReqoreDropdownItem) => void;
|
|
24
|
+
onItemClickIcon?: IReqoreTagProps['rightIcon'];
|
|
24
25
|
canRemoveItems?: boolean;
|
|
25
26
|
canCreateItems?: boolean;
|
|
26
27
|
selectedItemEffect?: IReqoreEffect;
|
|
@@ -35,6 +36,7 @@ export interface IReqoreMultiSelectItemProps
|
|
|
35
36
|
item: TReqoreMultiSelectItem;
|
|
36
37
|
onClick?: () => void;
|
|
37
38
|
onRemoveClick?: () => void;
|
|
39
|
+
onItemClickIcon?: IReqoreTagProps['rightIcon'];
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export const ReqoreMultiSelectItem = memo(
|
|
@@ -44,6 +46,7 @@ export const ReqoreMultiSelectItem = memo(
|
|
|
44
46
|
onClick,
|
|
45
47
|
selectedItemEffect,
|
|
46
48
|
selectedItemSize,
|
|
49
|
+
onItemClickIcon,
|
|
47
50
|
}: IReqoreMultiSelectItemProps) => {
|
|
48
51
|
if (!item) {
|
|
49
52
|
return null;
|
|
@@ -58,6 +61,7 @@ export const ReqoreMultiSelectItem = memo(
|
|
|
58
61
|
effect={!item.intent ? item.effect || selectedItemEffect : undefined}
|
|
59
62
|
size={selectedItemSize}
|
|
60
63
|
onClick={onClick}
|
|
64
|
+
rightIcon={item.rightIcon || item.disabled ? undefined : onItemClickIcon}
|
|
61
65
|
/>
|
|
62
66
|
);
|
|
63
67
|
}
|
|
@@ -77,6 +81,7 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
77
81
|
selectorProps,
|
|
78
82
|
openOnMount,
|
|
79
83
|
enterKeySelects,
|
|
84
|
+
onItemClickIcon,
|
|
80
85
|
...rest
|
|
81
86
|
}: IReqoreMultiSelectProps,
|
|
82
87
|
ref
|
|
@@ -85,6 +90,7 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
85
90
|
const [createdItems, setCreatedItems] = useState<TReqoreMultiSelectItem[]>([]);
|
|
86
91
|
const [query, setQuery] = useState<string>('');
|
|
87
92
|
const popoverData = useRef<IPopoverControls>(undefined);
|
|
93
|
+
const [focused, setFocused] = useState<boolean>(false);
|
|
88
94
|
|
|
89
95
|
useUpdateEffect(() => {
|
|
90
96
|
onValueChange?.(_value);
|
|
@@ -140,11 +146,11 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
140
146
|
);
|
|
141
147
|
|
|
142
148
|
/*
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
This code creates a list of all items that are available
|
|
150
|
+
for selection in the dropdown. It will include the items
|
|
151
|
+
that are passed in as props, as well as any items that the
|
|
152
|
+
user has created.
|
|
153
|
+
*/
|
|
148
154
|
const allItems: TReqoreMultiSelectItem[] = useMemo(() => {
|
|
149
155
|
const customItems: TReqoreMultiSelectItem[] = size(createdItems)
|
|
150
156
|
? [{ divider: true, label: 'Custom Items' }, ...createdItems]
|
|
@@ -161,7 +167,7 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
161
167
|
|
|
162
168
|
// Mark selected items as selected
|
|
163
169
|
filteredItems = filteredItems.map((item: TReqoreMultiSelectItem) => ({
|
|
164
|
-
...item,
|
|
170
|
+
...omit(item, ['actions', 'asBadge', 'rightIcon']),
|
|
165
171
|
selected: _value.includes(item.value),
|
|
166
172
|
}));
|
|
167
173
|
|
|
@@ -205,12 +211,12 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
205
211
|
|
|
206
212
|
const handleKeyDown = useCallback(
|
|
207
213
|
(e: KeyboardEvent) => {
|
|
208
|
-
if (e.key === 'Enter') {
|
|
214
|
+
if (e.key === 'Enter' && focused) {
|
|
209
215
|
const item = [...items, ...createdItems].find((item) => item.value === query);
|
|
210
216
|
|
|
211
217
|
if (item) {
|
|
212
218
|
handleItemSelect(item);
|
|
213
|
-
} else if (canCreateItems) {
|
|
219
|
+
} else if (canCreateItems && query) {
|
|
214
220
|
handleItemSelect({
|
|
215
221
|
value: query,
|
|
216
222
|
isNew: true,
|
|
@@ -218,7 +224,7 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
218
224
|
}
|
|
219
225
|
}
|
|
220
226
|
},
|
|
221
|
-
[items, createdItems, query, canCreateItems]
|
|
227
|
+
[items, createdItems, query, canCreateItems, focused]
|
|
222
228
|
);
|
|
223
229
|
|
|
224
230
|
const getItemByValue = useCallback(
|
|
@@ -236,6 +242,7 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
236
242
|
<ReqoreMultiSelectItem
|
|
237
243
|
key={v}
|
|
238
244
|
item={getItemByValue(v)}
|
|
245
|
+
onItemClickIcon={onItemClickIcon}
|
|
239
246
|
onRemoveClick={canRemoveItems ? () => addRemoveItem(getItemByValue(v)) : undefined}
|
|
240
247
|
onClick={
|
|
241
248
|
onItemClick
|
|
@@ -257,6 +264,8 @@ export const ReqoreMultiSelect = forwardRef<HTMLDivElement, IReqoreMultiSelectPr
|
|
|
257
264
|
{...selectorProps}
|
|
258
265
|
multiSelect
|
|
259
266
|
handler='focus'
|
|
267
|
+
onFocus={() => setFocused(true)}
|
|
268
|
+
onBlur={() => setFocused(false)}
|
|
260
269
|
passPopoverData={(data) => (popoverData.current = data)}
|
|
261
270
|
component={ReqoreInput}
|
|
262
271
|
onClearClick={() => setQuery('')}
|