@bitrise/bitkit 13.302.0 → 13.303.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.302.0",
4
+ "version": "13.303.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+ssh://git@github.com/bitrise-io/bitkit.git"
@@ -29,6 +29,7 @@ import { AvatarProps } from '../Avatar/Avatar';
29
29
  import { getDataAttributes } from '../../utils/utils';
30
30
  import Tag from '../Tag/Tag';
31
31
  import Box from '../Box/Box';
32
+ import Text from '../Text/Text';
32
33
  import IconButton from '../IconButton/IconButton';
33
34
  import { DropdownEventArgs, DropdownProvider, useDropdownContext, useDropdownStyles } from './Dropdown.context';
34
35
  import { DropdownDetailedOption, DropdownGroup, DropdownOption, DropdownOptionProps } from './DropdownOption';
@@ -38,7 +39,14 @@ import { NoResultsFound, useSimpleSearch } from './hooks/useSimpleSearch';
38
39
  import { isSearchable } from './isNodeMatch';
39
40
  import { DropdownProps } from './DropdownProps';
40
41
 
41
- const MultiSelectContext = createContext<{ invalidValues?: string[] } | undefined>(undefined);
42
+ const MultiSelectContext = createContext<
43
+ | {
44
+ invalidValues?: string[];
45
+ isConstrained?: boolean;
46
+ itemType?: string;
47
+ }
48
+ | undefined
49
+ >(undefined);
42
50
 
