@retray-dev/ui-kit 9.1.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/COMPONENTS.md +166 -4
- package/CONSUMER.md +247 -0
- package/DESIGN.md +668 -0
- package/FONTS.md +107 -0
- package/README.md +3 -3
- package/dist/AlertBanner.d.mts +3 -1
- package/dist/AlertBanner.d.ts +3 -1
- package/dist/AlertBanner.js +18 -2
- package/dist/AlertBanner.mjs +1 -1
- package/dist/ConfirmDialog.d.mts +3 -1
- package/dist/ConfirmDialog.d.ts +3 -1
- package/dist/ConfirmDialog.js +3 -0
- package/dist/ConfirmDialog.mjs +1 -1
- package/dist/CurrencyInput.d.mts +3 -1
- package/dist/CurrencyInput.d.ts +3 -1
- package/dist/CurrencyInput.js +52 -39
- package/dist/CurrencyInput.mjs +2 -3
- package/dist/ImageUpload.d.mts +27 -0
- package/dist/ImageUpload.d.ts +27 -0
- package/dist/ImageUpload.js +399 -0
- package/dist/ImageUpload.mjs +9 -0
- package/dist/Input.d.mts +3 -1
- package/dist/Input.d.ts +3 -1
- package/dist/Input.js +48 -37
- package/dist/Input.mjs +1 -2
- package/dist/ListItem.d.mts +9 -2
- package/dist/ListItem.d.ts +9 -2
- package/dist/ListItem.js +9 -2
- package/dist/ListItem.mjs +1 -1
- package/dist/SheetSelect.d.mts +25 -0
- package/dist/SheetSelect.d.ts +25 -0
- package/dist/SheetSelect.js +440 -0
- package/dist/SheetSelect.mjs +9 -0
- package/dist/Textarea.mjs +1 -2
- package/dist/{chunk-M6ZXVBTK.mjs → chunk-6MKGPAR2.mjs} +21 -5
- package/dist/{chunk-EH745HE5.mjs → chunk-CZCQZHG6.mjs} +13 -4
- package/dist/{chunk-7QHVVCB3.mjs → chunk-FZZLPJ6B.mjs} +3 -0
- package/dist/{chunk-MAC465BB.mjs → chunk-JUXSWN54.mjs} +5 -3
- package/dist/{chunk-BNP626TY.mjs → chunk-OHBNABL5.mjs} +10 -3
- package/dist/chunk-URI2WBIV.mjs +147 -0
- package/dist/chunk-Y4GL2MHX.mjs +112 -0
- package/dist/{chunk-756RAKE4.mjs → chunk-ZUR7AU5R.mjs} +38 -20
- package/dist/fonts.d.mts +32 -0
- package/dist/fonts.d.ts +32 -0
- package/dist/fonts.js +44 -0
- package/dist/fonts.mjs +37 -0
- package/dist/index.d.mts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +425 -106
- package/dist/index.mjs +55 -17
- package/package.json +23 -6
- package/src/components/AlertBanner/AlertBanner.tsx +21 -3
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +5 -0
- package/src/components/CurrencyInput/CurrencyInput.tsx +4 -0
- package/src/components/ImageUpload/ImageUpload.tsx +158 -0
- package/src/components/ImageUpload/index.ts +1 -0
- package/src/components/Input/Input.tsx +64 -53
- package/src/components/ListItem/ListItem.tsx +23 -4
- package/src/components/SheetSelect/SheetSelect.tsx +192 -0
- package/src/components/SheetSelect/index.ts +1 -0
- package/src/fonts.ts +30 -29
- package/src/hooks/useConfirmDialog.ts +67 -0
- package/src/index.ts +6 -0
- package/dist/chunk-26BCI223.mjs +0 -14
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React3 = require('react');
|
|
4
|
+
var reactNative = require('react-native');
|
|
5
|
+
var vectorIcons = require('@expo/vector-icons');
|
|
6
|
+
var reactNativeSizeMatters = require('react-native-size-matters');
|
|
7
|
+
var pressto = require('pressto');
|
|
8
|
+
var reactNativeReanimated = require('react-native-reanimated');
|
|
9
|
+
|
|
10
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
13
|
+
|
|
14
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
15
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
16
|
+
}) : x)(function(x) {
|
|
17
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
18
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
19
|
+
});
|
|
20
|
+
var _haptics = null;
|
|
21
|
+
var _hapticsLoaded = false;
|
|
22
|
+
async function getHaptics() {
|
|
23
|
+
if (reactNative.Platform.OS === "web") return null;
|
|
24
|
+
if (!_hapticsLoaded) {
|
|
25
|
+
_hapticsLoaded = true;
|
|
26
|
+
try {
|
|
27
|
+
_haptics = await import('expo-haptics');
|
|
28
|
+
} catch {
|
|
29
|
+
_haptics = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return _haptics;
|
|
33
|
+
}
|
|
34
|
+
var _pulsar = null;
|
|
35
|
+
var _pulsarChecked = false;
|
|
36
|
+
var _pulsarAvailable = false;
|
|
37
|
+
function isPulsarNativeRegistered() {
|
|
38
|
+
try {
|
|
39
|
+
const g = globalThis;
|
|
40
|
+
if (typeof g.__turboModuleProxy === "function") {
|
|
41
|
+
return g.__turboModuleProxy("RNPulsar") != null;
|
|
42
|
+
}
|
|
43
|
+
return reactNative.NativeModules?.RNPulsar != null;
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function getPulsar() {
|
|
49
|
+
if (reactNative.Platform.OS === "web") return null;
|
|
50
|
+
if (!_pulsarChecked) {
|
|
51
|
+
_pulsarChecked = true;
|
|
52
|
+
try {
|
|
53
|
+
if (isPulsarNativeRegistered()) {
|
|
54
|
+
_pulsar = __require("react-native-pulsar");
|
|
55
|
+
_pulsarAvailable = true;
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
_pulsar = null;
|
|
59
|
+
_pulsarAvailable = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return _pulsarAvailable ? _pulsar : null;
|
|
63
|
+
}
|
|
64
|
+
function impactLight() {
|
|
65
|
+
if (reactNative.Platform.OS === "web") return;
|
|
66
|
+
getHaptics().then((h) => {
|
|
67
|
+
if (h) {
|
|
68
|
+
h.impactAsync(h.ImpactFeedbackStyle.Light);
|
|
69
|
+
} else {
|
|
70
|
+
getPulsar()?.Presets.System.impactLight();
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/theme/colorUtils.ts
|
|
76
|
+
function hexToRgb(hex) {
|
|
77
|
+
const clean = hex.replace("#", "");
|
|
78
|
+
const full = clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean;
|
|
79
|
+
if (full.length !== 6) return null;
|
|
80
|
+
return {
|
|
81
|
+
r: parseInt(full.slice(0, 2), 16),
|
|
82
|
+
g: parseInt(full.slice(2, 4), 16),
|
|
83
|
+
b: parseInt(full.slice(4, 6), 16)
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function componentToHex(c) {
|
|
87
|
+
return Math.round(Math.max(0, Math.min(255, c))).toString(16).padStart(2, "0");
|
|
88
|
+
}
|
|
89
|
+
function rgbToHex(r, g, b) {
|
|
90
|
+
return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
|
|
91
|
+
}
|
|
92
|
+
function withAlphaOnWhite(hex, alpha) {
|
|
93
|
+
const rgb = hexToRgb(hex);
|
|
94
|
+
if (!rgb) return hex;
|
|
95
|
+
const r = rgb.r * alpha + 255 * (1 - alpha);
|
|
96
|
+
const g = rgb.g * alpha + 255 * (1 - alpha);
|
|
97
|
+
const b = rgb.b * alpha + 255 * (1 - alpha);
|
|
98
|
+
return rgbToHex(r, g, b);
|
|
99
|
+
}
|
|
100
|
+
function withAlphaOnDark(hex, alpha, bgHex = "#0f0f0f") {
|
|
101
|
+
const rgb = hexToRgb(hex);
|
|
102
|
+
const bg = hexToRgb(bgHex);
|
|
103
|
+
if (!rgb || !bg) return hex;
|
|
104
|
+
const r = rgb.r * alpha + bg.r * (1 - alpha);
|
|
105
|
+
const g = rgb.g * alpha + bg.g * (1 - alpha);
|
|
106
|
+
const b = rgb.b * alpha + bg.b * (1 - alpha);
|
|
107
|
+
return rgbToHex(r, g, b);
|
|
108
|
+
}
|
|
109
|
+
function mixWithBackground(fgHex, bgHex, opacity) {
|
|
110
|
+
const fg = hexToRgb(fgHex);
|
|
111
|
+
const bg = hexToRgb(bgHex);
|
|
112
|
+
if (!fg || !bg) return fgHex;
|
|
113
|
+
const r = fg.r * opacity + bg.r * (1 - opacity);
|
|
114
|
+
const g = fg.g * opacity + bg.g * (1 - opacity);
|
|
115
|
+
const b = fg.b * opacity + bg.b * (1 - opacity);
|
|
116
|
+
return rgbToHex(r, g, b);
|
|
117
|
+
}
|
|
118
|
+
function lighten(hex, amount) {
|
|
119
|
+
return withAlphaOnWhite(hex, 1 - amount);
|
|
120
|
+
}
|
|
121
|
+
function darken(hex, amount) {
|
|
122
|
+
const rgb = hexToRgb(hex);
|
|
123
|
+
if (!rgb) return hex;
|
|
124
|
+
return rgbToHex(rgb.r * (1 - amount), rgb.g * (1 - amount), rgb.b * (1 - amount));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/theme/colors.ts
|
|
128
|
+
var defaultLight = {
|
|
129
|
+
background: "#ffffff",
|
|
130
|
+
foreground: "#1a1a1a",
|
|
131
|
+
card: "#ffffff",
|
|
132
|
+
primary: "#1a1a1a",
|
|
133
|
+
primaryForeground: "#ffffff",
|
|
134
|
+
// AUDIT FIX: brand accent — was undefined; falls back to primary when omitted
|
|
135
|
+
accent: "#d4561d",
|
|
136
|
+
accentForeground: "#ffffff",
|
|
137
|
+
border: "#dddddd",
|
|
138
|
+
// AUDIT FIX: was #e53935 (4.22:1 on white — fails AA); #c72828 = 5.59:1 ✓
|
|
139
|
+
destructive: "#c72828",
|
|
140
|
+
destructiveForeground: "#ffffff",
|
|
141
|
+
success: "#1a7a45",
|
|
142
|
+
successForeground: "#ffffff",
|
|
143
|
+
// AUDIT FIX: was #e67e00 (2.86:1 — severe fail); #9a5200 = 5.86:1 ✓ AAA-near
|
|
144
|
+
warning: "#9a5200",
|
|
145
|
+
warningForeground: "#ffffff"
|
|
146
|
+
};
|
|
147
|
+
function deriveColors(t, scheme) {
|
|
148
|
+
const dark = scheme === "dark";
|
|
149
|
+
const bg = t.background;
|
|
150
|
+
const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.7);
|
|
151
|
+
const foregroundMuted = mixWithBackground(t.foreground, bg, 0.62);
|
|
152
|
+
const surface = dark ? lighten(bg, -0.06) : darken(bg, 0.04);
|
|
153
|
+
const surfaceStrong = dark ? lighten(bg, -0.12) : darken(bg, 0.08);
|
|
154
|
+
const destructiveTint = dark ? withAlphaOnDark(t.destructive, 0.15, bg) : withAlphaOnWhite(t.destructive, 0.08);
|
|
155
|
+
const destructiveBorder = dark ? withAlphaOnDark(t.destructive, 0.45, bg) : withAlphaOnWhite(t.destructive, 0.3);
|
|
156
|
+
const successTint = dark ? withAlphaOnDark(t.success, 0.15, bg) : withAlphaOnWhite(t.success, 0.08);
|
|
157
|
+
const successBorder = dark ? withAlphaOnDark(t.success, 0.45, bg) : withAlphaOnWhite(t.success, 0.3);
|
|
158
|
+
const warningTint = dark ? withAlphaOnDark(t.warning, 0.15, bg) : withAlphaOnWhite(t.warning, 0.08);
|
|
159
|
+
const warningBorder = dark ? withAlphaOnDark(t.warning, 0.45, bg) : withAlphaOnWhite(t.warning, 0.3);
|
|
160
|
+
return {
|
|
161
|
+
...t,
|
|
162
|
+
foregroundSubtle,
|
|
163
|
+
foregroundMuted,
|
|
164
|
+
surface,
|
|
165
|
+
surfaceStrong,
|
|
166
|
+
destructiveTint,
|
|
167
|
+
destructiveBorder,
|
|
168
|
+
successTint,
|
|
169
|
+
successBorder,
|
|
170
|
+
warningTint,
|
|
171
|
+
warningBorder,
|
|
172
|
+
overlay: t.overlay ?? "rgba(0,0,0,0.45)",
|
|
173
|
+
accentResolved: t.accent ?? t.primary,
|
|
174
|
+
accentForegroundResolved: t.accentForeground ?? t.primaryForeground,
|
|
175
|
+
ring: t.accent ?? t.primary,
|
|
176
|
+
input: t.border,
|
|
177
|
+
separator: dark ? lighten(t.border, 0.22) : darken(t.border, 0.16)
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/theme/ThemeProvider.tsx
|
|
182
|
+
var ThemeContext = React3.createContext({
|
|
183
|
+
colors: deriveColors(defaultLight, "light"),
|
|
184
|
+
colorScheme: "light"
|
|
185
|
+
});
|
|
186
|
+
function useTheme() {
|
|
187
|
+
const context = React3.useContext(ThemeContext);
|
|
188
|
+
if (!context) {
|
|
189
|
+
throw new Error("useTheme must be used within a ThemeProvider");
|
|
190
|
+
}
|
|
191
|
+
return context;
|
|
192
|
+
}
|
|
193
|
+
var isWeb = reactNative.Platform.OS === "web";
|
|
194
|
+
var s = isWeb ? (n) => n : reactNativeSizeMatters.scale;
|
|
195
|
+
var vs = isWeb ? (n) => n : reactNativeSizeMatters.verticalScale;
|
|
196
|
+
var ms = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateScale;
|
|
197
|
+
var mvs = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateVerticalScale;
|
|
198
|
+
|
|
199
|
+
// src/tokens.ts
|
|
200
|
+
var RADIUS = {
|
|
201
|
+
lg: 20};
|
|
202
|
+
var sizeMap = {
|
|
203
|
+
sm: "small",
|
|
204
|
+
md: "small",
|
|
205
|
+
lg: "large"
|
|
206
|
+
};
|
|
207
|
+
var labelFontSize = {
|
|
208
|
+
sm: ms(11),
|
|
209
|
+
md: ms(13),
|
|
210
|
+
lg: ms(14)
|
|
211
|
+
};
|
|
212
|
+
function Spinner({ size = "md", color, label, ...props }) {
|
|
213
|
+
const { colors } = useTheme();
|
|
214
|
+
const a11yLabel = label || "Loading";
|
|
215
|
+
if (label) {
|
|
216
|
+
return /* @__PURE__ */ React3__default.default.createElement(
|
|
217
|
+
reactNative.View,
|
|
218
|
+
{
|
|
219
|
+
style: styles.wrapper,
|
|
220
|
+
accessibilityRole: "progressbar",
|
|
221
|
+
accessibilityLabel: a11yLabel,
|
|
222
|
+
accessibilityState: { busy: true }
|
|
223
|
+
},
|
|
224
|
+
/* @__PURE__ */ React3__default.default.createElement(reactNative.ActivityIndicator, { size: sizeMap[size], color: color ?? colors.primary, ...props }),
|
|
225
|
+
/* @__PURE__ */ React3__default.default.createElement(
|
|
226
|
+
reactNative.Text,
|
|
227
|
+
{
|
|
228
|
+
style: [styles.label, { color: colors.foregroundMuted, fontSize: labelFontSize[size] }],
|
|
229
|
+
allowFontScaling: true
|
|
230
|
+
},
|
|
231
|
+
label
|
|
232
|
+
)
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return /* @__PURE__ */ React3__default.default.createElement(
|
|
236
|
+
reactNative.ActivityIndicator,
|
|
237
|
+
{
|
|
238
|
+
size: sizeMap[size],
|
|
239
|
+
color: color ?? colors.primary,
|
|
240
|
+
accessibilityRole: "progressbar",
|
|
241
|
+
accessibilityLabel: a11yLabel,
|
|
242
|
+
accessibilityState: { busy: true },
|
|
243
|
+
...props
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
var styles = reactNative.StyleSheet.create({
|
|
248
|
+
wrapper: {
|
|
249
|
+
alignItems: "center",
|
|
250
|
+
gap: vs(6)
|
|
251
|
+
},
|
|
252
|
+
label: {
|
|
253
|
+
fontFamily: "Sohne-Regular",
|
|
254
|
+
lineHeight: mvs(18)
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
({
|
|
258
|
+
/** Material-style ease-out — natural deceleration for state changes. */
|
|
259
|
+
standard: reactNativeReanimated.Easing.bezier(0.2, 0, 0, 1),
|
|
260
|
+
/** Strong ease-out for expanding surfaces (Accordion open). */
|
|
261
|
+
expand: reactNativeReanimated.Easing.bezier(0.23, 1, 0.32, 1),
|
|
262
|
+
/** Quick ease-in for collapsing. */
|
|
263
|
+
collapse: reactNativeReanimated.Easing.in(reactNativeReanimated.Easing.ease)
|
|
264
|
+
});
|
|
265
|
+
var PRESS_SCALE = {
|
|
266
|
+
button: 0.95,
|
|
267
|
+
card: 0.98,
|
|
268
|
+
row: 0.97,
|
|
269
|
+
chip: 0.94
|
|
270
|
+
};
|
|
271
|
+
pressto.createAnimatedPressable((progress) => {
|
|
272
|
+
"worklet";
|
|
273
|
+
const scale2 = 1 - (1 - PRESS_SCALE.button) * progress;
|
|
274
|
+
return { transform: [{ scale: scale2 }] };
|
|
275
|
+
});
|
|
276
|
+
var PressableCard = pressto.createAnimatedPressable((progress) => {
|
|
277
|
+
"worklet";
|
|
278
|
+
const scale2 = 1 - (1 - PRESS_SCALE.card) * progress;
|
|
279
|
+
return { transform: [{ scale: scale2 }] };
|
|
280
|
+
});
|
|
281
|
+
pressto.createAnimatedPressable((progress) => {
|
|
282
|
+
"worklet";
|
|
283
|
+
const scale2 = 1 - (1 - PRESS_SCALE.row) * progress;
|
|
284
|
+
return { transform: [{ scale: scale2 }] };
|
|
285
|
+
});
|
|
286
|
+
pressto.createAnimatedPressable((progress) => {
|
|
287
|
+
"worklet";
|
|
288
|
+
const scale2 = 1 - (1 - PRESS_SCALE.chip) * progress;
|
|
289
|
+
return { transform: [{ scale: scale2 }] };
|
|
290
|
+
});
|
|
291
|
+
pressto.createAnimatedPressable((progress) => {
|
|
292
|
+
"worklet";
|
|
293
|
+
const scale2 = 1 - (1 - PRESS_SCALE.button) * progress;
|
|
294
|
+
return { transform: [{ scale: scale2 }] };
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// src/components/ImageUpload/ImageUpload.tsx
|
|
298
|
+
function ImageUpload({
|
|
299
|
+
value,
|
|
300
|
+
onChange,
|
|
301
|
+
loading = false,
|
|
302
|
+
placeholder = "Tap to add image",
|
|
303
|
+
width,
|
|
304
|
+
height = 200,
|
|
305
|
+
borderRadius = RADIUS.lg,
|
|
306
|
+
resizeMode = "cover",
|
|
307
|
+
disabled = false,
|
|
308
|
+
style,
|
|
309
|
+
accessibilityLabel
|
|
310
|
+
}) {
|
|
311
|
+
const { colors } = useTheme();
|
|
312
|
+
const handlePress = async () => {
|
|
313
|
+
if (disabled || loading) return;
|
|
314
|
+
impactLight();
|
|
315
|
+
let ImagePicker;
|
|
316
|
+
try {
|
|
317
|
+
ImagePicker = await import('expo-image-picker');
|
|
318
|
+
} catch {
|
|
319
|
+
if (__DEV__) console.warn("[ImageUpload] expo-image-picker not installed. Add it as a dependency.");
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (reactNative.Platform.OS !== "web") {
|
|
323
|
+
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
|
324
|
+
if (status !== "granted") return;
|
|
325
|
+
}
|
|
326
|
+
const result = await ImagePicker.launchImageLibraryAsync({
|
|
327
|
+
mediaTypes: ["images"],
|
|
328
|
+
allowsEditing: true,
|
|
329
|
+
quality: 0.8
|
|
330
|
+
});
|
|
331
|
+
if (!result.canceled && result.assets[0]) {
|
|
332
|
+
onChange?.(result.assets[0].uri);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
const containerStyle = {
|
|
336
|
+
width,
|
|
337
|
+
height,
|
|
338
|
+
borderRadius,
|
|
339
|
+
borderWidth: value ? 0 : 1,
|
|
340
|
+
borderStyle: "dashed",
|
|
341
|
+
borderColor: colors.border,
|
|
342
|
+
backgroundColor: value ? "transparent" : colors.surface,
|
|
343
|
+
overflow: "hidden"
|
|
344
|
+
};
|
|
345
|
+
return /* @__PURE__ */ React3__default.default.createElement(
|
|
346
|
+
PressableCard,
|
|
347
|
+
{
|
|
348
|
+
onPress: handlePress,
|
|
349
|
+
enabled: !disabled && !loading,
|
|
350
|
+
rippleColor: "transparent",
|
|
351
|
+
touchSoundDisabled: true,
|
|
352
|
+
accessibilityRole: "button",
|
|
353
|
+
accessibilityLabel: accessibilityLabel ?? (value ? "Change image" : placeholder),
|
|
354
|
+
accessibilityState: { disabled: disabled || loading },
|
|
355
|
+
style: [containerStyle, style]
|
|
356
|
+
},
|
|
357
|
+
value ? /* @__PURE__ */ React3__default.default.createElement(
|
|
358
|
+
reactNative.Image,
|
|
359
|
+
{
|
|
360
|
+
source: { uri: value },
|
|
361
|
+
style: [reactNative.StyleSheet.absoluteFillObject, { borderRadius }],
|
|
362
|
+
resizeMode
|
|
363
|
+
}
|
|
364
|
+
) : /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles2.placeholder }, /* @__PURE__ */ React3__default.default.createElement(vectorIcons.Feather, { name: "image", size: ms(28), color: colors.foregroundMuted }), /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles2.placeholderText, { color: colors.foregroundMuted }], allowFontScaling: true }, placeholder)),
|
|
365
|
+
loading ? /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: [styles2.loadingOverlay, { backgroundColor: colors.overlay }] }, /* @__PURE__ */ React3__default.default.createElement(Spinner, { size: "md" })) : null,
|
|
366
|
+
value && !loading ? /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles2.editBadge, pointerEvents: "none" }, /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: [styles2.editBadgeInner, { backgroundColor: colors.overlay }] }, /* @__PURE__ */ React3__default.default.createElement(vectorIcons.Feather, { name: "edit-2", size: ms(12), color: "#fff" }))) : null
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
370
|
+
placeholder: {
|
|
371
|
+
flex: 1,
|
|
372
|
+
alignItems: "center",
|
|
373
|
+
justifyContent: "center",
|
|
374
|
+
gap: vs(8)
|
|
375
|
+
},
|
|
376
|
+
placeholderText: {
|
|
377
|
+
fontFamily: "Sohne-Regular",
|
|
378
|
+
fontSize: ms(13)
|
|
379
|
+
},
|
|
380
|
+
loadingOverlay: {
|
|
381
|
+
...reactNative.StyleSheet.absoluteFillObject,
|
|
382
|
+
alignItems: "center",
|
|
383
|
+
justifyContent: "center"
|
|
384
|
+
},
|
|
385
|
+
editBadge: {
|
|
386
|
+
position: "absolute",
|
|
387
|
+
bottom: vs(8),
|
|
388
|
+
right: s(8)
|
|
389
|
+
},
|
|
390
|
+
editBadgeInner: {
|
|
391
|
+
width: s(28),
|
|
392
|
+
height: s(28),
|
|
393
|
+
borderRadius: 999,
|
|
394
|
+
alignItems: "center",
|
|
395
|
+
justifyContent: "center"
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
exports.ImageUpload = ImageUpload;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { ImageUpload } from './chunk-Y4GL2MHX.mjs';
|
|
2
|
+
import './chunk-WBOOUHSS.mjs';
|
|
3
|
+
import './chunk-3DKJ2GIC.mjs';
|
|
4
|
+
import './chunk-EJ7ZPXOH.mjs';
|
|
5
|
+
import './chunk-DVK4G2GT.mjs';
|
|
6
|
+
import './chunk-QY3X2UYR.mjs';
|
|
7
|
+
import './chunk-SOYNZDVY.mjs';
|
|
8
|
+
import './chunk-2CE3TQVY.mjs';
|
|
9
|
+
import './chunk-Y6FXYEAI.mjs';
|
package/dist/Input.d.mts
CHANGED
|
@@ -17,7 +17,9 @@ interface InputProps extends TextInputProps {
|
|
|
17
17
|
type?: 'text' | 'password';
|
|
18
18
|
containerStyle?: ViewStyle;
|
|
19
19
|
inputWrapperStyle?: ViewStyle;
|
|
20
|
+
/** Use inside a Sheet/BottomSheet — swaps TextInput for BottomSheetTextInput to fix keyboard handling. */
|
|
21
|
+
sheetMode?: boolean;
|
|
20
22
|
}
|
|
21
|
-
declare function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type, containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }: InputProps): React.JSX.Element;
|
|
23
|
+
declare function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type, containerStyle, inputWrapperStyle, sheetMode, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }: InputProps): React.JSX.Element;
|
|
22
24
|
|
|
23
25
|
export { Input, type InputProps };
|
package/dist/Input.d.ts
CHANGED
|
@@ -17,7 +17,9 @@ interface InputProps extends TextInputProps {
|
|
|
17
17
|
type?: 'text' | 'password';
|
|
18
18
|
containerStyle?: ViewStyle;
|
|
19
19
|
inputWrapperStyle?: ViewStyle;
|
|
20
|
+
/** Use inside a Sheet/BottomSheet — swaps TextInput for BottomSheetTextInput to fix keyboard handling. */
|
|
21
|
+
sheetMode?: boolean;
|
|
20
22
|
}
|
|
21
|
-
declare function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type, containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }: InputProps): React.JSX.Element;
|
|
23
|
+
declare function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type, containerStyle, inputWrapperStyle, sheetMode, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }: InputProps): React.JSX.Element;
|
|
22
24
|
|
|
23
25
|
export { Input, type InputProps };
|
package/dist/Input.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var React3 = require('react');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
|
-
var
|
|
5
|
+
var bottomSheet = require('@gorhom/bottom-sheet');
|
|
6
|
+
var reactNativeEase = require('react-native-ease');
|
|
6
7
|
var vectorIcons = require('@expo/vector-icons');
|
|
7
8
|
var reactNativeSizeMatters = require('react-native-size-matters');
|
|
8
9
|
var AntDesign = require('@expo/vector-icons/AntDesign');
|
|
@@ -11,11 +12,11 @@ var Feather = require('@expo/vector-icons/Feather');
|
|
|
11
12
|
var FontAwesome5 = require('@expo/vector-icons/FontAwesome5');
|
|
12
13
|
var MaterialIcons = require('@expo/vector-icons/MaterialIcons');
|
|
13
14
|
var Ionicons = require('@expo/vector-icons/Ionicons');
|
|
15
|
+
var reactNativeReanimated = require('react-native-reanimated');
|
|
14
16
|
|
|
15
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
18
|
|
|
17
19
|
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
18
|
-
var Animated__default = /*#__PURE__*/_interopDefault(Animated);
|
|
19
20
|
var AntDesign__default = /*#__PURE__*/_interopDefault(AntDesign);
|
|
20
21
|
var Entypo__default = /*#__PURE__*/_interopDefault(Entypo);
|
|
21
22
|
var Feather__default = /*#__PURE__*/_interopDefault(Feather);
|
|
@@ -190,38 +191,27 @@ function renderIcon(name, size, color) {
|
|
|
190
191
|
}
|
|
191
192
|
var TIMINGS = {
|
|
192
193
|
/** Color/opacity transitions on toggles, checkboxes, switches. */
|
|
193
|
-
state: { duration: 160 }
|
|
194
|
-
|
|
195
|
-
focusIn: { duration: 140 },
|
|
196
|
-
focusOut: { duration: 100 }};
|
|
197
|
-
var EASINGS = {
|
|
194
|
+
state: { duration: 160 }};
|
|
195
|
+
({
|
|
198
196
|
/** Material-style ease-out — natural deceleration for state changes. */
|
|
199
|
-
standard:
|
|
197
|
+
standard: reactNativeReanimated.Easing.bezier(0.2, 0, 0, 1),
|
|
200
198
|
/** Strong ease-out for expanding surfaces (Accordion open). */
|
|
201
|
-
expand:
|
|
199
|
+
expand: reactNativeReanimated.Easing.bezier(0.23, 1, 0.32, 1),
|
|
202
200
|
/** Quick ease-in for collapsing. */
|
|
203
|
-
collapse:
|
|
201
|
+
collapse: reactNativeReanimated.Easing.in(reactNativeReanimated.Easing.ease)
|
|
202
|
+
});
|
|
203
|
+
var COLOR_TRANSITION = {
|
|
204
|
+
type: "timing",
|
|
205
|
+
duration: TIMINGS.state.duration,
|
|
206
|
+
easing: [0.2, 0, 0, 1]
|
|
204
207
|
};
|
|
205
208
|
|
|
206
|
-
// src/utils/useColorTransition.ts
|
|
207
|
-
function useColorTransition(active, options = {}) {
|
|
208
|
-
const { duration = TIMINGS.state.duration } = options;
|
|
209
|
-
const progress = Animated.useSharedValue(active ? 1 : 0);
|
|
210
|
-
React3.useEffect(() => {
|
|
211
|
-
progress.value = Animated.withTiming(active ? 1 : 0, { duration, easing: EASINGS.standard });
|
|
212
|
-
}, [active, duration, progress]);
|
|
213
|
-
return progress;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
209
|
// src/components/Input/Input.tsx
|
|
217
210
|
var webInputResetStyle = reactNative.Platform.OS === "web" ? { outlineStyle: "none", outlineWidth: 0, outlineColor: "transparent", boxShadow: "none" } : {};
|
|
218
|
-
function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = "text", containerStyle, inputWrapperStyle, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }) {
|
|
211
|
+
function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suffixStyle, prefixIcon, suffixIcon, prefixIconColor, suffixIconColor, type = "text", containerStyle, inputWrapperStyle, sheetMode = false, style, onFocus, onBlur, secureTextEntry, editable, accessibilityLabel, ...props }) {
|
|
219
212
|
const { colors } = useTheme();
|
|
220
213
|
const [focused, setFocused] = React3.useState(false);
|
|
221
214
|
const [showPassword, setShowPassword] = React3.useState(false);
|
|
222
|
-
const focusProgress = useColorTransition(focused, {
|
|
223
|
-
duration: focused ? TIMINGS.focusIn.duration : TIMINGS.focusOut.duration
|
|
224
|
-
});
|
|
225
215
|
const isDisabled = disabled || editable === false;
|
|
226
216
|
const isPassword = type === "password";
|
|
227
217
|
const effectiveSecure = isPassword ? !showPassword : secureTextEntry;
|
|
@@ -237,22 +227,45 @@ function Input({ label, error, hint, disabled, prefix, suffix, prefixStyle, suff
|
|
|
237
227
|
},
|
|
238
228
|
/* @__PURE__ */ React3__default.default.createElement(vectorIcons.AntDesign, { name: showPassword ? "eye" : "eye-invisible", size: 20, color: colors.foregroundMuted })
|
|
239
229
|
) : suffixIcon ? renderIcon(suffixIcon, 20, suffixIconColor ?? colors.foregroundMuted) : suffix;
|
|
240
|
-
const
|
|
241
|
-
borderColor: error ? colors.destructive : Animated.interpolateColor(focusProgress.value, [0, 1], [colors.border, colors.primary]),
|
|
242
|
-
borderWidth: error ? 2 : Animated.interpolate(focusProgress.value, [0, 1], [1, 2])
|
|
243
|
-
}));
|
|
230
|
+
const borderColor = error ? colors.destructive : focused ? colors.primary : colors.border;
|
|
244
231
|
return /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: [styles.container, isDisabled && styles.containerDisabled, containerStyle] }, label ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.label, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React3__default.default.createElement(
|
|
245
|
-
|
|
232
|
+
reactNativeEase.EaseView,
|
|
246
233
|
{
|
|
247
234
|
style: [
|
|
248
235
|
styles.inputWrapper,
|
|
249
236
|
{ backgroundColor: isDisabled ? colors.surface : colors.background },
|
|
237
|
+
error && styles.inputWrapperError,
|
|
250
238
|
inputWrapperStyle
|
|
251
|
-
]
|
|
239
|
+
],
|
|
240
|
+
animate: { borderColor },
|
|
241
|
+
transition: COLOR_TRANSITION
|
|
252
242
|
},
|
|
253
|
-
/* @__PURE__ */ React3__default.default.createElement(Animated__default.default.View, { style: [styles.borderOverlay, borderAnimStyle], pointerEvents: "none" }),
|
|
254
243
|
effectivePrefix ? typeof effectivePrefix === "string" ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.prefixText, { color: colors.foregroundMuted }, prefixStyle], allowFontScaling: true }, effectivePrefix) : /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.prefixContainer }, effectivePrefix) : null,
|
|
255
|
-
/* @__PURE__ */ React3__default.default.createElement(
|
|
244
|
+
sheetMode ? /* @__PURE__ */ React3__default.default.createElement(
|
|
245
|
+
bottomSheet.BottomSheetTextInput,
|
|
246
|
+
{
|
|
247
|
+
style: [
|
|
248
|
+
styles.input,
|
|
249
|
+
{ color: colors.foreground },
|
|
250
|
+
webInputResetStyle,
|
|
251
|
+
style
|
|
252
|
+
],
|
|
253
|
+
onFocus: (e) => {
|
|
254
|
+
setFocused(true);
|
|
255
|
+
onFocus?.(e);
|
|
256
|
+
},
|
|
257
|
+
onBlur: (e) => {
|
|
258
|
+
setFocused(false);
|
|
259
|
+
onBlur?.(e);
|
|
260
|
+
},
|
|
261
|
+
placeholderTextColor: colors.foregroundMuted,
|
|
262
|
+
allowFontScaling: true,
|
|
263
|
+
secureTextEntry: effectiveSecure,
|
|
264
|
+
editable: isDisabled ? false : editable,
|
|
265
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
266
|
+
...props
|
|
267
|
+
}
|
|
268
|
+
) : /* @__PURE__ */ React3__default.default.createElement(
|
|
256
269
|
reactNative.TextInput,
|
|
257
270
|
{
|
|
258
271
|
style: [
|
|
@@ -302,16 +315,14 @@ var styles = reactNative.StyleSheet.create({
|
|
|
302
315
|
inputWrapper: {
|
|
303
316
|
flexDirection: "row",
|
|
304
317
|
alignItems: "center",
|
|
305
|
-
// Border lives on borderOverlay (absolute) so its 1px→2px focus change
|
|
306
|
-
// never resizes this box. Wrapper itself carries no border.
|
|
307
318
|
borderRadius: 8,
|
|
319
|
+
borderWidth: 1,
|
|
308
320
|
paddingHorizontal: s(14),
|
|
309
321
|
paddingVertical: vs(11),
|
|
310
322
|
minHeight: 48
|
|
311
323
|
},
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
borderRadius: 8
|
|
324
|
+
inputWrapperError: {
|
|
325
|
+
borderWidth: 2
|
|
315
326
|
},
|
|
316
327
|
input: {
|
|
317
328
|
fontFamily: "Sohne-Regular",
|
package/dist/Input.mjs
CHANGED
package/dist/ListItem.d.mts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ViewStyle, TextStyle } from 'react-native';
|
|
2
|
+
import { ImageSourcePropType, ViewStyle, TextStyle } from 'react-native';
|
|
3
3
|
|
|
4
4
|
type ListItemVariant = 'plain' | 'card';
|
|
5
5
|
interface ListItemProps {
|
|
6
|
+
/**
|
|
7
|
+
* Image source for the left slot. If provided, renders an Image (40×40, borderRadius 8).
|
|
8
|
+
* Takes precedence over `leftRender` and `leftIcon`.
|
|
9
|
+
*/
|
|
10
|
+
imageSource?: ImageSourcePropType;
|
|
6
11
|
/**
|
|
7
12
|
* Arbitrary content rendered on the left (avatar, icon, image, etc.).
|
|
8
13
|
* Rendered inside a 44×44 aligned container.
|
|
@@ -53,12 +58,14 @@ interface ListItemProps {
|
|
|
53
58
|
titleStyle?: TextStyle;
|
|
54
59
|
/** Style applied to the subtitle Text. */
|
|
55
60
|
subtitleStyle?: TextStyle;
|
|
61
|
+
/** Max lines for the subtitle. Defaults to 2. */
|
|
62
|
+
subtitleNumberOfLines?: number;
|
|
56
63
|
/** Style applied to the caption Text. */
|
|
57
64
|
captionStyle?: TextStyle;
|
|
58
65
|
/** Accessibility label override. Defaults to the title. */
|
|
59
66
|
accessibilityLabel?: string;
|
|
60
67
|
}
|
|
61
|
-
declare function ListItemBase({ leftRender, rightRender, trailing, icon, leftIcon, rightIcon, leftIconColor, rightIconColor, title, subtitle, caption, variant, showChevron, showSeparator, onPress, disabled, style, titleStyle, subtitleStyle, captionStyle, accessibilityLabel, }: ListItemProps): React.JSX.Element;
|
|
68
|
+
declare function ListItemBase({ imageSource, leftRender, rightRender, trailing, icon, leftIcon, rightIcon, leftIconColor, rightIconColor, title, subtitle, caption, variant, showChevron, showSeparator, onPress, disabled, style, titleStyle, subtitleStyle, subtitleNumberOfLines, captionStyle, accessibilityLabel, }: ListItemProps): React.JSX.Element;
|
|
62
69
|
declare const ListItem: React.MemoExoticComponent<typeof ListItemBase>;
|
|
63
70
|
|
|
64
71
|
export { ListItem, type ListItemProps };
|
package/dist/ListItem.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ViewStyle, TextStyle } from 'react-native';
|
|
2
|
+
import { ImageSourcePropType, ViewStyle, TextStyle } from 'react-native';
|
|
3
3
|
|
|
4
4
|
type ListItemVariant = 'plain' | 'card';
|
|
5
5
|
interface ListItemProps {
|
|
6
|
+
/**
|
|
7
|
+
* Image source for the left slot. If provided, renders an Image (40×40, borderRadius 8).
|
|
8
|
+
* Takes precedence over `leftRender` and `leftIcon`.
|
|
9
|
+
*/
|
|
10
|
+
imageSource?: ImageSourcePropType;
|
|
6
11
|
/**
|
|
7
12
|
* Arbitrary content rendered on the left (avatar, icon, image, etc.).
|
|
8
13
|
* Rendered inside a 44×44 aligned container.
|
|
@@ -53,12 +58,14 @@ interface ListItemProps {
|
|
|
53
58
|
titleStyle?: TextStyle;
|
|
54
59
|
/** Style applied to the subtitle Text. */
|
|
55
60
|
subtitleStyle?: TextStyle;
|
|
61
|
+
/** Max lines for the subtitle. Defaults to 2. */
|
|
62
|
+
subtitleNumberOfLines?: number;
|
|
56
63
|
/** Style applied to the caption Text. */
|
|
57
64
|
captionStyle?: TextStyle;
|
|
58
65
|
/** Accessibility label override. Defaults to the title. */
|
|
59
66
|
accessibilityLabel?: string;
|
|
60
67
|
}
|
|
61
|
-
declare function ListItemBase({ leftRender, rightRender, trailing, icon, leftIcon, rightIcon, leftIconColor, rightIconColor, title, subtitle, caption, variant, showChevron, showSeparator, onPress, disabled, style, titleStyle, subtitleStyle, captionStyle, accessibilityLabel, }: ListItemProps): React.JSX.Element;
|
|
68
|
+
declare function ListItemBase({ imageSource, leftRender, rightRender, trailing, icon, leftIcon, rightIcon, leftIconColor, rightIconColor, title, subtitle, caption, variant, showChevron, showSeparator, onPress, disabled, style, titleStyle, subtitleStyle, subtitleNumberOfLines, captionStyle, accessibilityLabel, }: ListItemProps): React.JSX.Element;
|
|
62
69
|
declare const ListItem: React.MemoExoticComponent<typeof ListItemBase>;
|
|
63
70
|
|
|
64
71
|
export { ListItem, type ListItemProps };
|