@grupalia/rn-ui-kit 0.2.0 → 0.3.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.
Files changed (62) hide show
  1. package/lib/commonjs/components/BaseBottomSheetModal.js +46 -0
  2. package/lib/commonjs/components/BaseBottomSheetModal.js.map +1 -0
  3. package/lib/commonjs/components/BaseHorizontalTabs.js +138 -0
  4. package/lib/commonjs/components/BaseHorizontalTabs.js.map +1 -0
  5. package/lib/commonjs/components/BaseSelect.js +115 -0
  6. package/lib/commonjs/components/BaseSelect.js.map +1 -0
  7. package/lib/commonjs/components/BaseStackedList.js +6 -3
  8. package/lib/commonjs/components/BaseStackedList.js.map +1 -1
  9. package/lib/commonjs/components/FormikSelect.js +36 -0
  10. package/lib/commonjs/components/FormikSelect.js.map +1 -0
  11. package/lib/commonjs/components/index.js +28 -0
  12. package/lib/commonjs/components/index.js.map +1 -1
  13. package/lib/commonjs/styles/text-colors.js +4 -16
  14. package/lib/commonjs/styles/text-colors.js.map +1 -1
  15. package/lib/module/components/BaseBottomSheetModal.js +42 -0
  16. package/lib/module/components/BaseBottomSheetModal.js.map +1 -0
  17. package/lib/module/components/BaseHorizontalTabs.js +132 -0
  18. package/lib/module/components/BaseHorizontalTabs.js.map +1 -0
  19. package/lib/module/components/BaseSelect.js +109 -0
  20. package/lib/module/components/BaseSelect.js.map +1 -0
  21. package/lib/module/components/BaseStackedList.js +6 -3
  22. package/lib/module/components/BaseStackedList.js.map +1 -1
  23. package/lib/module/components/FormikSelect.js +31 -0
  24. package/lib/module/components/FormikSelect.js.map +1 -0
  25. package/lib/module/components/index.js +3 -0
  26. package/lib/module/components/index.js.map +1 -1
  27. package/lib/module/styles/text-colors.js +4 -16
  28. package/lib/module/styles/text-colors.js.map +1 -1
  29. package/lib/typescript/commonjs/components/BaseBottomSheetModal.d.ts +8 -0
  30. package/lib/typescript/commonjs/components/BaseBottomSheetModal.d.ts.map +1 -0
  31. package/lib/typescript/commonjs/components/BaseHorizontalTabs.d.ts +27 -0
  32. package/lib/typescript/commonjs/components/BaseHorizontalTabs.d.ts.map +1 -0
  33. package/lib/typescript/commonjs/components/BaseSelect.d.ts +28 -0
  34. package/lib/typescript/commonjs/components/BaseSelect.d.ts.map +1 -0
  35. package/lib/typescript/commonjs/components/BaseStackedList.d.ts +5 -8
  36. package/lib/typescript/commonjs/components/BaseStackedList.d.ts.map +1 -1
  37. package/lib/typescript/commonjs/components/FormikSelect.d.ts +20 -0
  38. package/lib/typescript/commonjs/components/FormikSelect.d.ts.map +1 -0
  39. package/lib/typescript/commonjs/components/index.d.ts +3 -0
  40. package/lib/typescript/commonjs/components/index.d.ts.map +1 -1
  41. package/lib/typescript/commonjs/styles/text-colors.d.ts.map +1 -1
  42. package/lib/typescript/module/components/BaseBottomSheetModal.d.ts +8 -0
  43. package/lib/typescript/module/components/BaseBottomSheetModal.d.ts.map +1 -0
  44. package/lib/typescript/module/components/BaseHorizontalTabs.d.ts +27 -0
  45. package/lib/typescript/module/components/BaseHorizontalTabs.d.ts.map +1 -0
  46. package/lib/typescript/module/components/BaseSelect.d.ts +28 -0
  47. package/lib/typescript/module/components/BaseSelect.d.ts.map +1 -0
  48. package/lib/typescript/module/components/BaseStackedList.d.ts +5 -8
  49. package/lib/typescript/module/components/BaseStackedList.d.ts.map +1 -1
  50. package/lib/typescript/module/components/FormikSelect.d.ts +20 -0
  51. package/lib/typescript/module/components/FormikSelect.d.ts.map +1 -0
  52. package/lib/typescript/module/components/index.d.ts +3 -0
  53. package/lib/typescript/module/components/index.d.ts.map +1 -1
  54. package/lib/typescript/module/styles/text-colors.d.ts.map +1 -1
  55. package/package.json +9 -5
  56. package/src/components/BaseBottomSheetModal.tsx +51 -0
  57. package/src/components/BaseHorizontalTabs.tsx +221 -0
  58. package/src/components/BaseSelect.tsx +165 -0
  59. package/src/components/BaseStackedList.tsx +14 -6
  60. package/src/components/FormikSelect.tsx +45 -0
  61. package/src/components/index.ts +3 -0
  62. package/src/styles/text-colors.ts +4 -16
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseHorizontalTabs.d.ts","sourceRoot":"","sources":["../../../../src/components/BaseHorizontalTabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAWxC,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG,WAAW,GAAG,aAAa,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAExG,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B;AAED,UAAU,uBAAuB;IAC/B,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;;;;;;;AA4LD,wBAA0C"}
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { ViewStyle } from 'react-native';
3
+ export interface SelectOption {
4
+ value: string;
5
+ label: string;
6
+ disabled?: boolean;
7
+ }
8
+ interface BaseSelectProps {
9
+ options: SelectOption[];
10
+ value?: string;
11
+ onChange?: (value: string) => void;
12
+ placeholder?: string;
13
+ label?: string;
14
+ helpText?: string;
15
+ error?: string;
16
+ touched?: boolean;
17
+ disabled?: boolean;
18
+ className?: string;
19
+ style?: ViewStyle;
20
+ }
21
+ declare const _default: React.ForwardRefExoticComponent<BaseSelectProps & {
22
+ className?: string | undefined;
23
+ tw?: string | undefined;
24
+ baseClassName?: string | undefined;
25
+ baseTw?: string | undefined;
26
+ } & React.RefAttributes<unknown>>;
27
+ export default _default;
28
+ //# sourceMappingURL=BaseSelect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseSelect.d.ts","sourceRoot":"","sources":["../../../../src/components/BaseSelect.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAYzC,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;;;;;;;AAkID,wBAAkC"}
@@ -1,5 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
- export interface BaseStackedListProps<T> {
2
+ import { ViewProps } from 'react-native';
3
+ export interface BaseStackedListProps<T> extends ViewProps {
3
4
  itemsCount: number;
4
5
  items: T[];
5
6
  renderItem: (item: T, index: number) => ReactNode;
@@ -13,11 +14,7 @@ export interface BaseStackedListProps<T> {
13
14
  emptyStateDescription?: string;
14
15
  minHeight?: number;
15
16
  }
16
- declare const _default: React.ForwardRefExoticComponent<BaseStackedListProps<unknown> & {
17
- className?: string | undefined;
18
- tw?: string | undefined;
19
- baseClassName?: string | undefined;
20
- baseTw?: string | undefined;
21
- } & React.RefAttributes<unknown>>;
22
- export default _default;
17
+ declare function BaseStackedList<T>({ itemsCount, items, renderItem, onNextPage, onPrevPage, header, pageSize, loading, currentPage, keyExtractor, emptyStateDescription, minHeight, ...props }: BaseStackedListProps<T>): React.JSX.Element;
18
+ declare const StackedList: typeof BaseStackedList;
19
+ export default StackedList;
23
20
  //# sourceMappingURL=BaseStackedList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BaseStackedList.d.ts","sourceRoot":"","sources":["../../../../src/components/BaseStackedList.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAW,MAAM,OAAO,CAAC;AAUlD,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAClD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;;;;;;;AAgHD,wBAAuC"}
1
+ {"version":3,"file":"BaseStackedList.d.ts","sourceRoot":"","sources":["../../../../src/components/BaseStackedList.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAW,MAAM,OAAO,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AASzC,MAAM,WAAW,oBAAoB,CAAC,CAAC,CAAE,SAAQ,SAAS;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAClD,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,iBAAS,eAAe,CAAC,CAAC,EAAE,EAC1B,UAAU,EACV,KAAK,EACL,UAAU,EACV,UAAU,EACV,UAAU,EACV,MAAM,EACN,QAAQ,EACR,OAAO,EACP,WAAe,EACf,YAAY,EACZ,qBAAqB,EACrB,SAAa,EACb,GAAG,KAAK,EACT,EAAE,oBAAoB,CAAC,CAAC,CAAC,qBA+EzB;AAED,QAAA,MAAM,WAAW,wBAAoD,CAAC;AAEtE,eAAe,WAAW,CAAC"}
@@ -0,0 +1,20 @@
1
+ /// <reference types="react" />
2
+ import { SelectOption } from './BaseSelect';
3
+ export type { SelectOption } from './BaseSelect';
4
+ interface FormikSelectProps {
5
+ name: string;
6
+ options: SelectOption[];
7
+ placeholder?: string;
8
+ label?: string;
9
+ helpText?: string;
10
+ disabled?: boolean;
11
+ className?: string;
12
+ }
13
+ declare const _default: import("react").ForwardRefExoticComponent<FormikSelectProps & {
14
+ className?: string | undefined;
15
+ tw?: string | undefined;
16
+ baseClassName?: string | undefined;
17
+ baseTw?: string | undefined;
18
+ } & import("react").RefAttributes<unknown>>;
19
+ export default _default;
20
+ //# sourceMappingURL=FormikSelect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormikSelect.d.ts","sourceRoot":"","sources":["../../../../src/components/FormikSelect.tsx"],"names":[],"mappings":";AAGA,OAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAExD,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;;;;;;;AA6BD,wBAAoC"}
@@ -4,4 +4,7 @@ export { default as BaseSpinner } from './BaseSpinner';
4
4
  export { default as BaseStackedList } from './BaseStackedList';
5
5
  export { default as BaseIcon } from './BaseIcon';
6
6
  export { default as BaseAlert } from './BaseAlert';
7
+ export { default as BaseSelect, SelectOption } from './BaseSelect';
8
+ export { default as FormikSelect } from './FormikSelect';
9
+ export { default as BaseHorizontalTabs } from './BaseHorizontalTabs';
7
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"text-colors.d.ts","sourceRoot":"","sources":["../../../../src/styles/text-colors.ts"],"names":[],"mappings":"AAGA,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;CAC5B,CAAC;AAEF,QAAA,MAAM,UAAU,EAAE,cAyGjB,CAAC;AASF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"text-colors.d.ts","sourceRoot":"","sources":["../../../../src/styles/text-colors.ts"],"names":[],"mappings":"AAGA,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;CAC5B,CAAC;AAEF,QAAA,MAAM,UAAU,EAAE,cA6FjB,CAAC;AASF,eAAe,UAAU,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grupalia/rn-ui-kit",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Grupalia React Native UI Kit",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/module/index.d.ts",
@@ -19,16 +19,19 @@
19
19
  "publish-local": "npx yalc publish"
20
20
  },
21
21
  "peerDependencies": {
22
+ "@gorhom/bottom-sheet": "^5",
22
23
  "clsx": "^2.1.1",
24
+ "formik": "^2",
23
25
  "nativewind": "^2.0.11",
24
26
  "react": "*",
25
27
  "react-native": "*",
26
- "tailwindcss": "3.3.2",
27
28
  "react-native-heroicons": "^4.0.0",
28
- "react-native-svg": "*"
29
+ "react-native-svg": "*",
30
+ "tailwindcss": "3.3.2"
29
31
  },
30
32
  "devDependencies": {
31
33
  "@babel/core": "^7.20.0",
34
+ "@gorhom/bottom-sheet": "^5",
32
35
  "@types/react": "~18.2.45",
33
36
  "@typescript-eslint/eslint-plugin": "^7.10.0",
34
37
  "@typescript-eslint/parser": "^7.10.0",
@@ -41,14 +44,15 @@
41
44
  "eslint-plugin-react": "^7.34.1",
42
45
  "eslint-plugin-react-hooks": "^4.6.2",
43
46
  "eslint-plugin-tailwindcss": "^3.17.4",
47
+ "formik": "^2",
44
48
  "nativewind": "^2.0.11",
45
49
  "react": "18.2.0",
46
50
  "react-native": "0.74.5",
47
51
  "react-native-builder-bob": "^0.40.6",
52
+ "react-native-heroicons": "^4.0.0",
48
53
  "react-native-svg": "^15.11.2",
49
54
  "tailwindcss": "3.3.2",
50
- "typescript": "~5.3.3",
51
- "react-native-heroicons": "^4.0.0"
55
+ "typescript": "~5.3.3"
52
56
  },
53
57
  "exports": {
54
58
  ".": {
@@ -0,0 +1,51 @@
1
+ import {
2
+ BottomSheetModal,
3
+ BottomSheetBackdrop,
4
+ BottomSheetBackdropProps,
5
+ BottomSheetModalProps,
6
+ BottomSheetView,
7
+ } from '@gorhom/bottom-sheet';
8
+ import { styled } from 'nativewind';
9
+ import { forwardRef, ReactNode } from 'react';
10
+ import { StyleSheet } from 'react-native';
11
+
12
+ function BackdropComponent(props: BottomSheetBackdropProps) {
13
+ return (
14
+ <BottomSheetBackdrop
15
+ {...props}
16
+ opacity={0.5}
17
+ enableTouchThrough={false}
18
+ appearsOnIndex={0}
19
+ disappearsOnIndex={-1}
20
+ style={[{ backgroundColor: 'rgba(0, 0, 0, 1)' }, StyleSheet.absoluteFillObject]}
21
+ />
22
+ );
23
+ }
24
+
25
+ interface BaseBottomSheetModalProps extends BottomSheetModalProps {
26
+ children: ReactNode;
27
+ }
28
+
29
+ const BaseBottomSheetModal = forwardRef<
30
+ BottomSheetModal,
31
+ BaseBottomSheetModalProps
32
+ >(({ children, ...props }, ref) => (
33
+ <BottomSheetModal
34
+ ref={ref}
35
+ backdropComponent={BackdropComponent}
36
+ style={{
37
+ shadowColor: 'black',
38
+ shadowOffset: { width: 0, height: 10 },
39
+ shadowOpacity: 0.53,
40
+ shadowRadius: 13.97,
41
+ elevation: 21,
42
+ }}
43
+ {...props}
44
+ >
45
+ <BottomSheetView>
46
+ {children}
47
+ </BottomSheetView>
48
+ </BottomSheetModal>
49
+ ));
50
+
51
+ export default styled(BaseBottomSheetModal);
@@ -0,0 +1,221 @@
1
+ import clsx from 'clsx';
2
+ import { styled } from 'nativewind';
3
+ import React, { useState } from 'react';
4
+
5
+ import {
6
+ View,
7
+ Text,
8
+ ScrollView,
9
+ Pressable,
10
+ } from '../hoc-components';
11
+ import BaseBadge from './BaseBadge';
12
+ import BaseSelect, { SelectOption } from './BaseSelect';
13
+
14
+ export type Variant = 'button-brand' | 'underline' | 'button-gray' | 'button-border' | 'button-minimal';
15
+
16
+ export interface Tab {
17
+ id: string;
18
+ label: string;
19
+ badge?: string | number;
20
+ content: React.ReactNode;
21
+ }
22
+
23
+ interface BaseHorizontalTabsProps {
24
+ tabs: Tab[];
25
+ defaultTab?: string;
26
+ selectedTab?: string;
27
+ onTabChange?: (tabId: string) => void;
28
+ variant?: Variant;
29
+ fullWidth?: boolean;
30
+ select?: boolean;
31
+ unmountHiddenTabs?: boolean;
32
+ className?: string;
33
+ }
34
+
35
+ function BaseHorizontalTabs({
36
+ tabs,
37
+ defaultTab,
38
+ selectedTab: controlledSelectedTab,
39
+ onTabChange,
40
+ variant = 'button-brand',
41
+ fullWidth = false,
42
+ select = false,
43
+ unmountHiddenTabs = false,
44
+ className,
45
+ }: BaseHorizontalTabsProps) {
46
+ const [internalSelectedTab, setInternalSelectedTab] = useState(defaultTab || tabs[0]?.id);
47
+ const selectedTab = controlledSelectedTab || internalSelectedTab;
48
+
49
+ const handleTabSelect = (tabId: string) => {
50
+ if (controlledSelectedTab === undefined) {
51
+ setInternalSelectedTab(tabId);
52
+ }
53
+ onTabChange?.(tabId);
54
+ };
55
+
56
+ const selectedTabContent = tabs.find((tab) => tab.id === selectedTab)?.content;
57
+
58
+ const getTabStyles = (isActive: boolean) => {
59
+ const baseStyles = 'rounded-md px-3 py-2';
60
+
61
+ switch (variant) {
62
+ case 'button-brand':
63
+ return clsx(
64
+ baseStyles,
65
+ isActive ? 'bg-brand-primary_alt' : 'bg-transparent',
66
+ );
67
+ case 'underline':
68
+ return clsx(
69
+ 'px-1 pb-3',
70
+ isActive ? 'border-b-2 border-brand-primary' : 'border-b-2 border-transparent',
71
+ );
72
+ case 'button-gray':
73
+ return clsx(
74
+ baseStyles,
75
+ isActive ? 'bg-active' : 'bg-transparent',
76
+ );
77
+ case 'button-border':
78
+ return clsx(
79
+ baseStyles,
80
+ isActive ? 'bg-primary shadow-sm' : 'bg-transparent',
81
+ );
82
+ case 'button-minimal':
83
+ return clsx(
84
+ baseStyles,
85
+ 'border',
86
+ isActive ? 'border-secondary bg-primary shadow-sm' : 'border-transparent bg-transparent',
87
+ );
88
+ default:
89
+ return baseStyles;
90
+ }
91
+ };
92
+
93
+ const getTextStyles = (isActive: boolean) => {
94
+ const baseStyles = 'text-sm font-semibold';
95
+
96
+ switch (variant) {
97
+ case 'button-brand':
98
+ return clsx(
99
+ baseStyles,
100
+ isActive ? 'text-brand-secondary' : 'text-quaternary',
101
+ );
102
+ case 'underline':
103
+ return clsx(
104
+ baseStyles,
105
+ isActive ? 'text-brand-secondary' : 'text-quaternary',
106
+ );
107
+ case 'button-gray':
108
+ case 'button-border':
109
+ case 'button-minimal':
110
+ return clsx(
111
+ baseStyles,
112
+ isActive ? 'text-secondary' : 'text-quaternary',
113
+ );
114
+ default:
115
+ return baseStyles;
116
+ }
117
+ };
118
+
119
+ const getContainerStyles = () => {
120
+ switch (variant) {
121
+ case 'button-brand':
122
+ case 'button-gray':
123
+ return fullWidth ? 'flex-row space-x-1 p-0' : 'flex-row space-x-1';
124
+ case 'underline':
125
+ return fullWidth ? 'flex-row space-x-3 border-b border-tertiary' : 'flex-row space-x-3 border-b border-tertiary';
126
+ case 'button-border':
127
+ return 'flex-row space-x-0.5 bg-secondary_alt p-1 rounded-lg border border-secondary';
128
+ case 'button-minimal':
129
+ return 'flex-row space-x-0.5 bg-secondary_alt rounded-lg border border-secondary';
130
+ default:
131
+ return 'flex-row space-x-1';
132
+ }
133
+ };
134
+
135
+ if (select) {
136
+ const selectOptions: SelectOption[] = tabs.map((tab) => ({
137
+ label: tab.badge ? `${tab.label} (${tab.badge})` : tab.label,
138
+ value: tab.id,
139
+ }));
140
+
141
+ return (
142
+ <View className={className}>
143
+ <BaseSelect
144
+ value={selectedTab}
145
+ onChange={handleTabSelect}
146
+ options={selectOptions}
147
+ placeholder="Select a tab"
148
+ />
149
+ <View className="mt-4">
150
+ {unmountHiddenTabs ? (
151
+ selectedTabContent
152
+ ) : (
153
+ tabs.map((tab) => (
154
+ <View
155
+ key={tab.id}
156
+ className={clsx(tab.id === selectedTab ? 'flex' : 'hidden')}
157
+ >
158
+ {tab.content}
159
+ </View>
160
+ ))
161
+ )}
162
+ </View>
163
+ </View>
164
+ );
165
+ }
166
+
167
+ return (
168
+ <View className={className}>
169
+ <ScrollView
170
+ horizontal
171
+ showsHorizontalScrollIndicator={false}
172
+ className={clsx(
173
+ 'p-0.5',
174
+ fullWidth && 'w-full',
175
+ )}
176
+ >
177
+ <View className={getContainerStyles()}>
178
+ {tabs.map((tab) => (
179
+ <Pressable
180
+ key={tab.id}
181
+ onPress={() => handleTabSelect(tab.id)}
182
+ className={clsx(
183
+ getTabStyles(tab.id === selectedTab),
184
+ fullWidth && 'flex-1',
185
+ )}
186
+ >
187
+ <View className="flex-row items-center space-x-2">
188
+ <Text className={getTextStyles(tab.id === selectedTab)}>
189
+ {tab.label}
190
+ </Text>
191
+ {tab.badge && (
192
+ <BaseBadge
193
+ text={String(tab.badge)}
194
+ variant="gray"
195
+ size="sm"
196
+ />
197
+ )}
198
+ </View>
199
+ </Pressable>
200
+ ))}
201
+ </View>
202
+ </ScrollView>
203
+ <View className="mt-4">
204
+ {unmountHiddenTabs ? (
205
+ selectedTabContent
206
+ ) : (
207
+ tabs.map((tab) => (
208
+ <View
209
+ key={tab.id}
210
+ className={clsx(tab.id === selectedTab ? 'flex' : 'hidden')}
211
+ >
212
+ {tab.content}
213
+ </View>
214
+ ))
215
+ )}
216
+ </View>
217
+ </View>
218
+ );
219
+ }
220
+
221
+ export default styled(BaseHorizontalTabs);
@@ -0,0 +1,165 @@
1
+ import { BottomSheetModal } from '@gorhom/bottom-sheet';
2
+ import clsx from 'clsx';
3
+ import { styled } from 'nativewind';
4
+ import React, { useRef, useState } from 'react';
5
+ import { ViewStyle } from 'react-native';
6
+ import { ChevronDownIcon, CheckIcon } from 'react-native-heroicons/outline';
7
+
8
+ import {
9
+ View,
10
+ Text,
11
+ Pressable,
12
+ TouchableOpacity,
13
+ } from '../hoc-components';
14
+ import BaseBottomSheetModal from './BaseBottomSheetModal';
15
+ import BaseIcon from './BaseIcon';
16
+
17
+ export interface SelectOption {
18
+ value: string;
19
+ label: string;
20
+ disabled?: boolean;
21
+ }
22
+
23
+ interface BaseSelectProps {
24
+ options: SelectOption[];
25
+ value?: string;
26
+ onChange?: (value: string) => void;
27
+ placeholder?: string;
28
+ label?: string;
29
+ helpText?: string;
30
+ error?: string;
31
+ touched?: boolean;
32
+ disabled?: boolean;
33
+ className?: string;
34
+ style?: ViewStyle;
35
+ }
36
+
37
+ function BaseSelect({
38
+ options,
39
+ value = '',
40
+ onChange,
41
+ placeholder = 'Select option',
42
+ label,
43
+ helpText,
44
+ error,
45
+ touched = false,
46
+ disabled = false,
47
+ className,
48
+ style,
49
+ }: BaseSelectProps) {
50
+ const bottomSheetRef = useRef<BottomSheetModal>(null);
51
+ const [isFocused, setIsFocused] = useState(false);
52
+
53
+ const selectedOption = options.find((opt) => opt.value === value);
54
+
55
+ const handlePress = () => {
56
+ if (disabled) return;
57
+ setIsFocused(true);
58
+ bottomSheetRef.current?.present();
59
+ };
60
+
61
+ const handleOptionPress = (optionValue: string) => {
62
+ onChange?.(optionValue);
63
+ bottomSheetRef.current?.dismiss();
64
+ };
65
+
66
+ const hasError = touched && error;
67
+
68
+ const selectClasses = clsx(
69
+ 'flex-row items-center justify-between rounded-lg border px-3.5 py-2.5',
70
+ {
71
+ 'border-gray-300 bg-white': !hasError && !disabled,
72
+ 'border-gray-300 bg-gray-50': disabled,
73
+ 'border-red-300 bg-white': hasError && !disabled,
74
+ 'shadow-sm': !disabled,
75
+ },
76
+ className,
77
+ );
78
+
79
+ const textClasses = clsx('text-base', {
80
+ 'text-gray-900': selectedOption && !disabled,
81
+ 'text-gray-500': (!selectedOption && !disabled) || disabled,
82
+ });
83
+
84
+ return (
85
+ <View style={style}>
86
+ {label && (
87
+ <Text className="mb-1.5 text-sm font-medium text-gray-700">{label}</Text>
88
+ )}
89
+
90
+ <Pressable
91
+ onPress={handlePress}
92
+ disabled={disabled}
93
+ className={selectClasses}
94
+ >
95
+ <Text
96
+ className={textClasses}
97
+ numberOfLines={1}
98
+ >
99
+ {selectedOption?.label || placeholder}
100
+ </Text>
101
+ <BaseIcon
102
+ icon={ChevronDownIcon}
103
+ size={20}
104
+ color="fg-quaternary"
105
+ className={clsx('ml-2', isFocused && 'rotate-180')}
106
+ />
107
+ </Pressable>
108
+
109
+ {helpText && !hasError && (
110
+ <Text className="mt-1.5 text-sm text-gray-500">{helpText}</Text>
111
+ )}
112
+
113
+ {hasError && (
114
+ <Text className="mt-1.5 text-sm text-red-600">{error}</Text>
115
+ )}
116
+
117
+ <BaseBottomSheetModal
118
+ ref={bottomSheetRef}
119
+ enableDynamicSizing
120
+ maxDynamicContentSize={400}
121
+ onDismiss={() => setIsFocused(false)}
122
+ >
123
+ <View className="px-4 pb-8 pt-4">
124
+ <Text className="mb-4 text-center text-lg font-semibold text-gray-900">
125
+ {label || 'Select an option'}
126
+ </Text>
127
+ <View className="mx-2">
128
+ {options.map((option, index) => (
129
+ <TouchableOpacity
130
+ key={option.value}
131
+ onPress={() => handleOptionPress(option.value)}
132
+ disabled={option.disabled}
133
+ className={clsx(
134
+ 'flex-row items-center justify-between py-4',
135
+ {
136
+ 'border-t border-gray-200': index > 0,
137
+ 'opacity-50': option.disabled,
138
+ },
139
+ )}
140
+ >
141
+ <Text
142
+ className={clsx('flex-1 text-base', {
143
+ 'text-gray-900': !option.disabled,
144
+ 'text-gray-400': option.disabled,
145
+ 'font-medium': option.value === value,
146
+ })}
147
+ >
148
+ {option.label}
149
+ </Text>
150
+ {option.value === value && (
151
+ <CheckIcon
152
+ size={20}
153
+ className="ml-2 text-brand-primary"
154
+ />
155
+ )}
156
+ </TouchableOpacity>
157
+ ))}
158
+ </View>
159
+ </View>
160
+ </BaseBottomSheetModal>
161
+ </View>
162
+ );
163
+ }
164
+
165
+ export default styled(BaseSelect);
@@ -9,7 +9,7 @@ import BaseButton from './BaseButton';
9
9
  import BaseSpinner from './BaseSpinner';
10
10
  import colors from '../styles/colors';
11
11
 
12
- export interface BaseStackedListProps<T> {
12
+ export interface BaseStackedListProps<T> extends ViewProps {
13
13
  itemsCount: number;
14
14
  items: T[];
15
15
  renderItem: (item: T, index: number) => ReactNode;
@@ -58,6 +58,7 @@ function BaseStackedList<T>({
58
58
  keyExtractor,
59
59
  emptyStateDescription,
60
60
  minHeight = 0,
61
+ ...props
61
62
  }: BaseStackedListProps<T>) {
62
63
  const totalPages = useMemo(() => Math.ceil(itemsCount / pageSize), [itemsCount, pageSize]);
63
64
  const hasNextPage = currentPage < totalPages - 1;
@@ -73,10 +74,15 @@ function BaseStackedList<T>({
73
74
  const hasItemsForCurrentPage = currentPageItems.length > pageSize * (currentPage + 1);
74
75
 
75
76
  return (
76
- <View className="flex flex-col rounded-xl border border-secondary bg-primary shadow-sm">
77
- <View className="border-b border-secondary p-4">
78
- {header}
79
- </View>
77
+ <View
78
+ className="flex flex-col rounded-xl border border-secondary bg-primary shadow-sm"
79
+ {...props}
80
+ >
81
+ {header && (
82
+ <View className="border-b border-secondary p-4">
83
+ {header}
84
+ </View>
85
+ )}
80
86
  {loading && !hasItemsForCurrentPage && (
81
87
  <View
82
88
  className="flex items-center justify-center py-12"
@@ -134,4 +140,6 @@ function BaseStackedList<T>({
134
140
  );
135
141
  }
136
142
 
137
- export default styled(BaseStackedList);
143
+ const StackedList = styled(BaseStackedList) as typeof BaseStackedList;
144
+
145
+ export default StackedList;