@retray-dev/ui-kit 9.2.0 → 9.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retray-dev/ui-kit",
3
- "version": "9.2.0",
3
+ "version": "9.3.0",
4
4
  "description": "Personal UI Kit for React Native / Expo",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -11,7 +11,11 @@
11
11
  "import": "./dist/index.mjs",
12
12
  "require": "./dist/index.js"
13
13
  },
14
- "./fonts": "./src/fonts.ts",
14
+ "./fonts": {
15
+ "types": "./dist/fonts.d.ts",
16
+ "import": "./dist/fonts.mjs",
17
+ "require": "./dist/fonts.js"
18
+ },
15
19
  "./*": {
16
20
  "types": "./dist/*.d.ts",
17
21
  "import": "./dist/*.mjs",
@@ -72,7 +76,7 @@
72
76
  "react-native-screens": ">=3.0.0",
73
77
  "react-native-size-matters": ">=0.4.0",
74
78
  "react-native-svg": ">=15.0.0",
75
- "react-native-worklets": "~0.5.1",
79
+ "react-native-worklets": ">=0.5.1",
76
80
  "sonner-native": ">=0.22.0"
77
81
  },
78
82
  "peerDependenciesMeta": {
@@ -1,17 +1,12 @@
1
1
  import React, { useState } from 'react'
2
2
  import { TextInput, View, Text, StyleSheet, TextInputProps, ViewStyle, TextStyle, TouchableOpacity, Platform } from 'react-native'
3
3
  import { BottomSheetTextInput } from '@gorhom/bottom-sheet'
4
- import Animated, {
5
- useAnimatedStyle,
6
- interpolateColor,
7
- interpolate,
8
- } from 'react-native-reanimated'
4
+ import { EaseView } from 'react-native-ease'
9
5
  import { AntDesign } from '@expo/vector-icons'
10
6
  import { useTheme } from '../../theme'
11
7
  import { s, vs, ms } from '../../utils/scaling'
12
8
  import { renderIcon } from '../../utils/icons'
13
- import { useColorTransition } from '../../utils/useColorTransition'
14
- import { TIMINGS } from '../../utils/animations'
9
+ import { COLOR_TRANSITION } from '../../utils/animations'
15
10
 
16
11
  const webInputResetStyle: Record<string, unknown> =
17
12
  Platform.OS === 'web'
@@ -43,10 +38,6 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
43
38
  const [focused, setFocused] = useState(false)
44
39
  const [showPassword, setShowPassword] = useState(false)
45
40
 
46
- const focusProgress = useColorTransition(focused, {
47
- duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration,
48
- })
49
-
50
41
  const isDisabled = disabled || editable === false
51
42
  const isPassword = type === 'password'
52
43
  const effectiveSecure = isPassword ? !showPassword : secureTextEntry
@@ -71,29 +62,23 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
71
62
  ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted)
72
63
  : suffix
73
64
 
74
- // Border drawn on an absolute overlay so the 1px→2px weight change never
75
- // resizes the layout box (which would reflow content / shift the interface).
76
- // Wrapper keeps borderWidth: 0; overlay grows inward and is non-interactive.
77
- const borderAnimStyle = useAnimatedStyle(() => ({
78
- borderColor: error
79
- ? colors.destructive
80
- : interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
81
- borderWidth: error
82
- ? 2
83
- : interpolate(focusProgress.value, [0, 1], [1, 2]),
84
- }))
65
+ // Border color animated via EaseView. Width is static (1px normal, 2px error)
66
+ // to avoid worklets 0.9.x interpolation issues with borderWidth.
67
+ const borderColor = error ? colors.destructive : (focused ? colors.primary : colors.border)
85
68
 
