@bitrise/bitkit 13.187.0 → 13.189.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.187.0",
4
+ "version": "13.189.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+ssh://git@github.com/bitrise-io/bitkit.git"
@@ -38,11 +38,11 @@
38
38
  "@floating-ui/react-dom-interactions": "^0.8.1",
39
39
  "@fontsource/figtree": "^5.1.1",
40
40
  "@fontsource/source-code-pro": "^5.1.0",
41
- "framer-motion": "^11.14.2",
41
+ "framer-motion": "^11.15.0",
42
42
  "luxon": "^3.5.0",
43
43
  "react": "^18.3.1",
44
44
  "react-dom": "^18.3.1",
45
- "react-focus-lock": "2.13.2",
45
+ "react-focus-lock": "2.13.5",
46
46
  "react-imask": "^7.6.1",
47
47
  "react-markdown": "^9.0.1"
48
48
  },
@@ -73,7 +73,7 @@
73
73
  "@testing-library/user-event": "^14.5.2",
74
74
  "@types/jest": "^29.5.14",
75
75
  "@types/luxon": "^3.4.2",
76
- "@types/react": "^18.3.16",
76
+ "@types/react": "^18.3.17",
77
77
  "@types/react-dom": "^18.3.5",
78
78
  "@typescript-eslint/eslint-plugin": "^7.18.0",
79
79
  "@typescript-eslint/parser": "^7.18.0",
@@ -1,6 +1,7 @@
1
1
  import { ComponentProps, ReactNode } from 'react';
2
2
  import { createStylesContext } from '@chakra-ui/react';
3
3
  import { createContext } from '@chakra-ui/react-utils';
4
+ import { DropdownProps } from './DropdownProps';
4
5
 
5
6
  const [DropdownStylesProvider, useDropdownStyles] = createStylesContext('Dropdown');
6
7
 
@@ -17,6 +18,7 @@ type DropdownContext<T> = {
17
18
  filter?: string;
18
19
  activeIndex?: number | null;
19
20
  getItemProps: (userProps?: React.HTMLProps<HTMLElement> | undefined) => Record<string, unknown>;
21
+ size: DropdownProps<unknown>['size'];
20
22
  };
21
23
 
22
24
  const [DropdownContextProvider, useDropdownContext] = createContext<DropdownContext<unknown>>();
@@ -4,6 +4,7 @@ import { DropdownProps } from './DropdownProps';
4
4
  type DropdownStateProps = Pick<DropdownProps<string | null>, 'disabled' | 'readOnly' | 'isWarning' | 'isError'> & {
5
5
  placeholder: boolean;
6
6
  isOpen: boolean;
7
+ hasAvatar: boolean;
7
8
  };
8
9
 
