@kaushverse/pickify 1.0.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.
@@ -0,0 +1,54 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { ViewStyle, TextStyle } from 'react-native';
4
+
5
+ type Option = {
6
+ label: string;
7
+ value: string;
8
+ };
9
+ type Group = {
10
+ label: string;
11
+ data: Option[];
12
+ };
13
+ type Theme = {
14
+ primaryColor?: string;
15
+ backgroundColor?: string;
16
+ textColor?: string;
17
+ };
18
+ type PickerStyles = {
19
+ container?: ViewStyle;
20
+ tab?: ViewStyle;
21
+ activeTab?: ViewStyle;
22
+ tabText?: TextStyle;
23
+ activeTabText?: TextStyle;
24
+ doneBtn?: ViewStyle;
25
+ doneText?: TextStyle;
26
+ selectTab?: ViewStyle;
27
+ selectTabText?: TextStyle;
28
+ };
29
+ type Props = {
30
+ visible: boolean;
31
+ selectedValue: string;
32
+ options: Option[];
33
+ groups?: Group[];
34
+ styles?: PickerStyles;
35
+ theme?: Theme;
36
+ renderTab?: (tab: Group, isActive: boolean, onPress: () => void) => React.ReactNode;
37
+ renderItem?: (item: Option, isSelected: boolean) => React.ReactNode;
38
+ renderContainer?: (children: React.ReactNode) => React.ReactNode;
39
+ renderIcon?: (props: {
40
+ name: string;
41
+ size: number;
42
+ color: string;
43
+ }) => React.ReactNode;
44
+ onSelect: (value: string) => void;
45
+ onClose: () => void;
46
+ };
47
+
48
+ declare function PickerModal({ visible, selectedValue, options, groups, styles, theme, renderTab, renderItem, renderContainer, onSelect, onClose, renderIcon, variant, }: Props & {
49
+ variant?: "tabs" | "input";
50
+ }): react_jsx_runtime.JSX.Element;
51
+
52
+ declare const groupOptions: (options: Option[], config: Record<string, string[]>) => Group[];
53
+
54
+ export { type Group, type Option, PickerModal, type PickerStyles, type Props, type Theme, groupOptions };
@@ -0,0 +1,54 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { ViewStyle, TextStyle } from 'react-native';
4
+
5
+ type Option = {
6
+ label: string;
7
+ value: string;
8
+ };
9
+ type Group = {
10
+ label: string;
11
+ data: Option[];
12
+ };
13
+ type Theme = {
14
+ primaryColor?: string;
15
+ backgroundColor?: string;
16
+ textColor?: string;
17
+ };
18
+ type PickerStyles = {
19
+ container?: ViewStyle;
20
+ tab?: ViewStyle;
21
+ activeTab?: ViewStyle;
22
+ tabText?: TextStyle;
23
+ activeTabText?: TextStyle;
24
+ doneBtn?: ViewStyle;
25
+ doneText?: TextStyle;
26
+ selectTab?: ViewStyle;
27
+ selectTabText?: TextStyle;
28
+ };
29
+ type Props = {
30
+ visible: boolean;
31
+ selectedValue: string;
32
+ options: Option[];
33
+ groups?: Group[];
34
+ styles?: PickerStyles;
35
+ theme?: Theme;
36
+ renderTab?: (tab: Group, isActive: boolean, onPress: () => void) => React.ReactNode;
37
+ renderItem?: (item: Option, isSelected: boolean) => React.ReactNode;
38
+ renderContainer?: (children: React.ReactNode) => React.ReactNode;
39
+ renderIcon?: (props: {
40
+ name: string;
41
+ size: number;
42
+ color: string;
43
+ }) => React.ReactNode;
44
+ onSelect: (value: string) => void;
45
+ onClose: () => void;
46
+ };
47
+
48
+ declare function PickerModal({ visible, selectedValue, options, groups, styles, theme, renderTab, renderItem, renderContainer, onSelect, onClose, renderIcon, variant, }: Props & {
49
+ variant?: "tabs" | "input";
50
+ }): react_jsx_runtime.JSX.Element;
51
+
52
+ declare const groupOptions: (options: Option[], config: Record<string, string[]>) => Group[];
53
+
54
+ export { type Group, type Option, PickerModal, type PickerStyles, type Props, type Theme, groupOptions };
package/dist/index.js ADDED
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ PickerModal: () => PickerModal,
24
+ groupOptions: () => groupOptions
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/core/PickerModel.tsx
29
+ var import_react = require("react");
30
+ var import_react_native = require("react-native");
31
+ var import_picker = require("@react-native-picker/picker");
32
+ var import_jsx_runtime = require("react/jsx-runtime");
33
+ function PickerModal({
34
+ visible,
35
+ selectedValue,
36
+ options,
37
+ groups = [],
38
+ styles,
39
+ theme,
40
+ renderTab,
41
+ renderItem,
42
+ renderContainer,
43
+ onSelect,
44
+ onClose,
45
+ renderIcon,
46
+ variant = "tabs"
47
+ }) {
48
+ const [activeTab, setActiveTab] = (0, import_react.useState)(0);
49
+ const hasGroups = groups.length > 0;
50
+ const isInputVariant = variant === "input";
51
+ const currentOptions = hasGroups ? groups[activeTab]?.data || [] : options;
52
+ (0, import_react.useEffect)(() => {
53
+ if (!hasGroups) return;
54
+ const index = groups.findIndex(
55
+ (group) => group.data.some((item) => item.value === selectedValue)
56
+ );
57
+ if (index !== -1) setActiveTab(index);
58
+ }, [selectedValue, visible]);
59
+ const primary = theme?.primaryColor || "#6366f1";
60
+ const bg = theme?.backgroundColor || "#fff";
61
+ const text = theme?.textColor || "#111827";
62
+ const content = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
63
+ import_react_native.View,
64
+ {
65
+ style: [
66
+ defaultStyles.container,
67
+ { backgroundColor: bg },
68
+ styles?.container
69
+ ],
70
+ children: [
71
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
72
+ import_react_native.TouchableOpacity,
73
+ {
74
+ style: [
75
+ defaultStyles.doneBtn,
76
+ { backgroundColor: primary },
77
+ styles?.doneBtn
78
+ ],
79
+ onPress: onClose,
80
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Text, { style: [defaultStyles.doneText, styles?.doneText], children: "Done" })
81
+ }
82
+ ),
83
+ hasGroups && !isInputVariant && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: groups.map((tab, index) => {
84
+ const isActive = activeTab === index;
85
+ if (renderTab) {
86
+ return renderTab(tab, isActive, () => setActiveTab(index));
87
+ }
88
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
89
+ import_react_native.TouchableOpacity,
90
+ {
91
+ style: [
92
+ defaultStyles.tab,
93
+ styles?.tab,
94
+ isActive && {
95
+ backgroundColor: primary
96
+ }
97
+ ],
98
+ onPress: () => setActiveTab(index),
99
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
100
+ import_react_native.Text,
101
+ {
102
+ style: [
103
+ defaultStyles.tabText,
104
+ { color: isActive ? "#fff" : text },
105
+ styles?.tabText
106
+ ],
107
+ children: tab.label
108
+ }
109
+ )
110
+ },
111
+ tab.label
112
+ );
113
+ }) }),
114
+ hasGroups && isInputVariant && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: groups.map((tab, index) => {
115
+ const isActive = activeTab === index;
116
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
117
+ import_react_native.TouchableOpacity,
118
+ {
119
+ style: [
120
+ defaultStyles.selectTab,
121
+ styles?.selectTab,
122
+ isActive && { borderColor: primary }
123
+ ],
124
+ onPress: () => setActiveTab(index),
125
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: defaultStyles.selectTabInner, children: [
126
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
127
+ import_react_native.Text,
128
+ {
129
+ style: [defaultStyles.selectTabText, styles?.selectTabText],
130
+ children: tab.label
131
+ }
132
+ ),
133
+ renderIcon?.({
134
+ name: "chevron-down",
135
+ size: 18,
136
+ color: "#6B7280"
137
+ })
138
+ ] })
139
+ },
140
+ tab.label
141
+ );
142
+ }) }),
143
+ renderItem ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.ScrollView, { style: { maxHeight: 250 }, children: currentOptions.map(
144
+ (item) => renderItem(item, selectedValue === item.value)
145
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_picker.Picker, { selectedValue, onValueChange: onSelect, children: currentOptions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
146
+ import_picker.Picker.Item,
147
+ {
148
+ label: item.label,
149
+ value: item.value,
150
+ color: text
151
+ },
152
+ item.value
153
+ )) })
154
+ ]
155
+ }
156
+ );
157
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.Modal, { visible, transparent: true, animationType: "slide", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: defaultStyles.modalOverlay, children: renderContainer ? renderContainer(content) : content }) });
158
+ }
159
+ var defaultStyles = import_react_native.StyleSheet.create({
160
+ modalOverlay: {
161
+ flex: 1,
162
+ justifyContent: "flex-end",
163
+ backgroundColor: "rgba(0,0,0,0.3)"
164
+ },
165
+ container: {
166
+ borderTopLeftRadius: 20,
167
+ borderTopRightRadius: 20,
168
+ padding: 20
169
+ },
170
+ /* ---------- NORMAL TABS ---------- */
171
+ tab: {
172
+ paddingHorizontal: 16,
173
+ paddingVertical: 8,
174
+ borderRadius: 20,
175
+ marginRight: 8,
176
+ backgroundColor: "#f3f4f6"
177
+ },
178
+ tabText: {
179
+ fontSize: 13,
180
+ fontWeight: "500"
181
+ },
182
+ /* ---------- INPUT STYLE TABS ---------- */
183
+ selectTab: {
184
+ height: 48,
185
+ borderWidth: 1,
186
+ borderColor: "#E5E7EB",
187
+ borderRadius: 12,
188
+ paddingHorizontal: 14,
189
+ flexDirection: "row",
190
+ justifyContent: "space-between",
191
+ alignItems: "center"
192
+ },
193
+ selectTabInner: {
194
+ flexDirection: "row",
195
+ justifyContent: "space-between",
196
+ alignItems: "center"
197
+ },
198
+ selectTabText: {
199
+ fontSize: 16,
200
+ fontWeight: "500"
201
+ },
202
+ /* ---------- DONE BUTTON ---------- */
203
+ doneBtn: {
204
+ alignSelf: "flex-end",
205
+ paddingHorizontal: 14,
206
+ paddingVertical: 6,
207
+ borderRadius: 30,
208
+ marginBottom: 20
209
+ },
210
+ doneText: {
211
+ color: "#FFF",
212
+ fontWeight: "600"
213
+ }
214
+ });
215
+
216
+ // src/utils/groupOptions.ts
217
+ var groupOptions = (options, config) => {
218
+ return Object.entries(config).map(([label, values]) => ({
219
+ label,
220
+ data: options.filter((o) => values.includes(o.value))
221
+ })).filter((g) => g.data.length > 0);
222
+ };
223
+ // Annotate the CommonJS export names for ESM import in node:
224
+ 0 && (module.exports = {
225
+ PickerModal,
226
+ groupOptions
227
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,206 @@
1
+ // src/core/PickerModel.tsx
2
+ import { useEffect, useState } from "react";
3
+ import {
4
+ Modal,
5
+ View,
6
+ Text,
7
+ TouchableOpacity,
8
+ StyleSheet,
9
+ ScrollView
10
+ } from "react-native";
11
+ import { Picker } from "@react-native-picker/picker";
12
+ import { jsx, jsxs } from "react/jsx-runtime";
13
+ function PickerModal({
14
+ visible,
15
+ selectedValue,
16
+ options,
17
+ groups = [],
18
+ styles,
19
+ theme,
20
+ renderTab,
21
+ renderItem,
22
+ renderContainer,
23
+ onSelect,
24
+ onClose,
25
+ renderIcon,
26
+ variant = "tabs"
27
+ }) {
28
+ const [activeTab, setActiveTab] = useState(0);
29
+ const hasGroups = groups.length > 0;
30
+ const isInputVariant = variant === "input";
31
+ const currentOptions = hasGroups ? groups[activeTab]?.data || [] : options;
32
+ useEffect(() => {
33
+ if (!hasGroups) return;
34
+ const index = groups.findIndex(
35
+ (group) => group.data.some((item) => item.value === selectedValue)
36
+ );
37
+ if (index !== -1) setActiveTab(index);
38
+ }, [selectedValue, visible]);
39
+ const primary = theme?.primaryColor || "#6366f1";
40
+ const bg = theme?.backgroundColor || "#fff";
41
+ const text = theme?.textColor || "#111827";
42
+ const content = /* @__PURE__ */ jsxs(
43
+ View,
44
+ {
45
+ style: [
46
+ defaultStyles.container,
47
+ { backgroundColor: bg },
48
+ styles?.container
49
+ ],
50
+ children: [
51
+ /* @__PURE__ */ jsx(
52
+ TouchableOpacity,
53
+ {
54
+ style: [
55
+ defaultStyles.doneBtn,
56
+ { backgroundColor: primary },
57
+ styles?.doneBtn
58
+ ],
59
+ onPress: onClose,
60
+ children: /* @__PURE__ */ jsx(Text, { style: [defaultStyles.doneText, styles?.doneText], children: "Done" })
61
+ }
62
+ ),
63
+ hasGroups && !isInputVariant && /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: groups.map((tab, index) => {
64
+ const isActive = activeTab === index;
65
+ if (renderTab) {
66
+ return renderTab(tab, isActive, () => setActiveTab(index));
67
+ }
68
+ return /* @__PURE__ */ jsx(
69
+ TouchableOpacity,
70
+ {
71
+ style: [
72
+ defaultStyles.tab,
73
+ styles?.tab,
74
+ isActive && {
75
+ backgroundColor: primary
76
+ }
77
+ ],
78
+ onPress: () => setActiveTab(index),
79
+ children: /* @__PURE__ */ jsx(
80
+ Text,
81
+ {
82
+ style: [
83
+ defaultStyles.tabText,
84
+ { color: isActive ? "#fff" : text },
85
+ styles?.tabText
86
+ ],
87
+ children: tab.label
88
+ }
89
+ )
90
+ },
91
+ tab.label
92
+ );
93
+ }) }),
94
+ hasGroups && isInputVariant && /* @__PURE__ */ jsx(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, children: groups.map((tab, index) => {
95
+ const isActive = activeTab === index;
96
+ return /* @__PURE__ */ jsx(
97
+ TouchableOpacity,
98
+ {
99
+ style: [
100
+ defaultStyles.selectTab,
101
+ styles?.selectTab,
102
+ isActive && { borderColor: primary }
103
+ ],
104
+ onPress: () => setActiveTab(index),
105
+ children: /* @__PURE__ */ jsxs(View, { style: defaultStyles.selectTabInner, children: [
106
+ /* @__PURE__ */ jsx(
107
+ Text,
108
+ {
109
+ style: [defaultStyles.selectTabText, styles?.selectTabText],
110
+ children: tab.label
111
+ }
112
+ ),
113
+ renderIcon?.({
114
+ name: "chevron-down",
115
+ size: 18,
116
+ color: "#6B7280"
117
+ })
118
+ ] })
119
+ },
120
+ tab.label
121
+ );
122
+ }) }),
123
+ renderItem ? /* @__PURE__ */ jsx(ScrollView, { style: { maxHeight: 250 }, children: currentOptions.map(
124
+ (item) => renderItem(item, selectedValue === item.value)
125
+ ) }) : /* @__PURE__ */ jsx(Picker, { selectedValue, onValueChange: onSelect, children: currentOptions.map((item) => /* @__PURE__ */ jsx(
126
+ Picker.Item,
127
+ {
128
+ label: item.label,
129
+ value: item.value,
130
+ color: text
131
+ },
132
+ item.value
133
+ )) })
134
+ ]
135
+ }
136
+ );
137
+ return /* @__PURE__ */ jsx(Modal, { visible, transparent: true, animationType: "slide", children: /* @__PURE__ */ jsx(View, { style: defaultStyles.modalOverlay, children: renderContainer ? renderContainer(content) : content }) });
138
+ }
139
+ var defaultStyles = StyleSheet.create({
140
+ modalOverlay: {
141
+ flex: 1,
142
+ justifyContent: "flex-end",
143
+ backgroundColor: "rgba(0,0,0,0.3)"
144
+ },
145
+ container: {
146
+ borderTopLeftRadius: 20,
147
+ borderTopRightRadius: 20,
148
+ padding: 20
149
+ },
150
+ /* ---------- NORMAL TABS ---------- */
151
+ tab: {
152
+ paddingHorizontal: 16,
153
+ paddingVertical: 8,
154
+ borderRadius: 20,
155
+ marginRight: 8,
156
+ backgroundColor: "#f3f4f6"
157
+ },
158
+ tabText: {
159
+ fontSize: 13,
160
+ fontWeight: "500"
161
+ },
162
+ /* ---------- INPUT STYLE TABS ---------- */
163
+ selectTab: {
164
+ height: 48,
165
+ borderWidth: 1,
166
+ borderColor: "#E5E7EB",
167
+ borderRadius: 12,
168
+ paddingHorizontal: 14,
169
+ flexDirection: "row",
170
+ justifyContent: "space-between",
171
+ alignItems: "center"
172
+ },
173
+ selectTabInner: {
174
+ flexDirection: "row",
175
+ justifyContent: "space-between",
176
+ alignItems: "center"
177
+ },
178
+ selectTabText: {
179
+ fontSize: 16,
180
+ fontWeight: "500"
181
+ },
182
+ /* ---------- DONE BUTTON ---------- */
183
+ doneBtn: {
184
+ alignSelf: "flex-end",
185
+ paddingHorizontal: 14,
186
+ paddingVertical: 6,
187
+ borderRadius: 30,
188
+ marginBottom: 20
189
+ },
190
+ doneText: {
191
+ color: "#FFF",
192
+ fontWeight: "600"
193
+ }
194
+ });
195
+
196
+ // src/utils/groupOptions.ts
197
+ var groupOptions = (options, config) => {
198
+ return Object.entries(config).map(([label, values]) => ({
199
+ label,
200
+ data: options.filter((o) => values.includes(o.value))
201
+ })).filter((g) => g.data.length > 0);
202
+ };
203
+ export {
204
+ PickerModal,
205
+ groupOptions
206
+ };
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@kaushverse/pickify",
3
+ "version": "1.0.0",
4
+ "description": "A fully customizable React Native picker with search, multi-select, grouping, and async support.",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup src/index.ts --format cjs,esm --dts",
20
+ "clean": "rimraf dist",
21
+ "prepublishOnly": "npm run clean && npm run build"
22
+ },
23
+ "keywords": [
24
+ "react-native",
25
+ "picker",
26
+ "select",
27
+ "dropdown",
28
+ "modal",
29
+ "multi-select",
30
+ "search",
31
+ "grouped-picker",
32
+ "react-native-picker",
33
+ "react-native-select",
34
+ "ui",
35
+ "component",
36
+ "typescript"
37
+ ],
38
+ "author": "Kaushik",
39
+ "license": "MIT",
40
+ "homepage": "https://github.com/kaushverse/pickify",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/kaushverse/pickify.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/kaushverse/pickify/issues"
47
+ },
48
+ "peerDependencies": {
49
+ "react": ">=17",
50
+ "react-native": ">=0.70"
51
+ },
52
+ "dependencies": {
53
+ "@react-native-picker/picker": "^2.11.4"
54
+ },
55
+ "devDependencies": {
56
+ "@types/react": "^19.2.14",
57
+ "react": "^19.2.4",
58
+ "react-native": "^0.84.1",
59
+ "rimraf": "^6.1.3",
60
+ "tsup": "^8.5.1",
61
+ "typescript": "^5.9.3"
62
+ }
63
+ }