@bitrise/bitkit 12.92.0 → 12.93.1-alpha.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.
- package/package.json +1 -1
- package/src/Components/Form/ChipInput/ChipInput.theme.ts +19 -0
- package/src/Components/Form/ChipInput/ChipInput.tsx +142 -0
- package/src/Components/Form/DateInput/DateInput.tsx +10 -2
- package/src/Components/Icons/16x16/ErrorCircleFilled.tsx +14 -0
- package/src/Components/Icons/16x16/index.ts +1 -0
- package/src/Components/Icons/24x24/ErrorCircleFilled.tsx +14 -0
- package/src/Components/Icons/24x24/index.ts +1 -0
- package/src/Components/Icons/utils.ts +3 -12
- package/src/Foundations/Icons/figmaIcons.ts +1 -1
- package/src/index.ts +3 -0
- package/src/theme.ts +2 -0
package/package.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineStyleConfig } from '@chakra-ui/styled-system';
|
|
2
|
+
|
|
3
|
+
const ChipInput = defineStyleConfig({
|
|
4
|
+
baseStyle: {
|
|
5
|
+
':has(:focus-visible)': { boxShadow: 'outline' },
|
|
6
|
+
appearance: 'none',
|
|
7
|
+
background: 'neutral.100',
|
|
8
|
+
border: '1px solid',
|
|
9
|
+
borderColor: 'neutral.90',
|
|
10
|
+
borderRadius: '4',
|
|
11
|
+
boxShadow: 'inner',
|
|
12
|
+
outline: 0,
|
|
13
|
+
padding: '0.6875rem',
|
|
14
|
+
transition: '200ms',
|
|
15
|
+
width: '100%',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export default ChipInput;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { ClipboardEventHandler, KeyboardEventHandler, ReactNode, useId } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
chakra,
|
|
4
|
+
FormControl,
|
|
5
|
+
FormControlProps,
|
|
6
|
+
FormErrorMessage,
|
|
7
|
+
FormHelperText,
|
|
8
|
+
FormLabel,
|
|
9
|
+
useStyleConfig,
|
|
10
|
+
} from '@chakra-ui/react';
|
|
11
|
+
import Icon from '../../Icon/Icon';
|
|
12
|
+
import Box from '../../Box/Box';
|
|
13
|
+
import Tag from '../../Tag/Tag';
|
|
14
|
+
import Text from '../../Text/Text';
|
|
15
|
+
|
|
16
|
+
type UsedFormControlProps = Omit<FormControlProps, 'label' | 'onBlur' | 'onChange'>;
|
|
17
|
+
export interface ChipInputProps extends UsedFormControlProps {
|
|
18
|
+
label?: string;
|
|
19
|
+
placeholder?: string;
|
|
20
|
+
value: string[];
|
|
21
|
+
onChange: (nv: string[]) => void;
|
|
22
|
+
separator?: RegExp;
|
|
23
|
+
maxCount?: number;
|
|
24
|
+
invalidValues?: string[];
|
|
25
|
+
errorText?: ReactNode;
|
|
26
|
+
helperText?: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ChipInput = ({
|
|
30
|
+
errorText,
|
|
31
|
+
helperText,
|
|
32
|
+
invalidValues = [],
|
|
33
|
+
label,
|
|
34
|
+
maxCount,
|
|
35
|
+
onChange,
|
|
36
|
+
placeholder,
|
|
37
|
+
separator = /[, ]/,
|
|
38
|
+
value,
|
|
39
|
+
...rest
|
|
40
|
+
}: ChipInputProps) => {
|
|
41
|
+
const theme = useStyleConfig('ChipInput');
|
|
42
|
+
const keyupHandler: KeyboardEventHandler<HTMLInputElement> = (ev) => {
|
|
43
|
+
const target = ev.currentTarget;
|
|
44
|
+
if (ev.key.match(separator)) {
|
|
45
|
+
ev.preventDefault();
|
|
46
|
+
if (target.value) {
|
|
47
|
+
const newValue = target.value.split(separator)[0];
|
|
48
|
+
if (!value.includes(newValue)) {
|
|
49
|
+
onChange([...value, newValue]);
|
|
50
|
+
}
|
|
51
|
+
target.value = '';
|
|
52
|
+
}
|
|
53
|
+
} else if (ev.key === 'Backspace' && target.value.length === 0) {
|
|
54
|
+
onChange(value.slice(0, -1));
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const pasteEventHandler: ClipboardEventHandler<HTMLInputElement> = (ev) => {
|
|
58
|
+
ev.preventDefault();
|
|
59
|
+
const newItems = ev.clipboardData
|
|
60
|
+
.getData('text/plain')
|
|
61
|
+
.split(separator)
|
|
62
|
+
.filter((item) => item && !item.match(/\s/) && !value.includes(item));
|
|
63
|
+
onChange([...value, ...newItems]);
|
|
64
|
+
};
|
|
65
|
+
const removeItem = (deleted: string) => {
|
|
66
|
+
onChange(value.filter((val) => val !== deleted));
|
|
67
|
+
};
|
|
68
|
+
const isInvalid = rest.isInvalid || (maxCount && value.length > maxCount) || Boolean(errorText);
|
|
69
|
+
const id = useId();
|
|
70
|
+
return (
|
|
71
|
+
<FormControl {...rest} isInvalid={isInvalid}>
|
|
72
|
+
<Box alignItems="center" display={label || maxCount ? 'flex' : 'none'} gap="4" marginBlockEnd="4">
|
|
73
|
+
{label && (
|
|
74
|
+
<FormLabel
|
|
75
|
+
htmlFor={id}
|
|
76
|
+
optionalIndicator={
|
|
77
|
+
<Text as="span" color="neutral.40" fontSize="2" fontWeight="normal" marginLeft="4px">
|
|
78
|
+
(Optional)
|
|
79
|
+
</Text>
|
|
80
|
+
}
|
|
81
|
+
requiredIndicator={false}
|
|
82
|
+
>
|
|
83
|
+
{label}
|
|
84
|
+
</FormLabel>
|
|
85
|
+
)}
|
|
86
|
+
|
|
87
|
+
{maxCount && (
|
|
88
|
+
<Text
|
|
89
|
+
as="span"
|
|
90
|
+
color="neutral.40"
|
|
91
|
+
marginInlineStart="auto"
|
|
92
|
+
size="2"
|
|
93
|
+
sx={{ fontVariantNumeric: 'tabular-nums' }}
|
|
94
|
+
>
|
|
95
|
+
{value.length}/{maxCount}
|
|
96
|
+
</Text>
|
|
97
|
+
)}
|
|
98
|
+
</Box>
|
|
99
|
+
<Box
|
|
100
|
+
__css={theme}
|
|
101
|
+
display="flex"
|
|
102
|
+
flexDirection="row"
|
|
103
|
+
flexWrap="wrap"
|
|
104
|
+
gap="4"
|
|
105
|
+
paddingRight={isInvalid ? '42px' : undefined}
|
|
106
|
+
>
|
|
107
|
+
{value.map((item, idx) => (
|
|
108
|
+
<Tag
|
|
109
|
+
key={item}
|
|
110
|
+
colorScheme={invalidValues.includes(item) || (maxCount && idx > maxCount - 1) ? 'red' : undefined}
|
|
111
|
+
onClose={() => removeItem(item)}
|
|
112
|
+
size="sm"
|
|
113
|
+
>
|
|
114
|
+
{item}
|
|
115
|
+
</Tag>
|
|
116
|
+
))}
|
|
117
|
+
{value.length === 0 && placeholder && (
|
|
118
|
+
<Text
|
|
119
|
+
color="sys.fg.subtle"
|
|
120
|
+
pointerEvents="none"
|
|
121
|
+
position="absolute"
|
|
122
|
+
sx={{ ':has(+ :focus-visible)': { display: 'none' } }}
|
|
123
|
+
>
|
|
124
|
+
{placeholder}
|
|
125
|
+
</Text>
|
|
126
|
+
)}
|
|
127
|
+
<chakra.input
|
|
128
|
+
_focusVisible={{ boxShadow: 'none' }}
|
|
129
|
+
flexGrow="1"
|
|
130
|
+
id={id}
|
|
131
|
+
onKeyDown={keyupHandler}
|
|
132
|
+
onPaste={pasteEventHandler}
|
|
133
|
+
/>
|
|
134
|
+
{isInvalid && <Icon color="icon.negative" name="ErrorCircleFilled" position="absolute" right="2rem" />}
|
|
135
|
+
</Box>
|
|
136
|
+
{errorText && <FormErrorMessage as="p">{errorText}</FormErrorMessage>}
|
|
137
|
+
{helperText && <FormHelperText as="p">{helperText}</FormHelperText>}
|
|
138
|
+
</FormControl>
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export default ChipInput;
|
|
@@ -16,6 +16,8 @@ export type DateInputProps = Omit<InputProps, 'value' | 'onChange' | 'placeholde
|
|
|
16
16
|
const DateInput = forwardRef<DateInputProps, 'div'>((props, ref) => {
|
|
17
17
|
const { inputRef, onCalendarClick, onChange, value, ...rest } = props;
|
|
18
18
|
const [isDatePickerVisible, setIsDatePickerVisible] = useState(false);
|
|
19
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
20
|
+
const [isEmpty, setIsEmpty] = useState(true);
|
|
19
21
|
|
|
20
22
|
const dateFormat = 'MM/dd/yyyy';
|
|
21
23
|
|
|
@@ -48,7 +50,7 @@ const DateInput = forwardRef<DateInputProps, 'div'>((props, ref) => {
|
|
|
48
50
|
},
|
|
49
51
|
},
|
|
50
52
|
format: (date: Date | null) => (date ? DateTime.fromJSDate(date).toFormat(dateFormat) : ''),
|
|
51
|
-
lazy:
|
|
53
|
+
lazy: !isFocused && isEmpty,
|
|
52
54
|
mask: Date,
|
|
53
55
|
parse: (str: string) => {
|
|
54
56
|
try {
|
|
@@ -60,7 +62,10 @@ const DateInput = forwardRef<DateInputProps, 'div'>((props, ref) => {
|
|
|
60
62
|
pattern: 'LL/dd/yyyy',
|
|
61
63
|
},
|
|
62
64
|
{
|
|
63
|
-
onAccept: (val) =>
|
|
65
|
+
onAccept: (val, maskRef) => {
|
|
66
|
+
onChange?.(val);
|
|
67
|
+
setIsEmpty(!maskRef.unmaskedValue);
|
|
68
|
+
},
|
|
64
69
|
},
|
|
65
70
|
);
|
|
66
71
|
|
|
@@ -89,6 +94,9 @@ const DateInput = forwardRef<DateInputProps, 'div'>((props, ref) => {
|
|
|
89
94
|
{...rest}
|
|
90
95
|
ref={ref}
|
|
91
96
|
inputRef={innerRef}
|
|
97
|
+
onBlur={() => setIsFocused(false)}
|
|
98
|
+
onFocus={() => setIsFocused(true)}
|
|
99
|
+
placeholder={dateFormat.toLocaleLowerCase()}
|
|
92
100
|
rightAddon={
|
|
93
101
|
<IconButton
|
|
94
102
|
_active={{ background: 'transparent' }}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { forwardRef, Icon, IconProps } from '@chakra-ui/react';
|
|
2
|
+
|
|
3
|
+
const ErrorCircleFilled = forwardRef<IconProps, 'svg'>((props, ref) => (
|
|
4
|
+
<Icon ref={ref} viewBox="0 0 16 16" {...props}>
|
|
5
|
+
<path
|
|
6
|
+
clipRule="evenodd"
|
|
7
|
+
d="M8 15C11.866 15 15 11.866 15 8C15 4.13401 11.866 1 8 1C4.13401 1 1 4.13401 1 8C1 11.866 4.13401 15 8 15ZM7.25 9V4H8.75V9H7.25ZM7.25 12V10.5H8.75V12H7.25Z"
|
|
8
|
+
fill="currentColor"
|
|
9
|
+
fillRule="evenodd"
|
|
10
|
+
/>
|
|
11
|
+
</Icon>
|
|
12
|
+
));
|
|
13
|
+
|
|
14
|
+
export default ErrorCircleFilled;
|
|
@@ -224,3 +224,4 @@ export { default as Workflow } from './Workflow';
|
|
|
224
224
|
export { default as Wow } from './Wow';
|
|
225
225
|
export { default as WrappedLines } from './WrappedLines';
|
|
226
226
|
export { default as Xamarin } from './Xamarin';
|
|
227
|
+
export { default as ErrorCircleFilled } from './ErrorCircleFilled';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { forwardRef, Icon, IconProps } from '@chakra-ui/react';
|
|
2
|
+
|
|
3
|
+
const ErrorCircleFilled = forwardRef<IconProps, 'svg'>((props, ref) => (
|
|
4
|
+
<Icon ref={ref} viewBox="0 0 24 24" {...props}>
|
|
5
|
+
<path
|
|
6
|
+
clipRule="evenodd"
|
|
7
|
+
d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM11 13.5V6.5H13V13.5H11ZM11 17.5V15.5H13V17.5H11Z"
|
|
8
|
+
fill="currentColor"
|
|
9
|
+
fillRule="evenodd"
|
|
10
|
+
/>
|
|
11
|
+
</Icon>
|
|
12
|
+
));
|
|
13
|
+
|
|
14
|
+
export default ErrorCircleFilled;
|
|
@@ -224,3 +224,4 @@ export { default as Workflow } from './Workflow';
|
|
|
224
224
|
export { default as Wow } from './Wow';
|
|
225
225
|
export { default as WrappedLines } from './WrappedLines';
|
|
226
226
|
export { default as Xamarin } from './Xamarin';
|
|
227
|
+
export { default as ErrorCircleFilled } from './ErrorCircleFilled';
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
let uniqueId = 0;
|
|
4
|
-
const getUniqueId = () => {
|
|
5
|
-
uniqueId += 1;
|
|
6
|
-
return uniqueId;
|
|
7
|
-
};
|
|
1
|
+
import { useId } from 'react';
|
|
8
2
|
|
|
9
3
|
export function useIconId() {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
idRef.current = getUniqueId();
|
|
13
|
-
}
|
|
14
|
-
return `iconRender${idRef.current}`;
|
|
4
|
+
const id = useId();
|
|
5
|
+
return `iconRender${id}`;
|
|
15
6
|
}
|
|
@@ -217,7 +217,7 @@ export const figmaIcons: {
|
|
|
217
217
|
{ figmaToken: 'check-circle', iconName: 'BuildstatusSuccessful', tags: 'success' },
|
|
218
218
|
{ figmaToken: 'check-circle-filled', iconName: 'BuildstatusSuccessfulSolid', tags: 'success' },
|
|
219
219
|
{ figmaToken: 'error-circle', iconName: 'StepstatusWarning' },
|
|
220
|
-
{ figmaToken: 'error-circle-filled', iconName: '' },
|
|
220
|
+
{ figmaToken: 'error-circle-filled', iconName: 'ErrorCircleFilled' },
|
|
221
221
|
{ figmaToken: 'info-circle', iconName: '', tags: 'tooltip' },
|
|
222
222
|
{ figmaToken: 'info-circle-filled', iconName: '' },
|
|
223
223
|
{ figmaToken: 'warning', iconName: 'Warning' },
|
package/src/index.ts
CHANGED
|
@@ -333,3 +333,6 @@ export * from './Components/Filter/Filter.types';
|
|
|
333
333
|
|
|
334
334
|
export type { DateInputProps } from './Components/Form/DateInput/DateInput';
|
|
335
335
|
export { default as DateInput } from './Components/Form/DateInput/DateInput';
|
|
336
|
+
|
|
337
|
+
export type { ChipInputProps } from './Components/Form/ChipInput/ChipInput';
|
|
338
|
+
export { default as ChipInput } from './Components/Form/ChipInput/ChipInput';
|
package/src/theme.ts
CHANGED
|
@@ -54,6 +54,7 @@ import zIndices from './Foundations/Zindex/Zindex';
|
|
|
54
54
|
import Toggletip from './Components/Toggletip/Toggletip.theme';
|
|
55
55
|
import FilterSwitch from './Components/Filter/FilterSwitch/FilterSwitch.theme';
|
|
56
56
|
import { colors, semanticTokens } from './tokens/tokens';
|
|
57
|
+
import ChipInput from './Components/Form/ChipInput/ChipInput.theme';
|
|
57
58
|
|
|
58
59
|
const theme = {
|
|
59
60
|
breakpoints,
|
|
@@ -78,6 +79,7 @@ const theme = {
|
|
|
78
79
|
FilterSwitch,
|
|
79
80
|
...Form,
|
|
80
81
|
Alert,
|
|
82
|
+
ChipInput,
|
|
81
83
|
CloseButton,
|
|
82
84
|
CodeBlock,
|
|
83
85
|
CodeSnippet,
|