ripal-ui 1.1.394 → 2.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.
Files changed (65) hide show
  1. package/README.md +3 -0
  2. package/components/Alert.jsx +74 -0
  3. package/components/Avatar.jsx +157 -0
  4. package/components/Button.jsx +58 -0
  5. package/components/COLORS.js +138 -0
  6. package/components/Checkbox.jsx +51 -0
  7. package/components/Dialog.jsx +221 -0
  8. package/components/Divider.jsx +62 -0
  9. package/components/Dropdown.jsx +229 -0
  10. package/components/Inline.jsx +37 -0
  11. package/components/Input.jsx +89 -0
  12. package/components/Rate.jsx +39 -0
  13. package/components/Slider.jsx +219 -0
  14. package/components/Switch.jsx +45 -0
  15. package/components/Table.jsx +67 -0
  16. package/components/Text.jsx +56 -0
  17. package/components/Toggle.jsx +88 -0
  18. package/index.js +16 -2
  19. package/package.json +20 -20
  20. package/babel.config.js +0 -3
  21. package/components/BottomSheet.tsx +0 -197
  22. package/components/Carousel.tsx +0 -61
  23. package/components/Circle.tsx +0 -44
  24. package/components/DatePicker.jsx +0 -181
  25. package/components/Tab.tsx +0 -90
  26. package/components/Table.tsx +0 -95
  27. package/components/index.ts +0 -5
  28. package/config.js +0 -4
  29. package/dist/BottomSheet.js +0 -186
  30. package/dist/Button.js +0 -109
  31. package/dist/Carousel.js +0 -52
  32. package/dist/Circle.js +0 -42
  33. package/dist/DatePicker.js +0 -199
  34. package/dist/Dialog.js +0 -81
  35. package/dist/Dropdown.js +0 -97
  36. package/dist/Inline.js +0 -38
  37. package/dist/Input.js +0 -88
  38. package/dist/ProgressBar.js +0 -64
  39. package/dist/Separator.js +0 -47
  40. package/dist/Skeleton.js +0 -62
  41. package/dist/Switch.js +0 -74
  42. package/dist/Tab.js +0 -85
  43. package/dist/Table.js +0 -96
  44. package/dist/Text.js +0 -78
  45. package/dist/Toast.js +0 -72
  46. package/dist/Toggle.js +0 -54
  47. package/dist/index.js +0 -96
  48. package/elements/Button.tsx +0 -121
  49. package/elements/ColorPicker.tsx +0 -70
  50. package/elements/Dialog.tsx +0 -87
  51. package/elements/Dropdown.tsx +0 -88
  52. package/elements/Inline.tsx +0 -52
  53. package/elements/Input.tsx +0 -83
  54. package/elements/ProgressBar.tsx +0 -52
  55. package/elements/SecureStorage.js +0 -27
  56. package/elements/Separator.tsx +0 -71
  57. package/elements/Skeleton.tsx +0 -64
  58. package/elements/Slider.tsx +0 -133
  59. package/elements/Switch.tsx +0 -63
  60. package/elements/Text.tsx +0 -95
  61. package/elements/Toast.tsx +0 -71
  62. package/elements/Toggle.tsx +0 -59
  63. package/elements/index.js +0 -14
  64. package/index.d.ts +0 -237
  65. package/scripts/generateConfig.js +0 -80