86
69
  return (
87
70
  <View style={[styles.container, isDisabled && styles.containerDisabled, containerStyle]}>
88
71
  {label ? <Text style={[styles.label, { color: colors.foreground }]} allowFontScaling={true}>{label}</Text> : null}
89
- <Animated.View
72
+ <EaseView
90
73
  style={[
91
74
  styles.inputWrapper,
92
75
  { backgroundColor: isDisabled ? colors.surface : colors.background },
76
+ error && styles.inputWrapperError,
93
77
  inputWrapperStyle,
94
78
  ]}
79
+ animate={{ borderColor }}
80
+ transition={COLOR_TRANSITION}
95
81
  >
96
- <Animated.View style={[styles.borderOverlay, borderAnimStyle]} pointerEvents="none" />
97
82
  {effectivePrefix ? (
98
83
  typeof effectivePrefix === 'string' ? (
99
84
  <Text style={[styles.prefixText, { color: colors.foregroundMuted }, prefixStyle]} allowFontScaling={true}>
@@ -159,7 +144,7 @@ export function Input({ label, error, hint, disabled, prefix, suffix, prefixStyl
159
144
  <View style={styles.suffixContainer}>{effectiveSuffix}</View>
160
145
  )
161
146
  ) : null}
162
- </Animated.View>
147
+ </EaseView>
163
148
  {error ? (
164
149
  <Text
165
150
  style={[styles.helperText, { color: colors.destructive }]}
@@ -190,16 +175,14 @@ const styles = StyleSheet.create({
190
175
  inputWrapper: {
191
176
  flexDirection: 'row',
192
177
  alignItems: 'center',
193
- // Border lives on borderOverlay (absolute) so its 1px→2px focus change
194
- // never resizes this box. Wrapper itself carries no border.
195
178
  borderRadius: 8,
179
+ borderWidth: 1,
196
180
  paddingHorizontal: s(14),
197
181
  paddingVertical: vs(11),
198
182
  minHeight: 48,
199
183
  },
200
- borderOverlay: {
201
- ...StyleSheet.absoluteFillObject,
202
- borderRadius: 8,
184
+ inputWrapperError: {
185
+ borderWidth: 2,
203
186
  },
204
187
  input: {
205
188
  fontFamily: 'Sohne-Regular',
@@ -5,6 +5,8 @@ import {
5
5
  StyleSheet,
6
6
  ViewStyle,
7
7
  TextStyle,
8
+ Image,
9
+ ImageSourcePropType,
8
10
  } from 'react-native'
9
11
  import { Entypo } from '@expo/vector-icons'
10
12
  import { selectionAsync as hapticSelection } from '../../utils/haptics'
@@ -17,6 +19,11 @@ import { PressableRow } from '../../utils/pressable'
17
19
  export type ListItemVariant = 'plain' | 'card'
18
20
 
19
21
  export interface ListItemProps {
22
+ /**
23
+ * Image source for the left slot. If provided, renders an Image (40×40, borderRadius 8).
24
+ * Takes precedence over `leftRender` and `leftIcon`.
25
+ */
26
+ imageSource?: ImageSourcePropType
20
27
  /**
21
28
  * Arbitrary content rendered on the left (avatar, icon, image, etc.).
22
29
  * Rendered inside a 44×44 aligned container.
@@ -81,6 +88,7 @@ export interface ListItemProps {
81
88
  }
82
89
 
83
90
  function ListItemBase({
91
+ imageSource,
84
92
  leftRender,
85
93
  rightRender,
86
94
  trailing,
@@ -111,9 +119,12 @@ function ListItemBase({
111
119
  onPress?.()
112
120
  }
113
121
 
114
- const effectiveLeft: React.ReactNode = leftIcon
115
- ? renderIcon(leftIcon, 24, leftIconColor ?? colors.foreground)
116
- : leftRender ?? icon
122
+ // imageSource takes precedence, then leftIcon, then leftRender/icon
123
+ const effectiveLeft: React.ReactNode = imageSource
124
+ ? <Image source={imageSource} style={styles.image} />
125
+ : leftIcon
126
+ ? renderIcon(leftIcon, 24, leftIconColor ?? colors.foreground)
127
+ : leftRender ?? icon
117
128
 
118
129
  const effectiveRight: React.ReactNode | string | undefined = rightIcon
119
130
  ? renderIcon(rightIcon, 24, rightIconColor ?? colors.foregroundMuted)
@@ -241,6 +252,11 @@ const styles = StyleSheet.create({
241
252
  justifyContent: 'center',
242
253
  flexShrink: 0,
243
254
  },
255
+ image: {
256
+ width: s(40),
257
+ height: s(40),
258
+ borderRadius: 8,
259
+ },
244
260
  content: {
245
261
  flex: 1,
246
262
  gap: vs(4),
package/src/fonts.ts CHANGED
@@ -14,38 +14,39 @@
14
14
  * }
15
15
  */
16
16
  // `.otf` assets resolve to a Metro asset module id (number) via require() at the
17
- // consumer's build time. Declared locally so the dts build does not depend on @types/node.
17
+ // consumer's build time. Paths are relative to dist/fonts.js (the compiled output).
18
+ // Both dist/ and src/ are published in the package, so ../src/assets/fonts/ resolves correctly.
18
19
  declare const require: (path: string) => number
19
20
 
20
21
  export const SohneFonts = {
21
22
  // Sohne base
22
- 'Sohne-ExtraLight': require('./assets/fonts/Sohne-ExtraLight.otf'),
23
- 'Sohne-ExtraLightItalic': require('./assets/fonts/Sohne-ExtraLightItalic.otf'),
24
- 'Sohne-Light': require('./assets/fonts/Sohne-Light.otf'),
25
- 'Sohne-LightItalic': require('./assets/fonts/Sohne-LightItalic.otf'),
26
- 'Sohne-Regular': require('./assets/fonts/Sohne-Regular.otf'),
27
- 'Sohne-Italic': require('./assets/fonts/Sohne-Italic.otf'),
28
- 'Sohne-Medium': require('./assets/fonts/Sohne-Medium.otf'),
29
- 'Sohne-MediumItalic': require('./assets/fonts/Sohne-MediumItalic.otf'),
30
- 'Sohne-SemiBold': require('./assets/fonts/Sohne-SemiBold.otf'),
31
- 'Sohne-SemiBoldItalic': require('./assets/fonts/Sohne-SemiBoldItalic.otf'),
32
- 'Sohne-Bold': require('./assets/fonts/Sohne-Bold.otf'),
33
- 'Sohne-BoldItalic': require('./assets/fonts/Sohne-BoldItalic.otf'),
34
- 'Sohne-ExtraBold': require('./assets/fonts/Sohne-ExtraBold.otf'),
35
- 'Sohne-ExtraBoldItalic': require('./assets/fonts/Sohne-ExtraBoldItalic.otf'),
23
+ 'Sohne-ExtraLight': require('../src/assets/fonts/Sohne-ExtraLight.otf'),
24
+ 'Sohne-ExtraLightItalic': require('../src/assets/fonts/Sohne-ExtraLightItalic.otf'),
25
+ 'Sohne-Light': require('../src/assets/fonts/Sohne-Light.otf'),
26
+ 'Sohne-LightItalic': require('../src/assets/fonts/Sohne-LightItalic.otf'),
27
+ 'Sohne-Regular': require('../src/assets/fonts/Sohne-Regular.otf'),
28
+ 'Sohne-Italic': require('../src/assets/fonts/Sohne-Italic.otf'),
29
+ 'Sohne-Medium': require('../src/assets/fonts/Sohne-Medium.otf'),
30
+ 'Sohne-MediumItalic': require('../src/assets/fonts/Sohne-MediumItalic.otf'),
31
+ 'Sohne-SemiBold': require('../src/assets/fonts/Sohne-SemiBold.otf'),
32
+ 'Sohne-SemiBoldItalic': require('../src/assets/fonts/Sohne-SemiBoldItalic.otf'),
33
+ 'Sohne-Bold': require('../src/assets/fonts/Sohne-Bold.otf'),
34
+ 'Sohne-BoldItalic': require('../src/assets/fonts/Sohne-BoldItalic.otf'),
35
+ 'Sohne-ExtraBold': require('../src/assets/fonts/Sohne-ExtraBold.otf'),
36
+ 'Sohne-ExtraBoldItalic': require('../src/assets/fonts/Sohne-ExtraBoldItalic.otf'),
36
37
  // SohneMono
37
- 'SohneMono-ExtraLight': require('./assets/fonts/SohneMono-ExtraLight.otf'),
38
- 'SohneMono-ExtraLightItalic': require('./assets/fonts/SohneMono-ExtraLightItalic.otf'),
39
- 'SohneMono-Light': require('./assets/fonts/SohneMono-Light.otf'),
40
- 'SohneMono-LightItalic': require('./assets/fonts/SohneMono-LightItalic.otf'),
41
- 'SohneMono-Regular': require('./assets/fonts/SohneMono-Regular.otf'),
42
- 'SohneMono-Italic': require('./assets/fonts/SohneMono-Italic.otf'),
43
- 'SohneMono-Medium': require('./assets/fonts/SohneMono-Medium.otf'),
44
- 'SohneMono-MediumItalic': require('./assets/fonts/SohneMono-MediumItalic.otf'),
45
- 'SohneMono-SemiBold': require('./assets/fonts/SohneMono-SemiBold.otf'),
46
- 'SohneMono-SemiBoldItalic': require('./assets/fonts/SohneMono-SemiBoldItalic.otf'),
47
- 'SohneMono-Bold': require('./assets/fonts/SohneMono-Bold.otf'),
48
- 'SohneMono-BoldItalic': require('./assets/fonts/SohneMono-BoldItalic.otf'),
49
- 'SohneMono-ExtraBold': require('./assets/fonts/SohneMono-ExtraBold.otf'),
50
- 'SohneMono-ExtraBoldItalic': require('./assets/fonts/SohneMono-ExtraBoldItalic.otf'),
38
+ 'SohneMono-ExtraLight': require('../src/assets/fonts/SohneMono-ExtraLight.otf'),
39
+ 'SohneMono-ExtraLightItalic': require('../src/assets/fonts/SohneMono-ExtraLightItalic.otf'),
40
+ 'SohneMono-Light': require('../src/assets/fonts/SohneMono-Light.otf'),
41
+ 'SohneMono-LightItalic': require('../src/assets/fonts/SohneMono-LightItalic.otf'),
42
+ 'SohneMono-Regular': require('../src/assets/fonts/SohneMono-Regular.otf'),
43
+ 'SohneMono-Italic': require('../src/assets/fonts/SohneMono-Italic.otf'),
44
+ 'SohneMono-Medium': require('../src/assets/fonts/SohneMono-Medium.otf'),
45
+ 'SohneMono-MediumItalic': require('../src/assets/fonts/SohneMono-MediumItalic.otf'),
46
+ 'SohneMono-SemiBold': require('../src/assets/fonts/SohneMono-SemiBold.otf'),
47
+ 'SohneMono-SemiBoldItalic': require('../src/assets/fonts/SohneMono-SemiBoldItalic.otf'),
48
+ 'SohneMono-Bold': require('../src/assets/fonts/SohneMono-Bold.otf'),
49
+ 'SohneMono-BoldItalic': require('../src/assets/fonts/SohneMono-BoldItalic.otf'),
50
+ 'SohneMono-ExtraBold': require('../src/assets/fonts/SohneMono-ExtraBold.otf'),
51
+ 'SohneMono-ExtraBoldItalic': require('../src/assets/fonts/SohneMono-ExtraBoldItalic.otf'),
51
52
  } as const
@@ -1,14 +0,0 @@
1
- import { TIMINGS, EASINGS } from './chunk-DVK4G2GT.mjs';
2
- import { useEffect } from 'react';
3
- import { useSharedValue, withTiming } from 'react-native-reanimated';
4
-
5
- function useColorTransition(active, options = {}) {
6
- const { duration = TIMINGS.state.duration } = options;
7
- const progress = useSharedValue(active ? 1 : 0);
8
- useEffect(() => {
9
- progress.value = withTiming(active ? 1 : 0, { duration, easing: EASINGS.standard });
10
- }, [active, duration, progress]);
11
- return progress;
12
- }
13
-
14
- export { useColorTransition };