@kivid/native-components 1.0.0-alpha.23 → 1.0.0-alpha.25

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 (50) hide show
  1. package/dist/commonjs/components/Dropdown/index.js +199 -0
  2. package/dist/commonjs/components/Dropdown/index.js.map +1 -0
  3. package/dist/commonjs/components/Dropdown/types.js +6 -0
  4. package/dist/commonjs/components/Dropdown/types.js.map +1 -0
  5. package/dist/commonjs/components/Tab/assets/class-variants.js +69 -0
  6. package/dist/commonjs/components/Tab/assets/class-variants.js.map +1 -0
  7. package/dist/commonjs/components/Tab/index.js +90 -0
  8. package/dist/commonjs/components/Tab/index.js.map +1 -0
  9. package/dist/commonjs/components/Tab/types.js +6 -0
  10. package/dist/commonjs/components/Tab/types.js.map +1 -0
  11. package/dist/commonjs/components/Title/components/marker/index.js +11 -4
  12. package/dist/commonjs/components/Title/components/marker/index.js.map +1 -1
  13. package/dist/commonjs/components/Toast/assets/class-variants.js +1 -1
  14. package/dist/commonjs/components/Toast/assets/class-variants.js.map +1 -1
  15. package/dist/commonjs/components/index.js +22 -0
  16. package/dist/commonjs/components/index.js.map +1 -1
  17. package/dist/module/components/Dropdown/index.js +195 -0
  18. package/dist/module/components/Dropdown/index.js.map +1 -0
  19. package/dist/module/components/Dropdown/types.js +4 -0
  20. package/dist/module/components/Dropdown/types.js.map +1 -0
  21. package/dist/module/components/Tab/assets/class-variants.js +66 -0
  22. package/dist/module/components/Tab/assets/class-variants.js.map +1 -0
  23. package/dist/module/components/Tab/index.js +86 -0
  24. package/dist/module/components/Tab/index.js.map +1 -0
  25. package/dist/module/components/Tab/types.js +4 -0
  26. package/dist/module/components/Tab/types.js.map +1 -0
  27. package/dist/module/components/Title/components/marker/index.js +11 -4
  28. package/dist/module/components/Title/components/marker/index.js.map +1 -1
  29. package/dist/module/components/Toast/assets/class-variants.js +1 -1
  30. package/dist/module/components/Toast/assets/class-variants.js.map +1 -1
  31. package/dist/module/components/index.js +2 -0
  32. package/dist/module/components/index.js.map +1 -1
  33. package/dist/typescript/components/Dropdown/index.d.ts +3 -0
  34. package/dist/typescript/components/Dropdown/types.d.ts +17 -0
  35. package/dist/typescript/components/Tab/assets/class-variants.d.ts +18 -0
  36. package/dist/typescript/components/Tab/index.d.ts +2 -0
  37. package/dist/typescript/components/Tab/types.d.ts +17 -0
  38. package/dist/typescript/components/Title/components/marker/index.d.ts +1 -1
  39. package/dist/typescript/components/Title/components/marker/types.d.ts +1 -0
  40. package/dist/typescript/components/index.d.ts +4 -0
  41. package/package.json +5 -5
  42. package/src/components/Dropdown/index.tsx +213 -0
  43. package/src/components/Dropdown/types.ts +18 -0
  44. package/src/components/Tab/assets/class-variants.ts +83 -0
  45. package/src/components/Tab/index.tsx +92 -0
  46. package/src/components/Tab/types.ts +20 -0
  47. package/src/components/Title/components/marker/index.tsx +10 -2
  48. package/src/components/Title/components/marker/types.ts +1 -0
  49. package/src/components/Toast/assets/class-variants.ts +1 -1
  50. package/src/components/index.ts +6 -0