@@ -0,0 +1,219 @@
1
+ import MaterialIcons from "@react-native-vector-icons/material-icons";
2
+ import React, { useRef, useState } from "react";
3
+ import { View, StyleSheet, PanResponder } from "react-native";
4
+
5
+ const Slider = ({
6
+ height = 20,
7
+ value = 0,
8
+ range = false,
9
+ onChange = () => {},
10
+ min = 0,
11
+ max = 100,
12
+ thumbRadius = 6,
13
+ }) => {
14
+
15
+ const trackWidth = useRef(0);
16
+
17
+ const [state, setState] = useState(
18
+ range
19
+ ? { min: value[0], max: value[1] }
20
+ : { value }
21
+ );
22
+
23
+ const clamp = (v, minv, maxv) =>
24
+ Math.min(maxv, Math.max(minv, v));
25
+
26
+ const percentToValue = (p) =>
27
+ min + p * (max - min);
28
+
29
+ const valueToPercent = (v) =>
30
+ (v - min) / (max - min);
31
+
32
+ const activeThumb = useRef(null);
33
+
34
+ const updateFromGesture = (x) => {
35
+
36
+ const percent = clamp(x / trackWidth.current, 0, 1);
37
+ const newValue = percentToValue(percent);
38
+
39
+ if (range) {
40
+
41
+ if (activeThumb.current === "min") {
42
+
43
+ const v = clamp(newValue, min, state.max);
44
+
45
+ setState(s => ({ ...s, min: v }));
46
+ onChange([v, state.max]);
47
+
48
+ } else {
49
+
50
+ const v = clamp(newValue, state.min, max);
51
+
52
+ setState(s => ({ ...s, max: v }));
53
+ onChange([state.min, v]);
54
+
55
+ }
56
+
57
+ } else {
58
+
59
+ setState({ value: newValue });
60
+ onChange(newValue);
61
+
62
+ }
63
+
64
+ };
65
+
66
+ const panResponder = useRef(
67
+ PanResponder.create({
68
+
69
+ onStartShouldSetPanResponder: () => true,
70
+ onMoveShouldSetPanResponder: () => true,
71
+
72
+ onPanResponderGrant: (evt) => {
73
+
74
+ const x = evt.nativeEvent.locationX;
75
+
76
+ if (range) {
77
+
78
+ const percent = x / trackWidth.current;
79
+
80
+ const distMin = Math.abs(percent - valueToPercent(state.min));
81
+ const distMax = Math.abs(percent - valueToPercent(state.max));
82
+
83
+ activeThumb.current =
84
+ distMin < distMax ? "min" : "max";
85
+
86
+ } else {
87
+ activeThumb.current = "single";
88
+ }
89
+
90
+ updateFromGesture(x);
91
+
92
+ },
93
+
94
+ onPanResponderMove: (evt) => {
95
+
96
+ updateFromGesture(evt.nativeEvent.locationX);
97
+
98
+ },
99
+
100
+ onPanResponderTerminationRequest: () => false,
101
+ onPanResponderTerminate: () => {},
102
+ onShouldBlockNativeResponder: () => true,
103
+
104
+ })
105
+ ).current;
106
+
107
+ const percentMin = range
108
+ ? valueToPercent(state.min)
109
+ : valueToPercent(state.value);
110
+
111
+ const percentMax = range
112
+ ? valueToPercent(state.max)
113
+ : null;
114
+
115
+ return (
116
+
117
+ <View style={styles.container}>
118
+ <View
119
+ style={[styles.track, { height }]}
120
+ {...panResponder.panHandlers}
121
+ onLayout={(e) => {
122
+ trackWidth.current =
123
+ e.nativeEvent.layout.width;
124
+ }}
125
+ >
126
+
127
+ <View
128
+ style={[
129
+ styles.fill,
130
+ range
131
+ ? {
132
+ left: `${percentMin * 100}%`,
133
+ width: `${(percentMax - percentMin) * 100}%`
134
+ }
135
+ : {
136
+ width: `${percentMin * 100}%`
137
+ }
138
+ ]}
139
+ />
140
+
141
+ <View
142
+ style={[
143
+ styles.thumb,
144
+ {
145
+ left: `${percentMin * 100}%`,
146
+ height: height + 10,
147
+ width: height * 1.25,
148
+ marginLeft: -(height * 0.6),
149
+ borderRadius: thumbRadius
150
+ }
151
+ ]}
152
+ >
153
+ <MaterialIcons
154
+ name="drag-indicator"
155
+ size={height * 0.75}
156
+ color="#888"
157
+ />
158
+ </View>
159
+
160
+ {range && (
161
+ <View
162
+ style={[
163
+ styles.thumb,
164
+ {
165
+ left: `${percentMax * 100}%`,
166
+ height: height + 10,
167
+ width: height * 1.25,
168
+ marginLeft: -(height * 0.6),
169
+ borderRadius: thumbRadius
170
+ }
171
+ ]}
172
+ >
173
+ <MaterialIcons
174
+ name="drag-indicator"
175
+ size={height * 0.75}
176
+ color="#888"
177
+ />
178
+ </View>
179
+ )}
180
+
181
+ </View>
182
+
183
+ </View>
184
+
185
+ );
186
+ };
187
+
188
+ const styles = StyleSheet.create({
189
+
190
+ container: {
191
+ justifyContent: "center"
192
+ },
193
+
194
+ track: {
195
+ width: "100%",
196
+ backgroundColor: "#eee",
197
+ borderRadius: 999,
198
+ justifyContent: "center"
199
+ },
200
+
201
+ fill: {
202
+ position: "absolute",
203
+ height: "100%",
204
+ backgroundColor: "#3b82f6",
205
+ borderRadius: 999
206
+ },
207
+
208
+ thumb: {
209
+ position: "absolute",
210
+ backgroundColor: "#fff",
211
+ borderWidth: 1,
212
+ borderColor: "#ddd",
213
+ alignItems: "center",
214
+ justifyContent: "center"
215
+ }
216
+
217
+ });
218
+
219
+ export default Slider;
@@ -0,0 +1,45 @@
1
+ import React, { useState } from "react";
2
+ import Inline from "./Inline";
3
+ import { StyleSheet, View } from "react-native";
4
+ import COLORS from "./COLORS";
5
+ import Text from "./Text";
6
+
7
+ const Switch = ({active, setActive, size = 24}) => {
8
+
9
+ return (
10
+ <Inline>
11
+ <Inline style={[
12
+ styles.container,
13
+ {
14
+ width: ((size + 15) * 2) - 5,
15
+ backgroundColor: active ? COLORS.green[500] : COLORS.gray[300]
16
+ }
17
+ ]} justifyContent={active ? 'flex-end' : 'flex-start'} onPress={() => {
18
+ setActive(!active);
19
+ }}>
20
+ <View style={[
21
+ styles.btn,
22
+ {
23
+ height: size,
24
+ width: size + 15,
25
+ }
26
+ ]} />
27
+ </Inline>
28
+ </Inline>
29
+ )
30
+ }
31
+
32
+ const styles = StyleSheet.create({
33
+ container: {
34
+ backgroundColor: COLORS.slate[200],
35
+ padding: 5,
36
+ borderRadius: 999,
37
+ },
38
+ btn: {
39
+ width: '100%',
40
+ backgroundColor: '#fff',
41
+ borderRadius: 99,
42
+ }
43
+ })
44
+
45
+ export default Switch;
@@ -0,0 +1,67 @@
1
+ import React, { createContext, useContext, useState } from "react";
2
+ import { ScrollView, StyleSheet, View } from "react-native";
3
+ import Text from "./Text";
4
+ import Inline from "./Inline";
5
+ import COLORS from "./COLORS";
6
+
7
+ const TableContext = createContext(null);
8
+ const useTable = () => {
9
+ const ctx = useContext(TableContext);
10
+ if (!ctx) throw new Error("Table subcomponents must be used inside Table");
11
+ return ctx;
12
+ };
13
+
14
+ const Table = ({ children, colsWidth }) => {
15
+ const [width, setWidth] = useState(0);
16
+
17
+ return (
18
+ <TableContext.Provider value={{
19
+ colsWidth: colsWidth ?? [],
20
+ width,
21
+ }}>
22
+ <ScrollView showsHorizontalScrollIndicator={false} horizontal style={{height: 'auto'}} contentContainerStyle={{ flexDirection: 'column', height: 'auto' }} onLayout={e => {
23
+ setWidth(e.nativeEvent.layout.width);
24
+ }}>
25
+ {children}
26
+ </ScrollView>
27
+ </TableContext.Provider>
28
+ )
29
+ }
30
+
31
+ Table.Row = ({ children, isHeader }) => {
32
+ const { colsWidth } = useTable();
33
+
34
+ return (
35
+ <Inline style={{
36
+ ...styles.row,
37
+ backgroundColor: isHeader ? COLORS.slate[200] : '#ffffff00'
38
+ }}>
39
+ {children}
40
+ </Inline>
41
+ )
42
+ }
43
+ Table.Cell = ({ children, index }) => {
44
+ const { colsWidth, width } = useTable();
45
+
46
+ return (
47
+ <View style={{
48
+ width: colsWidth[index] ?? 'auto',
49
+ }}>
50
+ { typeof children === "string" ?
51
+ <Text>{children}</Text>
52
+ : children
53
+ }
54
+ </View>
55
+ )
56
+ }
57
+
58
+ const styles = StyleSheet.create({
59
+ row: {
60
+ padding: 10,
61
+ paddingHorizontal: 20,
62
+ borderRadius: 8,
63
+ }
64
+ })
65
+
66
+
67
+ export default Table;
@@ -0,0 +1,56 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Text as RNText } from "react-native";
3
+ import COLORS from "./COLORS";
4
+
5
+ const Text = ({ children, style, size, align, limit, spacing, lineHeight = null, color = COLORS.stone[600] }) => {
6
+ const [toRender, setToRender] = useState(children);
7
+
8
+ useEffect(() => {
9
+ if (!limit) {
10
+ setToRender(children);
11
+ return;
12
+ }
13
+
14
+ if (typeof children !== "string") {
15
+ setToRender(children);
16
+ return;
17
+ }
18
+
19
+ let truncated = children;
20
+ let isTruncated = false;
21
+
22
+ if (typeof limit === "number") {
23
+ if (children.length > limit) {
24
+ truncated = children.substring(0, limit);
25
+ isTruncated = true;
26
+ }
27
+ } else if (typeof limit === "object" && limit.count) {
28
+ const words = children.split(" ");
29
+ if (words.length > limit.count) {
30
+ truncated = words.slice(0, limit.count).join(" ");
31
+ isTruncated = true;
32
+ }
33
+ }
34
+
35
+ setToRender(isTruncated ? truncated + "..." : truncated);
36
+ }, [children, limit]);
37
+
38
+ return (
39
+ <RNText
40
+ style={[
41
+ {
42
+ fontSize: size,
43
+ textAlign: align,
44
+ lineHeight: lineHeight ?? undefined,
45
+ letterSpacing: spacing ?? undefined,
46
+ color,
47
+ },
48
+ style
49
+ ]}
50
+ >
51
+ {toRender}
52
+ </RNText>
53
+ );
54
+ };
55
+
56
+ export default Text;
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+ import { StyleSheet, TouchableOpacity } from "react-native";
3
+ import Inline from "./Inline";
4
+ import COLORS from "./COLORS";
5
+ import Text from "./Text";
6
+
7
+ const Toggle = ({ options = [], value = null, setValue, onChange, objectKey = null }) => {
8
+
9
+ const getOptionValue = (opt) => {
10
+ if (objectKey && typeof opt === 'object') {
11
+ return opt[objectKey];
12
+ }
13
+ return opt;
14
+ };
15
+
16
+ const isActive = (opt, index) => {
17
+ if (value === null) {
18
+ return index === 0;
19
+ }
20
+
21
+ // compare primitive directly
22
+ if (typeof opt !== 'object') {
23
+ return value === opt;
24
+ }
25
+
26
+ // compare object by key
27
+ if (objectKey) {
28
+ return value?.[objectKey] === opt?.[objectKey];
29
+ }
30
+
31
+ // fallback: strict reference
32
+ return value === opt;
33
+ };
34
+
35
+ const handlePress = (opt) => {
36
+ setValue?.(opt);
37
+ onChange?.(opt);
38
+ };
39
+
40
+ return (
41
+ <Inline>
42
+ <Inline gap={0} style={styles.area}>
43
+ {options.map((opt, index) => {
44
+
45
+ const active = isActive(opt, index);
46
+
47
+ return (
48
+ <TouchableOpacity
49
+ key={index}
50
+ onPress={() => handlePress(opt)}
51
+ style={[
52
+ styles.item,
53
+ active && styles.item_active
54
+ ]}
55
+ >
56
+ <Text size={13} color={active ? COLORS.primary : COLORS.slate[500]} style={{fontWeight: active ? '700' : '400'}}>
57
+ {getOptionValue(opt)}
58
+ </Text>
59
+ </TouchableOpacity>
60
+ );
61
+
62
+ })}
63
+ </Inline>
64
+ </Inline>
65
+ );
66
+ };
67
+
68
+ const styles = StyleSheet.create({
69
+ area: {
70
+ borderRadius: 999,
71
+ backgroundColor: COLORS.slate[100],
72
+ padding: 5,
73
+ },
74
+ item: {
75
+ padding: 10,
76
+ paddingHorizontal: 20,
77
+ borderRadius: 99,
78
+ },
79
+ item_active: {
80
+ backgroundColor: '#fff',
81
+ shadowColor: '#ddd',
82
+ shadowOpacity: 0.8,
83
+ shadowOffset: { width: 1, height: 1},
84
+ shadowRadius: 10,
85
+ }
86
+ });
87
+
88
+ export default Toggle;
package/index.js CHANGED
@@ -1,2 +1,16 @@
1
- export * from './elements';
2
- export * from './components';
1
+ export { default as Alert } from "./components/Alert";
2
+ export { default as Avatar } from "./components/Avatar";
3
+ export { default as Button } from "./components/Button";
4
+ export { default as Checkbox } from "./components/Checkbox";
5
+ export { default as COLORS } from "./components/COLORS";
6
+ export { default as Dialog } from "./components/Dialog";
7
+ export { default as Divider } from "./components/Divider";
8
+ export { default as Dropdown } from "./components/Dropdown";
9
+ export { default as Inline } from "./components/Inline";
10
+ export { default as Input } from "./components/Input";
11
+ export { default as Rate } from "./components/Rate";
12
+ export { default as Slider } from "./components/Slider";
13
+ export { default as Switch } from "./components/Switch";
14
+ export { default as Table } from "./components/Table";
15
+ export { default as Text } from "./components/Text";
16
+ export { default as Toggle } from "./components/Toggle";
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "ripal-ui",
3
- "version": "1.1.394",
4
- "description": "A collection of React elements and components",
3
+ "version": "2.0.0",
4
+ "description": "Reusable React Native UI components",
5
5
  "main": "index.js",
