ferns-ui 1.2.4 → 1.4.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/dist/Common.d.ts CHANGED
@@ -443,11 +443,17 @@ export interface IconProps {
443
443
  }
444
444
  export type TooltipPosition = "top" | "bottom" | "left" | "right";
445
445
  export type IndicatorDirection = "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
446
+ export type SegmentedControlBadgeConfig = {
447
+ count: number;
448
+ status?: "info" | "error" | "warning" | "success" | "neutral";
449
+ };
446
450
  export interface SegmentedControlProps {
447
451
  items: string[];
448
452
  size?: "md" | "lg";
449
453
  onChange: (activeIndex: number) => void;
450
454
  selectedIndex?: number;
455
+ maxItems?: number;
456
+ badges?: SegmentedControlBadgeConfig[];
451
457
  }
452
458
  export interface TimezonePickerProps {
453
459
  timezone?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AAuXA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;CACP,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,WAAW,CAAC,OAAyB,CAAC,CAAC;AAChD,CAAC;AAqBD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAe,EAAE,EAAE;IAClD,OAAO;QACL,EAAE,EAAE,CAAC;QACL,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,KAAK,EAAE,EAAE;KACV,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAClB,CAAC,CAAC;AAiRF,MAAM,YAAY,GAAG;IACnB,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,GAAG;IACZ,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,QAAkB;IAC5C,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"Common.js","sourceRoot":"","sources":["../src/Common.ts"],"names":[],"mappings":"AAuXA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,CAAC,EAAE,EAAE;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;CACP,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAqB;IAC9C,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,OAAO,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAmB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,WAAW,CAAC,OAAyB,CAAC,CAAC;AAChD,CAAC;AAqBD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAe,EAAE,EAAE;IAClD,OAAO;QACL,EAAE,EAAE,CAAC;QACL,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,EAAE,EAAE,EAAE;QACN,KAAK,EAAE,EAAE;KACV,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAClB,CAAC,CAAC;AAwRF,MAAM,YAAY,GAAG;IACnB,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,GAAG;IACZ,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,CAAC;IACL,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE;IACN,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,QAAkB;IAC5C,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
2
  import { SegmentedControlProps } from "./Common";
3
- export declare const SegmentedControl: ({ items, onChange, size, selectedIndex, }: SegmentedControlProps) => React.JSX.Element;
3
+ export declare const SegmentedControl: React.FC<SegmentedControlProps>;
@@ -1,37 +1,72 @@
1
- import React from "react";
1
+ import React, { useCallback, useState } from "react";
2
2
  import { Pressable, View } from "react-native";
3
+ import { Badge } from "./Badge";
3
4
  import { Heading } from "./Heading";
5
+ import { Icon } from "./Icon";
4
6
  import { useTheme } from "./Theme";
5
- export const SegmentedControl = ({ items, onChange = () => { }, size = "md", selectedIndex, }) => {
7
+ export const SegmentedControl = ({ items, onChange = () => { }, size = "md", selectedIndex, maxItems, badges = [], }) => {
6
8
  const height = size === "md" ? 36 : 44;
7
9
  const { theme } = useTheme();
10
+ const [startIndex, setStartIndex] = useState(0);
11
+ const handlePrevious = useCallback(() => {
12
+ setStartIndex((prev) => Math.max(0, prev - (maxItems !== null && maxItems !== void 0 ? maxItems : 4)));
13
+ }, []);
14
+ const handleNext = useCallback(() => {
15
+ setStartIndex((prev) => Math.min(items.length - (maxItems !== null && maxItems !== void 0 ? maxItems : items.length), prev + (maxItems !== null && maxItems !== void 0 ? maxItems : 4)));
16
+ }, [items.length, maxItems]);
17
+ const visibleItems = maxItems ? items.slice(startIndex, startIndex + maxItems) : items;
18
+ const visibleBadges = maxItems ? badges.slice(startIndex, startIndex + maxItems) : badges;
19
+ const canScrollLeft = startIndex > 0;
20
+ const canScrollRight = maxItems ? startIndex + maxItems < items.length : false;
21
+ const shouldShowScrollButtons = maxItems ? maxItems < items.length : false;
8
22
  return (React.createElement(View, { style: {
9
23
  display: "flex",
10
- flexGrow: 1,
11
24
  flexDirection: "row",
12
- flexShrink: 1,
13
25
  alignItems: "center",
14
- gap: 4,
15
- height,
16
- maxHeight: height,
17
- borderRadius: theme.primitives.radius3xl,
18
- borderColor: theme.primitives.neutral300,
19
- borderWidth: 3,
20
- backgroundColor: theme.primitives.neutral300,
21
- } }, items.map((item, index) => (React.createElement(Pressable, { key: index, "aria-role": "button", style: {
22
- display: "flex",
23
- paddingHorizontal: size === "md" ? theme.spacing.sm : theme.spacing.md,
24
- justifyContent: "center",
25
- alignItems: "center",
26
- height: "100%",
27
- flexBasis: 0,
28
- gap: 12,
29
- flexGrow: 1,
30
- flexShrink: 0,
31
- borderRadius: theme.primitives.radius3xl,
32
- backgroundColor: index === selectedIndex ? theme.surface.base : undefined,
33
- overflow: "hidden",
34
- }, onPress: () => onChange(index) },
35
- React.createElement(Heading, { size: "sm" }, item))))));
26
+ gap: 8,
27
+ } },
28
+ Boolean(shouldShowScrollButtons) && (React.createElement(Pressable, { disabled: !canScrollLeft, onPress: handlePrevious },
29
+ React.createElement(Icon, { color: canScrollLeft ? "linkLight" : "extraLight", iconName: "chevron-left", size: "lg" }))),
30
+ React.createElement(View, { style: {
31
+ display: "flex",
32
+ flexGrow: 1,
33
+ flexDirection: "row",
34
+ flexShrink: 1,
35
+ alignItems: "center",
36
+ height,
37
+ maxHeight: height,
38
+ backgroundColor: theme.primitives.neutral300,
39
+ overflow: "hidden",
40
+ borderRadius: theme.primitives.radius3xl,
41
+ } },
42
+ React.createElement(View, { style: {
43
+ display: "flex",
44
+ flexDirection: "row",
45
+ gap: 4,
46
+ flexGrow: 1,
47
+ paddingHorizontal: 4,
48
+ height: height - 4,
49
+ } }, visibleItems.map((item, index) => {
50
+ var _a;
51
+ const actualIndex = startIndex + index;
52
+ return (React.createElement(Pressable, { key: actualIndex, "aria-role": "button", style: {
53
+ display: "flex",
54
+ paddingHorizontal: 2,
55
+ justifyContent: "center",
56
+ alignItems: "center",
57
+ height: "100%",
58
+ flexDirection: "row",
59
+ gap: 8,
60
+ flexGrow: 1,
61
+ flexBasis: 0,
62
+ borderRadius: theme.primitives.radius3xl,
63
+ backgroundColor: actualIndex === selectedIndex ? theme.surface.base : undefined,
64
+ overflow: "hidden",
65
+ }, onPress: () => onChange(actualIndex) },
66
+ React.createElement(Heading, { size: "sm" }, item),
67
+ visibleBadges[index] && (React.createElement(Badge, { status: (_a = visibleBadges[index].status) !== null && _a !== void 0 ? _a : "info", value: visibleBadges[index].count, variant: "numberOnly" }))));
68
+ }))),
69
+ Boolean(shouldShowScrollButtons) && (React.createElement(Pressable, { disabled: !canScrollRight, onPress: handleNext },
70
+ React.createElement(Icon, { color: canScrollRight ? "linkLight" : "extraLight", iconName: "chevron-right", size: "lg" })))));
36
71
  };
