@bitrise/bitkit 13.267.1-alpha.0 → 13.269.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.267.1-alpha.0",
4
+ "version": "13.269.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+ssh://git@github.com/bitrise-io/bitkit.git"
@@ -38,10 +38,10 @@
38
38
  "@floating-ui/react-dom-interactions": "^0.8.1",
39
39
  "@fontsource/figtree": "^5.2.8",
40
40
  "@fontsource/source-code-pro": "^5.2.6",
41
- "framer-motion": "^12.20.4",
41
+ "framer-motion": "^12.23.0",
42
42
  "luxon": "^3.6.1",
43
- "react": "^19.1.0",
44
- "react-dom": "^19.1.0",
43
+ "react": "^18.3.1",
44
+ "react-dom": "^18.3.1",
45
45
  "react-focus-lock": "2.13.6",
46
46
  "react-imask": "^7.6.1",
47
47
  "react-markdown": "^10.1.0"
@@ -51,14 +51,13 @@
51
51
  "react-dom": "^18.2.0"
52
52
  },
53
53
  "devDependencies": {
54
- "@babel/core": "^7.27.7",
55
- "@babel/preset-env": "^7.27.2",
54
+ "@babel/core": "^7.28.0",
55
+ "@babel/preset-env": "^7.28.0",
56
56
  "@babel/preset-react": "^7.27.1",
57
57
  "@babel/preset-typescript": "^7.27.1",
58
58
  "@bitrise/eslint-plugin": "^2.12.0",
59
59
  "@chakra-ui/cli": "^2.5.8",
60
60
  "@google-cloud/storage": "^7.16.0",
61
- "@storybook/addon-docs": "^9.0.15",
62
61
  "@storybook/addon-links": "^9.0.15",
63
62
  "@storybook/addon-webpack5-compiler-swc": "^3.0.0",
64
63
  "@storybook/react-webpack5": "^9.0.15",
@@ -66,17 +65,17 @@
66
65
  "@testing-library/jest-dom": "6.6.3",
67
66
  "@testing-library/react": "16.3.0",
68
67
  "@testing-library/user-event": "^14.6.1",
69
- "@types/jest": "^30.0.0",
68
+ "@types/jest": "^29.5.14",
70
69
  "@types/luxon": "^3.6.2",
71
- "@types/react": "^19.1.8",
72
- "@types/react-dom": "^19.1.6",
70
+ "@types/react": "^18.3.23",
71
+ "@types/react-dom": "^18.3.7",
73
72
  "@typescript-eslint/eslint-plugin": "^7.18.0",
74
73
  "@typescript-eslint/parser": "^7.18.0",
75
74
  "axios": "^1.10.0",
76
75
  "eslint": "^8.57.1",
77
76
  "glob": "^11.0.3",
78
- "jest": "^30.0.3",
79
- "jest-environment-jsdom": "^30.0.2",
77
+ "jest": "^29.7.0",
78
+ "jest-environment-jsdom": "^29.7.0",
80
79
  "jsdom": "26.1.0",
81
80
  "lodash": "^4.17.21",
82
81
  "prettier": "^3.6.2",
@@ -84,7 +83,8 @@
84
83
  "release-it": "^19.0.3",
85
84
  "storybook": "^9.0.15",
86
85
  "ts-jest": "^29.4.0",
87
- "typescript": "^5.8.3"
86
+ "typescript": "^5.8.3",
87
+ "@storybook/addon-docs": "^9.0.15"
88
88
  },