9
10
  const getCursor = ({ readOnly, disabled }: DropdownStateProps) => {
@@ -68,7 +69,7 @@ const getButtonContentColor = ({ disabled, placeholder }: DropdownStateProps) =>
68
69
 
69
70
  const DropdownTheme = {
70
71
  baseStyle: (props: DropdownStateProps) => {
71
- const { disabled, readOnly, isError } = props;
72
+ const { disabled, readOnly, hasAvatar, isError } = props;
72
73
  return {
73
74
  field: {
74
75
  _hover:
@@ -128,7 +129,8 @@ const DropdownTheme = {
128
129
  },
129
130
  color: 'purple.10',
130
131
  cursor: 'pointer',
131
- paddingX: '16',
132
+ paddingLeft: hasAvatar ? '12' : '16',
133
+ paddingRight: '24',
132
134
  paddingY: '8',
133
135
  textAlign: 'start',
134
136
  userSelect: 'none',
@@ -151,7 +153,7 @@ const DropdownTheme = {
151
153
  options: {
152
154
  flexShrink: 1,
153
155
  overflowY: 'auto',
154
- paddingY: '12',
156
+ paddingY: '8',
155
157
  position: 'relative',
156
158
  },
157
159
  search: {
@@ -162,22 +164,26 @@ const DropdownTheme = {
162
164
  };
163
165
  },
164
166
  sizes: {
165
- lg: {
167
+ lg: ({ hasAvatar }: DropdownStateProps) => ({
166
168
  field: {
167
169
  fontSize: '3',
168
- gap: '0.625rem',
170
+ gap: rem('8'),
169
171
  height: '48',
170
- paddingLeft: rem('15'),
171
- paddingRight: rem('15'),
172
+ paddingLeft: hasAvatar ? rem('12') : rem('16'),
173
+ paddingRight: rem('16'),
172
174
  },
173
- },
175
+ }),
174
176
  md: {
175
177
  field: {
176
178
  fontSize: '2',
177
- gap: '0.375rem',
179
+ gap: rem('8'),
178
180
  height: '40',
179
- paddingLeft: rem('11'),
180
- paddingRight: rem('11'),
181
+ paddingLeft: rem('12'),
182
+ paddingRight: rem('12'),
183
+ },
184
+ item: {
185
+ fontSize: '2',
186
+ paddingLeft: rem('12'),
181
187
  },
182
188
  },
183
189
  },
@@ -20,6 +20,7 @@ import {
20
20
  import { FloatingFocusManager } from '@floating-ui/react-dom-interactions';
21
21
  import SearchInput from '../SearchInput/SearchInput';
22
22
  import FormLabel from '../Form/FormLabel';
23
+ import { AvatarProps } from '../Avatar/Avatar';
23
24
  import { DropdownEventArgs, DropdownProvider, useDropdownContext, useDropdownStyles } from './Dropdown.context';
24
25
  import { DropdownDetailedOption, DropdownGroup, DropdownOption, DropdownOptionProps } from './DropdownOption';
25
26
  import DropdownButton from './DropdownButton';
@@ -112,14 +113,17 @@ type UseDropdownProps = {
112
113
  optionsRef: React.RefObject<HTMLDivElement>;
113
114
  };
114
115
 
115
- function findOption<T>(children: ReactNode, value: T): { label: ReactNode; index: number } | null {
116
+ function findOption<T>(
117
+ children: ReactNode,
118
+ value: T,
119
+ ): { label: ReactNode; index: number; avatar?: AvatarProps } | null {
116
120
  const list = React.Children.toArray(children);
117
121
  for (let i = 0; i < list.length; i++) {
118
122
  const elem = list[i];
119
123
  if (React.isValidElement(elem) && !elem.props.isDisabled) {
120
124
  const optValue = typeof elem.props.value === 'undefined' ? null : elem.props.value;
121
125
  if (elem.type === DropdownOption && optValue === value) {
122
- return { index: elem.props.index, label: elem.props.children };
126
+ return { index: elem.props.index, label: elem.props.children, avatar: elem.props.avatar };
123
127
  }
124
128
  const ch =
125
129
  findOption(elem.props.children, value) || (isSearchable(elem.type) && findOption(elem.type(elem.props), value));
@@ -141,6 +145,7 @@ function useDropdown<T>({
141
145
  placement = 'bottom-start',
142
146
  readOnly,
143
147
  ref,
148
+ size,
144
149
  value,
145
150
  ...rest
146
151
  }: DropdownProps<T> & UseDropdownProps) {
@@ -162,8 +167,8 @@ function useDropdown<T>({
162
167
  onChange: (newValue) => onChange?.({ target: { name, value: newValue } }),
163
168
  value,
164
169
  });
165
-
166
170
  const [formLabel, setFormLabel] = useState<ReactNode>();
171
+ const [selectedAvatar, setSelectedAvatar] = useState<AvatarProps | undefined>();
167
172
  const refdChildren = useOptionListWithIndexes({ children });
168
173
 
169
174
  const searchOnSubmit = useCallback(() => {
@@ -203,6 +208,7 @@ function useDropdown<T>({
203
208
  searchOnSubmit,
204
209
  searchRef,
205
210
  searchValue,
211
+ size,
206
212
  }),
207
213
  [
208
214
  listRef,
@@ -214,6 +220,7 @@ function useDropdown<T>({
214
220
  searchValue,
215
221
  searchRef,
216
222
  searchOnSubmit,
223
+ size,
217
224
  ],
218
225
  );
219
226
 
@@ -222,12 +229,15 @@ function useDropdown<T>({
222
229
  if (currentOption) {
223
230
  setFormLabel(currentOption.label);
224
231
  setSelectedIndex(currentOption.index);
232
+ setSelectedAvatar(currentOption.avatar);
225
233
  } else {
226
234
  setFormLabel(null);
227
235
  setSelectedIndex(null);
236
+ setSelectedAvatar(undefined);
228
237
  }
229
238
  }, [refdChildren, formValue]);
230
239
  return {
240
+ avatar: selectedAvatar,
231
241
  context,
232
242
  floatingContext,
233
243
  floatingProps,
@@ -283,6 +293,7 @@ const Dropdown = forwardRef<Element, DropdownProps<string | null>>(
283
293
  ) => {
284
294
  const optionsRef = useRef(null);
285
295
  const {
296
+ avatar,
286
297
  children,
287
298
  context: dropdownCtx,
288
299
  floatingContext,
@@ -303,10 +314,12 @@ const Dropdown = forwardRef<Element, DropdownProps<string | null>>(
303
314
  placement,
304
315
  readOnly,
305
316
  ref,
317
+ size,
306
318
  value,
307
319
  ...props,
308
320
  });
309
321
  const dropdownStyles = useMultiStyleConfig('Dropdown', {
322
+ hasAvatar: Boolean(avatar),
310
323
  disabled,
311
324
  isError,
312
325
  isOpen,
@@ -352,6 +365,7 @@ const Dropdown = forwardRef<Element, DropdownProps<string | null>>(
352
365
  {...referenceProps}
353
366
  {...buttonProps}
354
367
  aria-label={ariaLabel}
368
+ avatar={avatar}
355
369
  data-testid={dataTestid}
356
370
  id={buttonId}
357
371
  iconName={iconName}
@@ -1,10 +1,12 @@
1
1
  import { forwardRef, ReactNode } from 'react';
2
2
  import { chakra, ChakraProps } from '@chakra-ui/react';
3
3
  import Icon, { TypeIconName } from '../Icon/Icon';
4
+ import Avatar, { AvatarProps } from '../Avatar/Avatar';
4
5
  import { useDropdownStyles } from './Dropdown.context';
5
6
  import { DropdownProps } from './DropdownProps';
6
7
 
7
8
  interface DropdownButtonProps extends ChakraProps {
9
+ avatar?: AvatarProps | undefined;
8
10
  'aria-label'?: string;
9
11
  blurHandler: () => void;
10
12
  id?: string;
@@ -22,6 +24,7 @@ interface DropdownButtonProps extends ChakraProps {
22
24
  const DropdownButton = forwardRef<HTMLButtonElement, DropdownButtonProps>(
23
25
  (
24
26
  {
27
+ avatar,
25
28
  blurHandler,
26
29
  children,
27
30
  disabled,
@@ -57,6 +60,7 @@ const DropdownButton = forwardRef<HTMLButtonElement, DropdownButtonProps>(
57
60
  type="button"
58
61
  {...rest}
59
62
  >
63
+ {avatar && <Avatar size={size === 'lg' ? '32' : '24'} {...avatar} />}
60
64
  {iconName && <Icon __css={icon} aria-hidden="true" name={iconName} size={iconSize} />}
61
65
  <chakra.span
62
66
  __css={buttonContent}
@@ -1,11 +1,13 @@
1
1
  import { MouseEventHandler, ReactNode, useId } from 'react';
2
- import { chakra } from '@chakra-ui/react';
2
+ import { Avatar, AvatarProps, chakra } from '@chakra-ui/react';
3
3
  import { cx } from '@chakra-ui/utils';
4
4
  import Text, { TextProps } from '../Text/Text';
5
5
  import Divider from '../Divider/Divider';
6
+ import Box from '../Box/Box';
6
7
  import { useDropdownContext, useDropdownStyles } from './Dropdown.context';
7
8
 
8
9
  export type DropdownOptionProps<T> = {
10
+ avatar?: AvatarProps;
9
11
  value?: T | null;
10
12
  children?: ReactNode;
11
13
  'aria-label'?: string;
@@ -13,6 +15,7 @@ export type DropdownOptionProps<T> = {
13
15
  isDisabled?: boolean;
14
16
  };
15
17
  const DropdownOption = <T = string,>({
18
+ avatar,
16
19
  children,
17
20
  isDisabled,
18
21
  onClick,
@@ -22,6 +25,7 @@ const DropdownOption = <T = string,>({
22
25
  const { item } = useDropdownStyles();
23
26
  const ctx = useDropdownContext<T | null>();
24
27
  const { index } = rest as { index?: number };
28
+
25
29
  return (
26
30
  <chakra.div
27
31
  ref={(node) => {
@@ -52,7 +56,14 @@ const DropdownOption = <T = string,>({
52
56
  },
53
57
  )}
54
58
  >
55
- {children}
59
+ {avatar ? (
60
+ <Box display="flex" alignItems="center" gap="8">
61
+ <Avatar size={ctx.size === 'lg' ? '32' : '24'} {...avatar} />
62
+ {children}
63
+ </Box>
64
+ ) : (
65
+ children
66
+ )}
56
67
  </chakra.div>
57
68
  );
58
69
  };