43
51
  type DropdownSearchCustomProps = {
44
52
  value?: string;
@@ -134,7 +142,11 @@ function findOption<T>(
134
142
  if (React.isValidElement(elem) && !elem.props.isDisabled) {
135
143
  const optValue = typeof elem.props.value === 'undefined' ? null : elem.props.value;
136
144
  if (elem.type === DropdownOption && optValue === value) {
137
- return { index: elem.props.index, label: elem.props.children, avatar: elem.props.avatar };
145
+ return {
146
+ index: elem.props.index,
147
+ label: elem.props.children,
148
+ avatar: elem.props.avatar,
149
+ };
138
150
  }
139
151
  const ch =
140
152
  findOption(elem.props.children, value) || (isSearchable(elem.type) && findOption(elem.type(elem.props), value));
@@ -203,7 +215,12 @@ function useDropdown<T>({
203
215
  listRef,
204
216
  setActiveIndex,
205
217
  setSelectedIndex,
206
- } = useFloatingDropdown({ dropdownWidth, enabled: !readOnly, optionsRef, placement });
218
+ } = useFloatingDropdown({
219
+ dropdownWidth,
220
+ enabled: !readOnly,
221
+ optionsRef,
222
+ placement,
223
+ });
207
224
 
208
225
  const multiSelectContext = useContext(MultiSelectContext);
209
226
  const isMultiSelect = Boolean(multiSelectContext);
@@ -304,46 +321,63 @@ function useDropdown<T>({
304
321
  formValue.length > 0 ? (
305
322
  <Box alignItems="center" display="flex" gap={8}>
306
323
  <Box display="flex" flexGrow={1} flexWrap="wrap" gap={8}>
307
- {formValue
308
- ?.sort((a, b) => {
309
- if (typeof a === 'string' && typeof b === 'string') {
310
- return a.localeCompare(b);
311
- }
312
-
313
- if (a === null) {
314
- return -1;
315
- }
316
-
317
- return 1;
318
- })
319
- .map((formValueItem) => {
320
- if (typeof formValueItem !== 'string' && formValueItem !== null) {
321
- return <>{formValueItem}</>;
322
- }
323
-
324
- const colors = multiSelectContext?.invalidValues?.includes(formValueItem) ? 'red' : 'neutral';
325
- return (
326
- <Tag
327
- colorScheme={colors}
328
- isDisabled={disabled}
329
- key={formValueItem}
330
- onClose={(event) => {
331
- event.stopPropagation();
332
-
333
- setFormValue((previous: T) => {
334
- if (!Array.isArray(previous)) {
335
- return previous;
336
- }
337
-
338
- return previous.filter((aPrevious) => aPrevious !== formValueItem) as T;
339
- });
340
- }}
341
- size="sm"
342
- >
343
- {labelCache.get(formValueItem) || fallback?.(formValueItem) || formValueItem}
344
- </Tag>
345
- );
346
- })}
324
+ {multiSelectContext?.isConstrained ? (
325
+ <>
326
+ <Tag
327
+ size="sm"
328
+ colorScheme="neutral"
329
+ onClose={(event) => {
330
+ event.stopPropagation();
331
+ setFormValue([] as T);
332
+ }}
333
+ isDisabled={disabled}
334
+ >
335
+ {formValue.length}
336
+ </Tag>
337
+ <Text>{`${multiSelectContext.itemType} selected`}</Text>
338
+ </>
339
+ ) : (
340
+ formValue
341
+ ?.sort((a, b) => {
342
+ if (typeof a === 'string' && typeof b === 'string') {
343
+ return a.localeCompare(b);
344
+ }
345
+
346
+ if (a === null) {
347
+ return -1;
348
+ }
349
+
350
+ return 1;
351
+ })
352
+ .map((formValueItem) => {
353
+ if (typeof formValueItem !== 'string' && formValueItem !== null) {
354
+ return <>{formValueItem}</>;
355
+ }
356
+
357
+ const colors = multiSelectContext?.invalidValues?.includes(formValueItem) ? 'red' : 'neutral';
358
+ return (
359
+ <Tag
360
+ colorScheme={colors}
361
+ isDisabled={disabled}
362
+ key={formValueItem}
363
+ onClose={(event) => {
364
+ event.stopPropagation();
365
+
366
+ setFormValue((previous: T) => {
367
+ if (!Array.isArray(previous)) {
368
+ return previous;
369
+ }
370
+
371
+ return previous.filter((aPrevious) => aPrevious !== formValueItem) as T;
372
+ });
373
+ }}
374
+ size="sm"
375
+ >
376
+ {labelCache.get(formValueItem) || fallback?.(formValueItem) || formValueItem}
377
+ </Tag>
378
+ );
379
+ })
380
+ )}
347
381
  </Box>
348
382
  <IconButton
349
383
  aria-label="Clear all"
@@ -377,7 +411,7 @@ function useDropdown<T>({
377
411
  setSelectedAvatar(undefined);
378
412
  }
379
413
  }
380
- }, [refdChildren, formValue]);
414
+ }, [refdChildren, formValue, multiSelectContext]);
381
415
  return {
382
416
  avatar: selectedAvatar,
383
417
  context,
@@ -587,11 +621,20 @@ export function typedDropdown<T>() {
587
621
  };
588
622
  }
589
623
 
590
- export const MultiSelectDropdown = (props: DropdownProps<(string | null)[]> & { invalidValues?: string[] }) => {
624
+ export const MultiSelectDropdown = (
625
+ props: DropdownProps<(string | null)[]> & {
626
+ invalidValues?: string[];
627
+ isConstrained?: boolean;
628
+ itemType?: string;
629
+ },
630
+ ) => {
591
631
  const { Dropdown: TypedDropdown } = typedDropdown<(string | null)[]>();
592
632
 
593
- const { children, invalidValues, ...rest } = props;
594
- const contextValue = useMemo(() => ({ invalidValues }), [invalidValues]);
633
+ const { children, invalidValues, isConstrained, itemType, ...rest } = props;
634
+ const contextValue = useMemo(
635
+ () => ({ invalidValues, isConstrained, itemType }),
636
+ [invalidValues, isConstrained, itemType],
637
+ );
595
638
 
596
639
  return (
597
640
  <MultiSelectContext.Provider value={contextValue}>