89
89
  "files": [
90
90
  "src",
@@ -1,15 +1,9 @@
1
1
  import React, {
2
- Children,
3
2
  cloneElement,
4
3
  createContext,
5
4
  forwardRef,
6
- ForwardRefExoticComponent,
7
- isValidElement,
8
5
  JSX,
9
6
  ReactNode,
10
- Ref,
11
- RefAttributes,
12
- RefObject,
13
7
  useCallback,
14
8
  useContext,
15
9
  useEffect,
@@ -100,24 +94,23 @@ export { DropdownOption, DropdownGroup, DropdownSearch, NoResultsFound, Dropdown
100
94
 
101
95
  function useOptionListWithIndexes({ children }: { children: ReactNode }) {
102
96
  return useMemo(() => {
103
- const childList = Children.toArray(children);
97
+ const childList = React.Children.toArray(children);
104
98
  let idx = 0;
105
99
  const transform = (ch: ReactNode): ReactNode => {
106
- if (isValidElement(ch)) {
100
+ if (React.isValidElement(ch)) {
107
101
  if (ch.type === DropdownOption || ch.type === DropdownDetailedOption) {
108
102
  const index = idx;
109
103
  idx += 1;
110
104
  return cloneElement(ch, {
111
- ...(ch.props || {}),
105
+ ...ch.props,
112
106
  index,
113
- } as any);
107
+ });
114
108
  }
115
- if ('children' in (ch.props as any)) {
109
+ if ('children' in ch.props) {
116
110
  return cloneElement(ch, {
117
- ...(ch.props || {}),
118
- // Cast to any to allow children property
119
- children: Children.toArray((ch.props as any).children).map(transform),
120
- } as any);
111
+ ...ch.props,
112
+ children: React.Children.toArray(ch.props.children).map(transform),
113
+ });
121
114
  }
122
115
  }
123
116
  return ch;
@@ -127,29 +120,24 @@ function useOptionListWithIndexes({ children }: { children: ReactNode }) {
127
120
  }
128
121
 
129
122
  type UseDropdownProps = {
130
- ref: Ref<Element>;
131
- optionsRef: RefObject<HTMLDivElement | null>;
123
+ ref: React.Ref<Element>;
124
+ optionsRef: React.RefObject<HTMLDivElement>;
132
125
  };
133
126
 
134
127
  function findOption<T>(
135
128
  children: ReactNode,
136
129
  value: T,
137
130
  ): { label: ReactNode; index: number; avatar?: AvatarProps } | null {
138
- const list = Children.toArray(children);
131
+ const list = React.Children.toArray(children);
139
132
  for (let i = 0; i < list.length; i++) {
140
133
  const elem = list[i];
141
- if (isValidElement(elem) && !(elem.props as any).isDisabled) {
142
- const optValue = typeof (elem.props as any).value === 'undefined' ? null : (elem.props as any).value;
134
+ if (React.isValidElement(elem) && !elem.props.isDisabled) {
135
+ const optValue = typeof elem.props.value === 'undefined' ? null : elem.props.value;
143
136
  if (elem.type === DropdownOption && optValue === value) {
144
- return {
145
- index: (elem.props as any).index,
146
- label: (elem.props as any).children,
147
- avatar: (elem.props as any).avatar,
148
- };
137
+ return { index: elem.props.index, label: elem.props.children, avatar: elem.props.avatar };
149
138
  }
150
139
  const ch =
151
- findOption((elem.props as any).children, value) ||
152
- (isSearchable(elem.type) && findOption(elem.type(elem.props), value));
140
+ findOption(elem.props.children, value) || (isSearchable(elem.type) && findOption(elem.type(elem.props), value));
153
141
  if (ch) {
154
142
  return ch;
155
143
  }
@@ -207,7 +195,7 @@ function useDropdown<T>({
207
195
  }
208
196
  }, [activeIndex]);
209
197
  const referenceKeyDown = useCallback(
210
- (ev: React.KeyboardEvent<Element>) => {
198
+ (ev: React.KeyboardEvent) => {
211
199
  if (ev.key === 'Enter') {
212
200
  ev.preventDefault();
213
201
  searchOnSubmit();
@@ -221,7 +209,7 @@ function useDropdown<T>({
221
209
  });
222
210
 
223
211
  // this can just be a ref as it will always be updated when formValue is, which will cause a re-render
224
- const labelMapRef = useRef<Map<T, ReactNode>>(new Map());
212
+ const labelMapRef = useRef<Map<T, ReactNode>>();
225
213
  if (!labelMapRef.current) labelMapRef.current = new Map();
226
214
 
227
215
  // clear map when value is changed from the outside
@@ -420,7 +408,7 @@ const Dropdown = forwardRef<Element, DropdownProps<string | null>>(
420
408
  ) => {
421
409
  const dataAttributes = getDataAttributes(props);
422
410
 
423
- const optionsRef = useRef<HTMLDivElement | null>(null);
411
+ const optionsRef = useRef(null);
424
412
  const {
425
413
  avatar,
426
414
  children,
@@ -566,7 +554,7 @@ const Dropdown = forwardRef<Element, DropdownProps<string | null>>(
566
554
 
567
555
  export function typedDropdown<T>() {
568
556
  return {
569
- Dropdown: Dropdown as ForwardRefExoticComponent<DropdownProps<T> & RefAttributes<Element>>,
557
+ Dropdown: Dropdown as React.ForwardRefExoticComponent<DropdownProps<T> & React.RefAttributes<Element>>,
570
558
  DropdownOption: DropdownOption as (p: DropdownOptionProps<T>) => JSX.Element,
571
559
  };
572
560
  }
@@ -29,7 +29,7 @@ const DropdownOption = <T = string,>({
29
29
  const ctx = useDropdownContext<T | null>();
30
30
  const { index } = rest as { index?: number };
31
31
  const isSelected = !!(
32
- ctx.formValue && (Array.isArray(ctx.formValue) ? ctx.formValue.includes(value) : ctx.formValue === value)
32
+ ctx.formValue !== null && (Array.isArray(ctx.formValue) ? ctx.formValue.includes(value) : ctx.formValue === value)
33
33
  );
34
34
 
35
35
  return (
@@ -7,13 +7,13 @@ const useAutoScroll = ({
7
7
  optionsRef,
8
8
  selectedIndex,
9
9
  }: {
10
- optionsRef: React.RefObject<HTMLDivElement | null>;
10
+ optionsRef: React.RefObject<HTMLDivElement>;
11
11
  listRef: React.MutableRefObject<HTMLElement[]>;
12
12
  activeIndex: number | null;
13
13
  selectedIndex: number | null;
14
14
  keyboardControlled: boolean;
15
15
  }) => {
16
- const prevActiveIndexRef = useRef<number | null>(null);
16
+ const prevActiveIndexRef = useRef<number | null>();
17
17
  useLayoutEffect(() => {
18
18
  prevActiveIndexRef.current = activeIndex;
19
19
  }, [activeIndex]);
@@ -27,7 +27,7 @@ const useFloatingDropdown = ({
27
27
  placement,
28
28
  }: {
29
29
  enabled: boolean;
30
- optionsRef: RefObject<HTMLDivElement | null>;
30
+ optionsRef: RefObject<HTMLDivElement>;
31
31
  dropdownWidth: ChakraProps['width'] | 'match';
32
32
  placement: UseFloatingProps['placement'] | undefined;
33
33
  }) => {
@@ -1,4 +1,4 @@
1
- import { Children, cloneElement, isValidElement, ReactElement, ReactNode, useMemo, useState } from 'react';
1
+ import { Children, cloneElement, isValidElement, ReactNode, useMemo, useState } from 'react';
2
2
  import { chakra } from '@chakra-ui/react';
3
3
  import { useDropdownStyles } from '../Dropdown.context';
4
4
  import isNodeMatch from '../isNodeMatch';
@@ -25,13 +25,12 @@ function useSimpleSearch({ children, onSearch }: { children?: ReactNode; onSearc
25
25
 
26
26
  const transform = (node: ReactNode): ReactNode => {
27
27
  if (isValidElement(node) && node.type === DropdownGroup) {
28
- const element = node as ReactElement<{ children?: ReactNode }>;
29
- const groupChildren = Children.toArray(element.props.children).map(transform).filter(Boolean);
28
+ const groupChildren = Children.toArray(node.props.children).map(transform).filter(Boolean);
30
29
  if (groupChildren.length === 0) {
31
30
  return null;
32
31
  }
33
- return cloneElement(element, {
34
- ...element.props,
32
+ return cloneElement(node, {
33
+ ...node.props,
35
34
  children: groupChildren,
36
35
  });
37
36
  }
@@ -1,4 +1,4 @@
1
- import { isValidElement, JSXElementConstructor, ReactElement, ReactNode } from 'react';
1
+ import React, { JSXElementConstructor, ReactElement, ReactNode } from 'react';
2
2
 
3
3
  type SearchableElement = JSXElementConstructor<any> & { searchable: true };
4
4
  export function isSearchable(
@@ -17,10 +17,10 @@ function isNodeMatch(node: ReactNode, filter: string): boolean {
17
17
  if (Array.isArray(node)) {
18
18
  return Array.from(node).some((child) => isNodeMatch(child, filter));
19
19
  }
20
- if (typeof node === 'object' && node !== null && 'children' in node) {
21
- return isNodeMatch((node as any).children, filter);
20
+ if ('children' in node) {
21
+ return isNodeMatch(node.children, filter);
22
22
  }
23
- if (isValidElement<any>(node)) {
23
+ if (React.isValidElement<any>(node)) {
24
24
  if (node.type === 'svg') {
25
25
  return false;
26
26
  }
@@ -28,18 +28,9 @@ function isNodeMatch(node: ReactNode, filter: string): boolean {
28
28
  if (isSearchable(ctor)) {
29
29
  return isNodeMatch(ctor(node.props), filter);
30
30
  }
31
- if (isValidElement(node)) {
32
- return isNodeMatch((node as ReactElement<any>).props.children, filter);
33
- }
34
- return false;
35
- }
36
- if (
37
- (typeof node === 'object' && node !== null && (Symbol.iterator in node || 'length' in node)) ||
38
- Array.isArray(node)
39
- ) {
40
- return Array.from(node as Iterable<ReactNode> | ArrayLike<ReactNode>).some((child) => isNodeMatch(child, filter));
31
+ return isNodeMatch(node.props.children, filter);
41
32
  }
42
- return false;
33
+ return isNodeMatch(Array.from(node), filter);
43
34
  }
44
35
 
45
36
  export default isNodeMatch;
@@ -252,9 +252,8 @@ const FilterForm = (props: FilterFormProps) => {
252
252
  ))
253
253
  : getEmptyText()}
254
254
  {items.length > MAX_ITEMS && (
255
- <Text textStyle="body/md/regular">
256
- We show only {MAX_ITEMS} items, use the search
257
- <br /> to find more.
255
+ <Text textStyle="body/sm/regular" color="text.secondary" marginBlockStart="4">
256
+ Showing first {MAX_ITEMS} items. Use search to find more.
258
257
  </Text>
259
258
  )}
260
259
  </CheckboxGroup>
@@ -287,9 +286,8 @@ const FilterForm = (props: FilterFormProps) => {
287
286
  })
288
287
  : getEmptyText()}
289
288
  {items.length > MAX_ITEMS && (
290
- <Text textStyle="body/md/regular">
291
- We show only {MAX_ITEMS} items, use the search
292
- <br /> to find more.
289
+ <Text textStyle="body/sm/regular" color="text.secondary" marginBlockStart="4">
290
+ Showing first {MAX_ITEMS} items. Use search to find more.
293
291
  </Text>
294
292
  )}
295
293
  </RadioGroup>
@@ -17,7 +17,7 @@ const TreeViewGroup = ({ label, role, level, indexPath, titlePath, children }: T
17
17
  ? cloneElement(child, {
18
18
  level,
19
19
  indexPath: [...indexPath, childIndex],
20
- titlePath: [...titlePath, (child.props as { title: string }).title],
20
+ titlePath: [...titlePath, child.props.title],
21
21
  } as { level: number; indexPath: number[]; titlePath: string[] })
22
22
  : child,
23
23
  )}