6
- "types": "index.d.ts",
7
- "scripts": {
8
- "build": "babel elements components --out-dir dist",
9
- "postinstall": "node ./scripts/generateConfig.js"
10
- },
11
- "dependencies": {
12
- "expo-secure-store": "~15.0.7",
13
- "react": "^19.1.0",
14
- "react-native": "^0.81.5"
15
- },
16
- "devDependencies": {
17
- "@babel/cli": "^7.25.6",
18
- "@babel/core": "^7.25.2",
19
- "@babel/preset-env": "^7.25.4",
20
- "@babel/preset-react": "^7.24.7",
21
- "@types/react": "^19.0.0",
22
- "typescript": "^5.6.2"
6
+ "react-native": "index.js",
7
+ "files": [
8
+ "components",
9
+ "index.js"
10
+ ],
11
+ "keywords": [
12
+ "react-native",
13
+ "ui",
14
+ "components"
15
+ ],
16
+ "author": "Your Name",
17
+ "license": "MIT",
18
+
19
+ "peerDependencies": {
20
+ "react": ">=18",
21
+ "react-native": ">=0.70",
22
+ "@react-native-vector-icons/material-icons": ">=12"
23
23
  }
24
- }
24
+ }
package/babel.config.js DELETED
@@ -1,3 +0,0 @@
1
- module.exports = {
2
- presets: ['@babel/preset-env', '@babel/preset-react']
3
- };