37
72
  //# sourceMappingURL=SegmentedControl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../src/SegmentedControl.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,SAAS,EAAE,IAAI,EAAC,MAAM,cAAc,CAAC;AAG7C,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,OAAO,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AAEjC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,EAC/B,KAAK,EACL,QAAQ,GAAG,GAAG,EAAE,GAAE,CAAC,EACnB,IAAI,GAAG,IAAI,EACX,aAAa,GACS,EAAE,EAAE;IAC1B,MAAM,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvC,MAAM,EAAC,KAAK,EAAC,GAAG,QAAQ,EAAE,CAAC;IAC3B,OAAO,CACL,oBAAC,IAAI,IACH,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,QAAQ,EAAE,CAAC;YACX,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,CAAC;YACb,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;YACN,MAAM;YACN,SAAS,EAAE,MAAM;YACjB,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;YACxC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;YACxC,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;SAC7C,IAEA,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,oBAAC,SAAS,IACR,GAAG,EAAE,KAAK,eACA,QAAQ,EAClB,KAAK,EAAE;YACL,OAAO,EAAE,MAAM;YACf,iBAAiB,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;YACtE,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,MAAM,EAAE,MAAM;YACd,SAAS,EAAE,CAAC;YACZ,GAAG,EAAE,EAAE;YACP,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,CAAC;YACb,YAAY,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;YACxC,eAAe,EAAE,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YACzE,QAAQ,EAAE,QAAQ;SACnB,EACD,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;QAE9B,oBAAC,OAAO,IAAC,IAAI,EAAC,IAAI,IAAE,IAAI,CAAW,CACzB,CACb,CAAC,CACG,CACR,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"SegmentedControl.js","sourceRoot":"","sources":["../src/SegmentedControl.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ferns-ui",