@@ -0,0 +1,213 @@
1
+ import React, { useState, useRef, useEffect } from "react";
2
+ import { View, Pressable, Modal, TouchableWithoutFeedback } from "react-native";
3
+ import { Typography } from "../Typography";
4
+ import type { DropdownProps } from "./types";
5
+ import { ArrowChevronDownStroke } from "@kivid/icons/native";
6
+ import { Animated, Easing } from "react-native";
7
+ import { IconButton } from "../IconButton";
8
+ import { IconButtonSizeEnum } from "../IconButton/enums";
9
+ import { cva } from "class-variance-authority";
10
+ import { SizeEnum } from "../../enums";
11
+
12
+ export function Dropdown(props: DropdownProps) {
13
+ const {
14
+ label,
15
+ value,
16
+ placeholder,
17
+ disabled = false,
18
+ className,
19
+ leftButtonText,
20
+ hidePlaceholder = false,
21
+ children,
22
+ iconButtonTrigger,
23
+ iconButtonAlign = "right",
24
+ size = SizeEnum.MEDIUM,
25
+ corner = SizeEnum.SMALL,
26
+ } = props;
27
+
28
+ const [isOpen, setIsOpen] = useState(false);
29
+ const [dropdownLayout, setDropdownLayout] = useState({
30
+ top: 0,
31
+ left: 0,
32
+ width: 0,
33
+ });
34
+ const triggerRef = useRef<View>(null);
35
+
36
+ const rotateAnim = useRef(new Animated.Value(0)).current;
37
+
38
+ useEffect(() => {
39
+ Animated.timing(rotateAnim, {
40
+ toValue: isOpen ? 1 : 0,
41
+ duration: 200,
42
+ easing: Easing.out(Easing.ease),
43
+ useNativeDriver: true,
44
+ }).start();
45
+ }, [isOpen, rotateAnim]);
46
+
47
+ const rotate = rotateAnim.interpolate({
48
+ inputRange: [0, 1],
49
+ outputRange: ["0deg", "180deg"],
50
+ });
51
+
52
+
53
+ const handlePress = () => {
54
+ if (disabled) return;
55
+
56
+ triggerRef.current?.measureInWindow((x, y, width, height) => {
57
+ setDropdownLayout({
58
+ top: y + height + 4,
59
+ left: x,
60
+ width: width,
61
+ });
62
+ setIsOpen(true);
63
+ });
64
+ };
65
+
66
+ const handleClose = () => {
67
+ setIsOpen(false);
68
+ };
69
+
70
+ const textStyle = cva("text-chia-900", {
71
+ variants: {
72
+ placeholder: {
73
+ true: "text-chia-600",
74
+ false: "text-chia-900",
75
+ },
76
+ },
77
+ });
78
+
79
+ const dropdownStyle = cva("bg-chia-100 border border-chia-400 px-500 ", {
80
+ variants: {
81
+ size: {
82
+ [SizeEnum.SMALL]: "py-400",
83
+ [SizeEnum.MEDIUM]: "py-600",
84
+ },
85
+ corner: {
86
+ [SizeEnum.SMALL]: "rounded-400",
87
+ [SizeEnum.MEDIUM]: "rounded-700",
88
+ },
89
+ },
90
+ });
91
+
92
+ const triggerPositionStyle = cva("flex-row w-full", {
93
+ variants: {
94
+ align: {
95
+ left: "justify-start",
96
+ right: "justify-end",
97
+ center: "justify-center",
98
+ },
99
+ },
100
+ });
101
+
102
+ function renderVariant() {
103
+ const displayPlaceholder = !!placeholder && !value;
104
+ if (hidePlaceholder) {
105
+ return null;
106
+ }
107
+
108
+ return (
109
+ <View className="flex-row justify-between gap-100">
110
+ <Typography
111
+ variant="label_large"
112
+ weight="700"
113
+ className={textStyle({ placeholder: displayPlaceholder })}
114
+ >
115
+ {displayPlaceholder ? placeholder : value}
116
+ </Typography>
117
+ </View>
118
+ );
119
+ }
120
+
121
+ function renderTrigger() {
122
+ if (iconButtonTrigger) {
123
+ return (
124
+ <View className={triggerPositionStyle({ align: iconButtonAlign })}>
125
+ <IconButton
126
+ onPress={handlePress}
127
+ disabled={disabled}
128
+ size={IconButtonSizeEnum.MEDIUM}
129
+ {...iconButtonTrigger}
130
+ />
131
+ </View>
132
+ );
133
+ }
134
+
135
+ return (
136
+ <Pressable
137
+ onPress={handlePress}
138
+ disabled={disabled}
139
+ className={dropdownStyle({ size, corner })}
140
+ >
141
+ <View className="flex-row justify-between items-center">
142
+ <View className="">
143
+ <View className="flex-col">
144
+ {label && (
145
+ <Typography
146
+ variant="label_small"
147
+ weight="600"
148
+ className="text-chia-900"
149
+ >
150
+ {label}
151
+ </Typography>
152
+ )}
153
+ </View>
154
+
155
+ {renderVariant()}
156
+ </View>
157
+
158
+ <View className="flex-row items-center gap-400">
159
+ {leftButtonText && (
160
+ <Typography
161
+ variant="label_medium"
162
+ weight="700"
163
+ >
164
+ {leftButtonText}
165
+ </Typography>
166
+ )}
167
+ <Animated.View
168
+ style={{
169
+ transform: [{ rotate }],
170
+ }}
171
+ >
172
+ <ArrowChevronDownStroke size={24} className="text-chia-900" />
173
+ </Animated.View>
174
+ </View>
175
+ </View>
176
+ </Pressable>
177
+ )
178
+ }
179
+
180
+ return (
181
+ <>
182
+ <View ref={triggerRef} className={className}>
183
+ {renderTrigger()}
184
+ </View>
185
+
186
+ <Modal
187
+ visible={isOpen}
188
+ transparent
189
+ animationType="fade"
190
+ onRequestClose={handleClose}
191
+ >
192
+ <TouchableWithoutFeedback onPress={handleClose}>
193
+ <View className="flex-1">
194
+ <TouchableWithoutFeedback>
195
+ <View
196
+ style={{
197
+ position: "absolute",
198
+ top: dropdownLayout.top,
199
+ left: dropdownLayout.left,
200
+ width: dropdownLayout.width,
201
+ zIndex: 9999,
202
+ }}
203
+ className="bg-white border border-gray-200 rounded-xl shadow-lg"
204
+ >
205
+ {children}
206
+ </View>
207
+ </TouchableWithoutFeedback>
208
+ </View>
209
+ </TouchableWithoutFeedback>
210
+ </Modal>
211
+ </>
212
+ );
213
+ }
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from "react";
2
+ import { IconButtonProps } from "../IconButton/types";
3
+ import { SizeEnum } from "../../enums";
4
+
5
+ export interface DropdownProps {
6
+ label?: string;
7
+ value?: string;
8
+ placeholder?: string;
9
+ disabled?: boolean;
10
+ className?: string;
11
+ leftButtonText?: string;
12
+ hidePlaceholder?: boolean;
13
+ children: ReactNode;
14
+ iconButtonTrigger?: IconButtonProps;
15
+ iconButtonAlign?: "left" | "right" | "center";
16
+ size?: SizeEnum.SMALL | SizeEnum.MEDIUM;
17
+ corner?: SizeEnum.SMALL | SizeEnum.MEDIUM;
18
+ }
@@ -0,0 +1,83 @@
1
+ import { cva } from "class-variance-authority";
2
+ import { SizeEnum } from "../../../enums";
3
+
4
+ const tabContainerVariants = cva(["flex-row w-full"], {
5
+ variants: {
6
+ size: {
7
+ [SizeEnum.MEDIUM]: "",
8
+ [SizeEnum.SMALL]: "",
9
+ },
10
+ },
11
+ defaultVariants: {
12
+ size: SizeEnum.MEDIUM,
13
+ },
14
+ });
15
+
16
+ const dividerVariants = cva(
17
+ [
18
+ "w-full",
19
+ ],
20
+ {
21
+ variants: {
22
+ selected: {
23
+ true: "h-200 bg-grape-500",
24
+ false: "h-[1px] bg-chia-400",
25
+ },
26
+ size: {
27
+ [SizeEnum.MEDIUM]: "mt-500",
28
+ [SizeEnum.SMALL]: "mt-400",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ selected: false,
33
+ size: SizeEnum.MEDIUM,
34
+ },
35
+ }
36
+ );
37
+
38
+ const tabLabelVariants = cva("", {
39
+ variants: {
40
+ selected: {
41
+ true: "text-chia-900",
42
+ false: "text-chia-700",
43
+ },
44
+ },
45
+ defaultVariants: {
46
+ selected: false,
47
+ },
48
+ });
49
+
50
+ const tabCountVariants = cva(
51
+ ["px-300 rounded-300 items-center justify-center ml-400"],
52
+ {
53
+ variants: {
54
+ selected: {
55
+ true: "bg-grape-500",
56
+ false: "bg-chia-400",
57
+ },
58
+ },
59
+ defaultVariants: {
60
+ selected: false,
61
+ },
62
+ }
63
+ );
64
+
65
+ const tabCountTextVariants = cva("", {
66
+ variants: {
67
+ selected: {
68
+ true: "text-chia-100",
69
+ false: "text-chia-700",
70
+ },
71
+ },
72
+ defaultVariants: {
73
+ selected: false,
74
+ },
75
+ });
76
+
77
+ export {
78
+ tabContainerVariants,
79
+ dividerVariants,
80
+ tabLabelVariants,
81
+ tabCountVariants,
82
+ tabCountTextVariants,
83
+ };
@@ -0,0 +1,92 @@
1
+ import { Pressable, View } from "react-native";
2
+ import { merge } from "@kivid/tailwind-preset";
3
+ import type { TabProps } from "./types";
4
+ import {
5
+ tabContainerVariants,
6
+ dividerVariants,
7
+ tabLabelVariants,
8
+ tabCountVariants,
9
+ tabCountTextVariants,
10
+ } from "./assets/class-variants";
11
+ import { Typography } from "../Typography";
12
+ import { SizeEnum } from "../../enums";
13
+
14
+ export function Tab(props: TabProps) {
15
+ const {
16
+ items,
17
+ onTabChange,
18
+ size = SizeEnum.MEDIUM,
19
+ className,
20
+ selectedTab,
21
+ customDividerColor,
22
+ customDividerComponent,
23
+ } = props;
24
+
25
+ const handleTabPress = (index: number) => {
26
+ onTabChange?.(index);
27
+ };
28
+
29
+ const containerStyle = merge(tabContainerVariants({ size }), className);
30
+
31
+ return (
32
+ <View className={containerStyle} accessibilityRole="tablist">
33
+ {items.map((item, index) => {
34
+ const selected = selectedTab === index;
35
+ const buttonStyle = merge("flex-1 flex-col items-center justify-center", className);
36
+ const labelStyle = tabLabelVariants({ selected });
37
+ const countTextStyle = tabCountTextVariants({ selected });
38
+
39
+ const dividerStyle = (selected && customDividerColor)
40
+ ? merge(dividerVariants({ selected, size }), customDividerColor)
41
+ : dividerVariants({ selected, size });
42
+
43
+ const countContainerStyle = (selected && customDividerColor)
44
+ ? merge(tabCountVariants({ selected }), customDividerColor)
45
+ : tabCountVariants({ selected });
46
+
47
+ const renderDivider = () => {
48
+ if (selected && customDividerComponent) {
49
+ return customDividerComponent;
50
+ }
51
+
52
+ return (
53
+ <View className={dividerStyle} />
54
+ )
55
+ };
56
+
57
+ return (
58
+ <Pressable
59
+ key={index}
60
+ testID={`tab-${index}`}
61
+ className={buttonStyle}
62
+ onPress={() => handleTabPress(index)}
63
+ accessibilityRole="tab"
64
+ accessibilityState={{ selected }}
65
+ >
66
+ <View className="flex flex-row">
67
+ <Typography
68
+ variant={size === SizeEnum.MEDIUM ? "label_medium" : "label_small"}
69
+ weight="700"
70
+ className={labelStyle}
71
+ >
72
+ {item.label}
73
+ </Typography>
74
+ {item.count !== undefined && (
75
+ <View className={countContainerStyle}>
76
+ <Typography
77
+ variant="label_small"
78
+ weight="700"
79
+ className={countTextStyle}
80
+ >
81
+ {item.count}
82
+ </Typography>
83
+ </View>
84
+ )}
85
+ </View>
86
+ {renderDivider()}
87
+ </Pressable>
88
+ );
89
+ })}
90
+ </View>
91
+ );
92
+ }
@@ -0,0 +1,20 @@
1
+ import { ReactNode } from "react";
2
+ import { SizeEnum } from "../../enums";
3
+
4
+ export type TabSize = SizeEnum.SMALL | SizeEnum.MEDIUM;
5
+
6
+ export interface TabItem {
7
+ label: string;
8
+ count?: number;
9
+ }
10
+
11
+ export interface TabProps{
12
+ items: TabItem[];
13
+ onTabChange: (index: number) => void;
14
+ size?: TabSize;
15
+ className?: string;
16
+ customDividerColor?: string;
17
+ customDividerComponent?: ReactNode;
18
+ selectedTab: number;
19
+ selected?: boolean;
20
+ }
@@ -3,7 +3,7 @@ import type { MarkerProps } from "./types";
3
3
  import { SizeEnum } from "../../../../enums";
4
4
 
5
5
  export function Marker(props: MarkerProps) {
6
- const { size = SizeEnum.MEDIUM, color = "chia" } = props;
6
+ const { size = SizeEnum.MEDIUM, color = "chia", customMarkerComponent } = props;
7
7
 
8
8
  const mappedSize = {
9
9
  [SizeEnum.SMALL]: "w-700 h-300",
@@ -22,5 +22,13 @@ export function Marker(props: MarkerProps) {
22
22
  ghost: "bg-chia-200",
23
23
  }[color];
24
24
 
25
- return <View className={`${mappedColor} ${mappedSize} rounded-500`} />;
25
+ function renderMarker() {
26
+ if (customMarkerComponent) {
27
+ return customMarkerComponent
28
+ }
29
+
30
+ return <View className={`${mappedColor} ${mappedSize} rounded-500`} />;
31
+ }
32
+
33
+ return renderMarker();
26
34
  }
@@ -3,6 +3,7 @@ import { SizeEnum } from "../../../../enums";
3
3
  export type MarkerSize = SizeEnum.SMALL | SizeEnum.MEDIUM;
4
4
 
5
5
  export interface MarkerProps {
6
+ customMarkerComponent?: React.ReactNode;
6
7
  size?: MarkerSize;
7
8
  color?:
8
9
  | "pear"
@@ -20,7 +20,7 @@ const toastVariants = cva(
20
20
  const containerVariants = cva("absolute z-[800px] w-full min-h-12 flex", {
21
21
  variants: {
22
22
  position: {
23
- [ToastPositionEnum.TOP]: "top-1000",
23
+ [ToastPositionEnum.TOP]: "top-1000 mt-700",
24
24
  [ToastPositionEnum.BOTTOM]: "bottom-1000",
25
25
  },
26
26
  },
@@ -86,3 +86,9 @@ export type * from "./MessageInput/types";
86
86
 
87
87
  export * from "./DatePicker";
88
88
  export type * from "./DatePicker/types";
89
+
90
+ export * from "./Tab";
91
+ export type * from "./Tab/types";
92
+
93
+ export * from "./Dropdown";
94
+ export type * from "./Dropdown/types";