@bitrise/bitkit 13.245.0 → 13.247.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bitrise/bitkit",
3
3
  "description": "Bitrise React component library",
4
- "version": "13.245.0",
4
+ "version": "13.247.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+ssh://git@github.com/bitrise-io/bitkit.git"
@@ -24,7 +24,7 @@ const Breadcrumb = forwardRef<BreadcrumbProps, 'nav'>((props, ref) => {
24
24
 
25
25
  const childArray = Children.toArray(children);
26
26
  const childrenCount = childArray.length;
27
- const items = childArray.map((child, index) => {
27
+ const items = Children.map(childArray, (child, index) => {
28
28
  return (
29
29
  <BreadcrumbItem>
30
30
  {hasSeparatorBeforeFirst && index === 0 && <BreadcrumbSeparator marginLeft="0" />}
@@ -41,6 +41,7 @@ export const FILTER_STORY_DATA: FilterData = {
41
41
  branch: {
42
42
  categoryName: 'Branch',
43
43
  categoryNamePlural: 'Branches',
44
+ isMultiple: true,
44
45
  isPatternEnabled: true,
45
46
  options: ['default 1', 'default 2', 'default 3', 'default 13'],
46
47
  type: 'tag',
@@ -28,6 +28,7 @@ export type FilterCategoryProps = {
28
28
  options?: FilterOptions;
29
29
  optionsMap?: FilterOptionsMap;
30
30
  isPatternEnabled?: boolean;
31
+ loadingText?: string;
31
32
  } & (
32
33
  | {
33
34
  type: 'dateRange';
@@ -74,6 +74,7 @@ const FilterAdd = (props: FilterAddProps) => {
74
74
  category={selectedCategory}
75
75
  categoryName={data[selectedCategory].categoryName}
76
76
  categoryNamePlural={data[selectedCategory].categoryNamePlural}
77
+ loadingText={data[selectedCategory].loadingText}
77
78
  onCancel={onClose}
78
79
  onChange={onFilterChange}
79
80
  />
@@ -11,6 +11,7 @@ import Icon from '../../Icon/Icon';
11
11
  import Input from '../../Form/Input/Input';
12
12
  import List from '../../List/List';
13
13
  import ListItem from '../../List/ListItem';
14
+ import ProgressSpinner from '../../ProgressSpinner/ProgressSpinner';
14
15
  import Radio from '../../Form/Radio/Radio';
15
16
  import RadioGroup from '../../Form/Radio/RadioGroup';
16
17
  import SearchInput from '../../SearchInput/SearchInput';
@@ -29,36 +30,55 @@ function regExpEscape(s: string) {
29
30
  return s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
30
31
  }
31
32
 
32
- const getMatchingResults = (categoryNamePlural: string, selected: FilterValue, items: FilterOptions) => {
33
- if (!selected.length || selected[0] === '') {
34
- return (
35
- <Text textStyle="body/md/regular" color="text/secondary">
36
- Enter pattern to view {categoryNamePlural} with matching names.
37
- </Text>
38
- );
39
- }
33
+ type MatchingResultsProps = {
34
+ categoryNamePlural: string;
35
+ selected: FilterValue;
36
+ items: FilterOptions;
37
+ };
40
38
 
41
- const filterRegexp = new RegExp(`^${selected[0].split(/\*+/).map(regExpEscape).join('.*')}$`);
39
+ const MatchingResults = (props: MatchingResultsProps) => {
40
+ const { categoryNamePlural, selected, items } = props;
42
41
 
43
- const matchingResults = items.filter((item) => {
44
- return filterRegexp.test(item) && item !== selected[0];
45
- });
46
- if (!matchingResults.length) {
47
- return (
42
+ let content;
43
+ let matchingResults: FilterOptions = [];
44
+ if (!selected.length || selected[0] === '') {
45
+ content = (
48
46
  <Text textStyle="body/md/regular" color="text/secondary">
49
- (no matching {categoryNamePlural})
47
+ Enter pattern to view {categoryNamePlural} with matching names.
50
48
  </Text>
51
49
  );
50
+ } else {
51
+ const filterRegexp = new RegExp(`^${selected[0].split(/\*+/).map(regExpEscape).join('.*')}$`);
52
+ matchingResults = items.filter((item) => {
53
+ return filterRegexp.test(item);
54
+ });
55
+ if (!matchingResults.length) {
56
+ content = (
57
+ <Text textStyle="body/md/regular" color="text/secondary">
58
+ (no matching {categoryNamePlural})
59
+ </Text>
60
+ );
61
+ } else {
62
+ content = (
63
+ <Box maxHeight="11rem" overflow="scroll">
64
+ <List textStyle="body/md/regular" variant="unordered">
65
+ {matchingResults.map((r) => (
66
+ <ListItem key={r}>{r}</ListItem>
67
+ ))}
68
+ </List>
69
+ </Box>
70
+ );
71
+ }
52
72
  }
53
73
 
54
74
  return (
55
- <Box maxHeight="11rem" overflow="scroll">
56
- <List textStyle="body/md/regular" variant="unordered">
57
- {matchingResults.map((r) => (
58
- <ListItem key={r}>{r}</ListItem>
59
- ))}
60
- </List>
61
- </Box>
75
+ <>
76
+ <Text as="label" textStyle="comp/input/label" color="text/primary" display="block" marginBlockEnd="8">
77
+ Matching result{matchingResults.length > 1 ? 's' : ''}{' '}
78
+ {matchingResults.length ? `(${matchingResults.length})` : ''}
79
+ </Text>
80
+ {content}
81
+ </>
62
82
  );
63
83
  };
64
84
 
@@ -66,12 +86,13 @@ export type FilterFormProps = {
66
86
  category: string;
67
87
  categoryName?: string;
68
88
  categoryNamePlural?: string;
89
+ loadingText?: string;
69
90
  onChange: (category: string, selected: FilterValue, previousValue: FilterValue) => void;
70
91
  onCancel: () => void;
71
92
  };
72
93
 
73
94
  const FilterForm = (props: FilterFormProps) => {
74
- const { category, categoryName, categoryNamePlural, onCancel, onChange } = props;
95
+ const { category, categoryName, categoryNamePlural, loadingText, onCancel, onChange } = props;
75
96
 
76
97
  const filterStyle = useMultiStyleConfig('Filter') as FilterStyle;
77
98
 
@@ -190,7 +211,7 @@ const FilterForm = (props: FilterFormProps) => {
190
211
  <Text as="h5" sx={filterStyle.formTitle}>
191
212
  {categoryName || category}
192
213
  </Text>
193
- {isMultiple && (
214
+ {isMultiple && mode === 'manually' && (
194
215
  <Badge variant="subtle" colorScheme="neutral" sx={filterStyle.formBadge}>
195
216
  {selected[0] === '' ? '0' : String(selected.length)}
196
217
  </Badge>
@@ -208,7 +229,12 @@ const FilterForm = (props: FilterFormProps) => {
208
229
  value={searchValue}
209
230
  />
210
231
  )}
211
- {isLoading && 'Loading...'}
232
+ {isLoading && (
233
+ <Box display="flex" alignItems="center">
234
+ <ProgressSpinner color="sys/primary/base" marginRight="12" size="16" />
235
+ <Text color="text/secondary">{loadingText || 'Loading...'}</Text>
236
+ </Box>
237
+ )}
212
238
  {!isLoading && isMultiple && (
213
239
  <CheckboxGroup onChange={setSelected} sx={filterStyle.formInputGroup} value={selected}>
214
240
  {items.length
@@ -263,17 +289,17 @@ const FilterForm = (props: FilterFormProps) => {
263
289
  onChange={(e) => setSelected([e.target.value])}
264
290
  value={selected[0] || ''}
265
291
  />
266
- <Text as="label" textStyle="comp/input/label" color="text/primary" display="block" marginBlockEnd="8">
267
- Matching results
268
- </Text>
269
- {getMatchingResults((categoryNamePlural || category).toLowerCase(), selected, items)}
292
+ <MatchingResults categoryNamePlural={categoryNamePlural || category} items={items} selected={selected} />
270
293
  </>
271
294
  )}
272
295
  <ButtonGroup spacing="12" sx={filterStyle.formButtonGroup}>
273
296
  {isPatternEnabled && !isEditMode && (
274
297
  <Button
275
298
  marginInlineEnd="auto"
276
- onClick={() => setMode(mode === 'manually' ? 'pattern' : 'manually')}
299
+ onClick={() => {
300
+ setMode(mode === 'manually' ? 'pattern' : 'manually');
301
+ setSelected([]);
302
+ }}
277
303
  size="sm"
278
304
  variant="tertiary"
279
305
  >
@@ -23,7 +23,7 @@ const FilterItem = (props: FilterItemProps) => {
23
23
 
24
24
  const { data, isLoading, onFilterChange, onFilterClear, setPopoverOpen, state } = useFilterContext();
25
25
 
26
- const { categoryName, categoryNamePlural, optionsMap, type, unfilteredLabel } = data[category];
26
+ const { categoryName, categoryNamePlural, loadingText, optionsMap, type, unfilteredLabel } = data[category];
27
27
 
28
28
  const value = state[category];
29
29
 
@@ -102,6 +102,7 @@ const FilterItem = (props: FilterItemProps) => {
102
102
  category={category}
103
103
  categoryName={categoryName}
104
104
  categoryNamePlural={pluralCategoryString}
105
+ loadingText={loadingText}
105
106
  onCancel={onClose}
106
107
  onChange={onChange}
107
108
  />