3
- "version": "1.2.4",
3
+ "version": "1.4.0",
4
4
  "main": "dist/index.js",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
@@ -85,38 +85,38 @@
85
85
  ],
86
86
  "devDependencies": {
87
87
  "@expo/config-plugins": "~8.0.0",
88
- "@types/jest": "^29.5.12",
89
- "@types/lodash": "^4.17.0",
88
+ "@types/jest": "^29.5.14",
89
+ "@types/lodash": "^4.17.14",
90
90
  "@types/luxon": "^3.4.2",
91
91
  "@types/mdurl": "^2.0.0",
92
- "@types/react": "~18.2.45",
92
+ "@types/react": "~18.3.12",
93
93
  "@types/react-datetime-picker": "^5.0.0",
94
94
  "@types/react-signature-canvas": "^1.0.5",
95
95
  "@types/react-time-picker": "^6.0.0",
96
- "@typescript-eslint/eslint-plugin": "^8.2.0",
97
- "@typescript-eslint/parser": "^8.2.0",
96
+ "@typescript-eslint/eslint-plugin": "^8.19.0",
97
+ "@typescript-eslint/parser": "^8.19.0",
98
98
  "babel-jest": "^29.7.0",
99
99
  "babel-preset-react-app": "^10.0.1",
100
100
  "eslint": "^8.57.0",
101
101
  "eslint-config-prettier": "^9.1.0",
102
- "eslint-plugin-ban": "^1.6.0",
103
- "eslint-plugin-comment-length": "^1.7.3",
102
+ "eslint-plugin-ban": "^2.0.0",
103
+ "eslint-plugin-comment-length": "^2.1.1",
104
104
  "eslint-plugin-ferns": "^0.3.0",
105
- "eslint-plugin-import": "^2.29.1",
106
- "eslint-plugin-lodash": "^7.1.0",
107
- "eslint-plugin-prettier": "^5.1.3",
108
- "eslint-plugin-react": "^7.34.1",
109
- "eslint-plugin-react-hooks": "^4.6.2",
110
- "eslint-plugin-react-native": "^4.1.0",
105
+ "eslint-plugin-import": "^2.31.0",
106
+ "eslint-plugin-lodash": "^8.0.0",
107
+ "eslint-plugin-prettier": "^5.2.1",
108
+ "eslint-plugin-react": "^7.37.3",
109
+ "eslint-plugin-react-hooks": "^5.1.0",
110
+ "eslint-plugin-react-native": "^5.0.0",
111
111
  "eslint-plugin-react-native-a11y": "^3.3.0",
112
- "eslint-plugin-simple-import-sort": "^12.1.0",
113
- "eslint-plugin-unused-imports": "3.2.0",
112
+ "eslint-plugin-simple-import-sort": "^12.1.1",
113
+ "eslint-plugin-unused-imports": "4.1.4",
114
114
  "jest": "^29.7.0",
115
- "jest-expo": "~51.0.2",
115
+ "jest-expo": "~52.0.5",
116
116
  "jest-github-actions-reporter": "^1.0.3",
117
117
  "mdurl": "^2.0.0",
118
- "prettier": "^3.2.5",
119
- "react": "18.2.0",
118
+ "prettier": "^3.3.3",
119
+ "react": "18.3.1",
120
120
  "react-keyed-flatten-children": "^3.0.0",
121
121
  "react-router": "^6.23.0",
122
122
  "react-router-dom": "^6.23.0",
@@ -134,42 +134,42 @@
134
134
  "@expo/vector-icons": "^14.0.1",
135
135
  "@react-native-async-storage/async-storage": "1.23.1",
136
136
  "@react-native-community/blur": "^4.4.0",
137
- "@react-native-community/datetimepicker": "8.0.1",
138
- "@react-native-picker/picker": "2.7.5",
139
- "expo-clipboard": "~6.0.3",
140
- "expo-font": "~12.0.5",
141
- "expo-haptics": "~13.0.1",
142
- "expo-image-manipulator": "~12.0.5",
143
- "expo-image-picker": "~15.0.5",
144
- "expo-linear-gradient": "~13.0.2",
137
+ "@react-native-community/datetimepicker": "8.2.0",
138
+ "@react-native-picker/picker": "2.9.0",
139
+ "expo-clipboard": "~7.0.1",
140
+ "expo-font": "~13.0.4",
141
+ "expo-haptics": "~14.0.1",
142
+ "expo-image-manipulator": "~13.0.6",
143
+ "expo-image-picker": "~16.0.6",
144
+ "expo-linear-gradient": "~14.0.2",
145
145
  "expo-localization": "~15.0.3",
146
- "libphonenumber-js": "^1.10.61",
146
+ "libphonenumber-js": "^1.11.17",
147
147
  "lodash": "^4.17.21",
148
- "luxon": "^3.4.4",
148
+ "luxon": "^3.5.0",
149
149
  "patch-package": "^8.0.0",
150
150
  "react-app-polyfill": "^3.0.0",
151
151
  "react-date-picker": "^11.0.0",
152
152
  "react-datetime-picker": "^6.0.1",
153
153
  "react-dev-utils": "^12.0.1",
154
- "react-dom": "18.2.0",
155
- "react-native": "0.74.5",
154
+ "react-dom": "18.3.1",
155
+ "react-native": "0.76.7",
156
156
  "react-native-actions-sheet": "^0.9.3",
157
- "react-native-calendars": "^1.1305.0",
158
- "react-native-drawer-layout": "^3.3.2",
159
- "react-native-gesture-handler": "~2.16.1",
157
+ "react-native-calendars": "^1.1304.1",
158
+ "react-native-drawer-layout": "3.3.2",
159
+ "react-native-gesture-handler": "~2.20.2",
160
160
  "react-native-google-places-autocomplete": "^2.5.6",
161
161
  "react-native-markdown-display": "^7.0.2",
162
162
  "react-native-modalize": "^2.1.1",
163
163
  "react-native-permissions": "^4.1.5",
164
164
  "react-native-picker-select": "^9.1.3",
165
165
  "react-native-portalize": "^1.0.7",
166
- "react-native-reanimated": "~3.10.1",
166
+ "react-native-reanimated": "~3.16.1",
167
167
  "react-native-signature-canvas": "^4.7.2",
168
- "react-native-svg": "15.2.0",
169
- "react-native-swiper-flatlist": "^3.2.3",
168
+ "react-native-svg": "15.8.0",
169
+ "react-native-swiper-flatlist": "^3.2.4",
170
170
  "react-native-toast-notifications": "^3.4.0",
171
- "react-native-webview": "13.8.6",
172
- "react-signature-canvas": "^1.0.6",
171
+ "react-native-webview": "13.12.5",
172
+ "react-signature-canvas": "^1.1.0-alpha.1",
173
173
  "react-time-picker": "^7.0.0"
174
174
  }
175
175
  }
package/src/Common.ts CHANGED
@@ -575,11 +575,18 @@ export type TooltipPosition = "top" | "bottom" | "left" | "right";
575
575
 
576
576
  export type IndicatorDirection = "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
577
577
 
578
+ export type SegmentedControlBadgeConfig = {
579
+ count: number;
580
+ status?: "info" | "error" | "warning" | "success" | "neutral";
581
+ };
582
+
578
583
  export interface SegmentedControlProps {
579
584
  items: string[];
580
585
  size?: "md" | "lg"; // default "md"
581
586
  onChange: (activeIndex: number) => void;
582
587
  selectedIndex?: number;
588
+ maxItems?: number;
589
+ badges?: SegmentedControlBadgeConfig[];
583
590
  }
584
591
 
585
592
  export interface TimezonePickerProps {
@@ -1,58 +1,124 @@
1
- import React from "react";
1
+ import React, {useCallback, useState} from "react";
2
2
  import {Pressable, View} from "react-native";
3
3
 
4
+ import {Badge} from "./Badge";
4
5
  import {SegmentedControlProps} from "./Common";
5
6
  import {Heading} from "./Heading";
7
+ import {Icon} from "./Icon";
6
8
  import {useTheme} from "./Theme";
7
9
 
8
- export const SegmentedControl = ({
10
+ export const SegmentedControl: React.FC<SegmentedControlProps> = ({
9
11
  items,
10
12
  onChange = () => {},
11
13
  size = "md",
12
14
  selectedIndex,
13
- }: SegmentedControlProps) => {
15
+ maxItems,
16
+ badges = [],
17
+ }) => {
14
18
  const height = size === "md" ? 36 : 44;
15
19
  const {theme} = useTheme();
20
+ const [startIndex, setStartIndex] = useState(0);
21
+
22
+ const handlePrevious = useCallback(() => {
23
+ setStartIndex((prev) => Math.max(0, prev - (maxItems ?? 4)));
24
+ }, []);
25
+
26
+ const handleNext = useCallback(() => {
27
+ setStartIndex((prev) => Math.min(items.length - (maxItems ?? items.length), prev + (maxItems ?? 4)));
28
+ }, [items.length, maxItems]);
29
+
30
+ const visibleItems = maxItems ? items.slice(startIndex, startIndex + maxItems) : items;
31
+ const visibleBadges = maxItems ? badges.slice(startIndex, startIndex + maxItems) : badges;
32
+ const canScrollLeft = startIndex > 0;
33
+ const canScrollRight = maxItems ? startIndex + maxItems < items.length : false;
34
+ const shouldShowScrollButtons = maxItems ? maxItems < items.length : false;
35
+
16
36
  return (
17
37
  <View
18
38
  style={{
19
39
  display: "flex",
20
- flexGrow: 1,
21
40
  flexDirection: "row",
22
- flexShrink: 1,
23
41
  alignItems: "center",
24
- gap: 4,
25
- height,
26
- maxHeight: height,
27
- borderRadius: theme.primitives.radius3xl,
28
- borderColor: theme.primitives.neutral300,
29
- borderWidth: 3,
30
- backgroundColor: theme.primitives.neutral300,
42
+ gap: 8,
31
43
  }}
32
44
  >
33
- {items.map((item, index) => (
34
- <Pressable
35
- key={index}
36
- aria-role="button"
45
+ {Boolean(shouldShowScrollButtons) && (
46
+ <Pressable disabled={!canScrollLeft} onPress={handlePrevious}>
47
+ <Icon
48
+ color={canScrollLeft ? "linkLight" : "extraLight"}
49
+ iconName="chevron-left"
50
+ size="lg"
51
+ />
52
+ </Pressable>
53
+ )}
54
+ <View
55
+ style={{
56
+ display: "flex",
57
+ flexGrow: 1,
58
+ flexDirection: "row",
59
+ flexShrink: 1,
60
+ alignItems: "center",
61
+ height,
62
+ maxHeight: height,
63
+ backgroundColor: theme.primitives.neutral300,
64
+ overflow: "hidden",
65
+ borderRadius: theme.primitives.radius3xl,
66
+ }}
67
+ >
68
+ <View
37
69
  style={{
38
70
  display: "flex",
39
- paddingHorizontal: size === "md" ? theme.spacing.sm : theme.spacing.md,
40
- justifyContent: "center",
41
- alignItems: "center",
42
- height: "100%",
43
- flexBasis: 0,
44
- gap: 12,
71
+ flexDirection: "row",
72
+ gap: 4,
45
73
  flexGrow: 1,
46
- flexShrink: 0,
47
- borderRadius: theme.primitives.radius3xl,
48
- backgroundColor: index === selectedIndex ? theme.surface.base : undefined,
49
- overflow: "hidden",
74
+ paddingHorizontal: 4,
75
+ height: height - 4,
50
76
  }}
51
- onPress={() => onChange(index)}
52
77
  >
53
- <Heading size="sm">{item}</Heading>
78
+ {visibleItems.map((item, index) => {
79
+ const actualIndex = startIndex + index;
80
+ return (
81
+ <Pressable
82
+ key={actualIndex}
83
+ aria-role="button"
84
+ style={{
85
+ display: "flex",
86
+ paddingHorizontal: 2,
87
+ justifyContent: "center",
88
+ alignItems: "center",
89
+ height: "100%",
90
+ flexDirection: "row",
91
+ gap: 8,
92
+ flexGrow: 1,
93
+ flexBasis: 0,
94
+ borderRadius: theme.primitives.radius3xl,
95
+ backgroundColor: actualIndex === selectedIndex ? theme.surface.base : undefined,
96
+ overflow: "hidden",
97
+ }}
98
+ onPress={() => onChange(actualIndex)}
99
+ >
100
+ <Heading size="sm">{item}</Heading>
101
+ {visibleBadges[index] && (
102
+ <Badge
103
+ status={visibleBadges[index].status ?? "info"}
104
+ value={visibleBadges[index].count}
105
+ variant="numberOnly"
106
+ />
107
+ )}
108
+ </Pressable>
109
+ );
110
+ })}
111
+ </View>
112
+ </View>
113
+ {Boolean(shouldShowScrollButtons) && (
114
+ <Pressable disabled={!canScrollRight} onPress={handleNext}>
115
+ <Icon
116
+ color={canScrollRight ? "linkLight" : "extraLight"}
117
+ iconName="chevron-right"
118
+ size="lg"
119
+ />
54
120
  </Pressable>
55
- ))}
121
+ )}
56
122
  </View>
57
123
  );
58
124
  };