@harkenapp/sdk-react-native 0.0.1-alpha.1

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 (235) hide show
  1. package/README.md +67 -0
  2. package/app.plugin.cjs +135 -0
  3. package/app.plugin.js +1 -0
  4. package/dist/api/client.d.ts +67 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +163 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/api/errors.d.ts +46 -0
  9. package/dist/api/errors.d.ts.map +1 -0
  10. package/dist/api/errors.js +72 -0
  11. package/dist/api/errors.js.map +1 -0
  12. package/dist/api/index.d.ts +7 -0
  13. package/dist/api/index.d.ts.map +1 -0
  14. package/dist/api/index.js +20 -0
  15. package/dist/api/index.js.map +1 -0
  16. package/dist/api/retry.d.ts +29 -0
  17. package/dist/api/retry.d.ts.map +1 -0
  18. package/dist/api/retry.js +74 -0
  19. package/dist/api/retry.js.map +1 -0
  20. package/dist/attachments/FeedbackSheet.d.ts +88 -0
  21. package/dist/attachments/FeedbackSheet.d.ts.map +1 -0
  22. package/dist/attachments/FeedbackSheet.js +250 -0
  23. package/dist/attachments/FeedbackSheet.js.map +1 -0
  24. package/dist/attachments/index.d.ts +20 -0
  25. package/dist/attachments/index.d.ts.map +1 -0
  26. package/dist/attachments/index.js +40 -0
  27. package/dist/attachments/index.js.map +1 -0
  28. package/dist/components/AttachmentGrid.d.ts +94 -0
  29. package/dist/components/AttachmentGrid.d.ts.map +1 -0
  30. package/dist/components/AttachmentGrid.js +132 -0
  31. package/dist/components/AttachmentGrid.js.map +1 -0
  32. package/dist/components/AttachmentPicker.d.ts +98 -0
  33. package/dist/components/AttachmentPicker.d.ts.map +1 -0
  34. package/dist/components/AttachmentPicker.js +297 -0
  35. package/dist/components/AttachmentPicker.js.map +1 -0
  36. package/dist/components/AttachmentPreview.d.ts +78 -0
  37. package/dist/components/AttachmentPreview.d.ts.map +1 -0
  38. package/dist/components/AttachmentPreview.js +133 -0
  39. package/dist/components/AttachmentPreview.js.map +1 -0
  40. package/dist/components/CategorySelector.d.ts +77 -0
  41. package/dist/components/CategorySelector.d.ts.map +1 -0
  42. package/dist/components/CategorySelector.js +117 -0
  43. package/dist/components/CategorySelector.js.map +1 -0
  44. package/dist/components/FeedbackForm.d.ts +50 -0
  45. package/dist/components/FeedbackForm.d.ts.map +1 -0
  46. package/dist/components/FeedbackForm.js +141 -0
  47. package/dist/components/FeedbackForm.js.map +1 -0
  48. package/dist/components/FeedbackSheet.d.ts +75 -0
  49. package/dist/components/FeedbackSheet.d.ts.map +1 -0
  50. package/dist/components/FeedbackSheet.js +215 -0
  51. package/dist/components/FeedbackSheet.js.map +1 -0
  52. package/dist/components/ThemedButton.d.ts +23 -0
  53. package/dist/components/ThemedButton.d.ts.map +1 -0
  54. package/dist/components/ThemedButton.js +77 -0
  55. package/dist/components/ThemedButton.js.map +1 -0
  56. package/dist/components/ThemedText.d.ts +16 -0
  57. package/dist/components/ThemedText.d.ts.map +1 -0
  58. package/dist/components/ThemedText.js +44 -0
  59. package/dist/components/ThemedText.js.map +1 -0
  60. package/dist/components/ThemedTextInput.d.ts +13 -0
  61. package/dist/components/ThemedTextInput.d.ts.map +1 -0
  62. package/dist/components/ThemedTextInput.js +76 -0
  63. package/dist/components/ThemedTextInput.js.map +1 -0
  64. package/dist/components/UploadStatusOverlay.d.ts +82 -0
  65. package/dist/components/UploadStatusOverlay.d.ts.map +1 -0
  66. package/dist/components/UploadStatusOverlay.js +319 -0
  67. package/dist/components/UploadStatusOverlay.js.map +1 -0
  68. package/dist/components/index.d.ts +19 -0
  69. package/dist/components/index.d.ts.map +1 -0
  70. package/dist/components/index.js +28 -0
  71. package/dist/components/index.js.map +1 -0
  72. package/dist/context/HarkenContext.d.ts +62 -0
  73. package/dist/context/HarkenContext.d.ts.map +1 -0
  74. package/dist/context/HarkenContext.js +128 -0
  75. package/dist/context/HarkenContext.js.map +1 -0
  76. package/dist/context/index.d.ts +3 -0
  77. package/dist/context/index.d.ts.map +1 -0
  78. package/dist/context/index.js +7 -0
  79. package/dist/context/index.js.map +1 -0
  80. package/dist/domain/index.d.ts +3 -0
  81. package/dist/domain/index.d.ts.map +1 -0
  82. package/dist/domain/index.js +7 -0
  83. package/dist/domain/index.js.map +1 -0
  84. package/dist/domain/upload-queue.d.ts +116 -0
  85. package/dist/domain/upload-queue.d.ts.map +1 -0
  86. package/dist/domain/upload-queue.js +34 -0
  87. package/dist/domain/upload-queue.js.map +1 -0
  88. package/dist/hooks/index.d.ts +6 -0
  89. package/dist/hooks/index.d.ts.map +1 -0
  90. package/dist/hooks/index.js +16 -0
  91. package/dist/hooks/index.js.map +1 -0
  92. package/dist/hooks/useAnonymousId.d.ts +28 -0
  93. package/dist/hooks/useAnonymousId.d.ts.map +1 -0
  94. package/dist/hooks/useAnonymousId.js +59 -0
  95. package/dist/hooks/useAnonymousId.js.map +1 -0
  96. package/dist/hooks/useAttachmentPicker.d.ts +84 -0
  97. package/dist/hooks/useAttachmentPicker.d.ts.map +1 -0
  98. package/dist/hooks/useAttachmentPicker.js +181 -0
  99. package/dist/hooks/useAttachmentPicker.js.map +1 -0
  100. package/dist/hooks/useAttachmentStatus.d.ts +51 -0
  101. package/dist/hooks/useAttachmentStatus.d.ts.map +1 -0
  102. package/dist/hooks/useAttachmentStatus.js +69 -0
  103. package/dist/hooks/useAttachmentStatus.js.map +1 -0
  104. package/dist/hooks/useAttachmentUpload.d.ts +101 -0
  105. package/dist/hooks/useAttachmentUpload.d.ts.map +1 -0
  106. package/dist/hooks/useAttachmentUpload.js +293 -0
  107. package/dist/hooks/useAttachmentUpload.js.map +1 -0
  108. package/dist/hooks/useFeedback.d.ts +55 -0
  109. package/dist/hooks/useFeedback.d.ts.map +1 -0
  110. package/dist/hooks/useFeedback.js +96 -0
  111. package/dist/hooks/useFeedback.js.map +1 -0
  112. package/dist/hooks/useHarkenContext.d.ts +25 -0
  113. package/dist/hooks/useHarkenContext.d.ts.map +1 -0
  114. package/dist/hooks/useHarkenContext.js +35 -0
  115. package/dist/hooks/useHarkenContext.js.map +1 -0
  116. package/dist/hooks/useHarkenTheme.d.ts +26 -0
  117. package/dist/hooks/useHarkenTheme.d.ts.map +1 -0
  118. package/dist/hooks/useHarkenTheme.js +36 -0
  119. package/dist/hooks/useHarkenTheme.js.map +1 -0
  120. package/dist/index.d.ts +49 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +91 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/services/index.d.ts +4 -0
  125. package/dist/services/index.d.ts.map +1 -0
  126. package/dist/services/index.js +9 -0
  127. package/dist/services/index.js.map +1 -0
  128. package/dist/services/uploadQueueService.d.ts +193 -0
  129. package/dist/services/uploadQueueService.d.ts.map +1 -0
  130. package/dist/services/uploadQueueService.js +623 -0
  131. package/dist/services/uploadQueueService.js.map +1 -0
  132. package/dist/services/uploadQueueStorage.d.ts +30 -0
  133. package/dist/services/uploadQueueStorage.d.ts.map +1 -0
  134. package/dist/services/uploadQueueStorage.js +77 -0
  135. package/dist/services/uploadQueueStorage.js.map +1 -0
  136. package/dist/storage/IdentityStore.d.ts +38 -0
  137. package/dist/storage/IdentityStore.d.ts.map +1 -0
  138. package/dist/storage/IdentityStore.js +83 -0
  139. package/dist/storage/IdentityStore.js.map +1 -0
  140. package/dist/storage/SecureStoreAdapter.d.ts +28 -0
  141. package/dist/storage/SecureStoreAdapter.d.ts.map +1 -0
  142. package/dist/storage/SecureStoreAdapter.js +52 -0
  143. package/dist/storage/SecureStoreAdapter.js.map +1 -0
  144. package/dist/storage/defaultStorage.d.ts +20 -0
  145. package/dist/storage/defaultStorage.d.ts.map +1 -0
  146. package/dist/storage/defaultStorage.js +131 -0
  147. package/dist/storage/defaultStorage.js.map +1 -0
  148. package/dist/storage/index.d.ts +6 -0
  149. package/dist/storage/index.d.ts.map +1 -0
  150. package/dist/storage/index.js +13 -0
  151. package/dist/storage/index.js.map +1 -0
  152. package/dist/storage/types.d.ts +32 -0
  153. package/dist/storage/types.d.ts.map +1 -0
  154. package/dist/storage/types.js +11 -0
  155. package/dist/storage/types.js.map +1 -0
  156. package/dist/theme/defaults.d.ts +43 -0
  157. package/dist/theme/defaults.d.ts.map +1 -0
  158. package/dist/theme/defaults.js +128 -0
  159. package/dist/theme/defaults.js.map +1 -0
  160. package/dist/theme/index.d.ts +3 -0
  161. package/dist/theme/index.d.ts.map +1 -0
  162. package/dist/theme/index.js +14 -0
  163. package/dist/theme/index.js.map +1 -0
  164. package/dist/theme/types.d.ts +136 -0
  165. package/dist/theme/types.d.ts.map +1 -0
  166. package/dist/theme/types.js +3 -0
  167. package/dist/theme/types.js.map +1 -0
  168. package/dist/types/config.d.ts +100 -0
  169. package/dist/types/config.d.ts.map +1 -0
  170. package/dist/types/config.js +3 -0
  171. package/dist/types/config.js.map +1 -0
  172. package/dist/types/index.d.ts +3 -0
  173. package/dist/types/index.d.ts.map +1 -0
  174. package/dist/types/index.js +3 -0
  175. package/dist/types/index.js.map +1 -0
  176. package/dist/types/openapi.d.ts +601 -0
  177. package/dist/types/openapi.d.ts.map +1 -0
  178. package/dist/types/openapi.js +7 -0
  179. package/dist/types/openapi.js.map +1 -0
  180. package/dist/utils/index.d.ts +2 -0
  181. package/dist/utils/index.d.ts.map +1 -0
  182. package/dist/utils/index.js +6 -0
  183. package/dist/utils/index.js.map +1 -0
  184. package/dist/utils/uuid.d.ts +10 -0
  185. package/dist/utils/uuid.d.ts.map +1 -0
  186. package/dist/utils/uuid.js +60 -0
  187. package/dist/utils/uuid.js.map +1 -0
  188. package/package.json +124 -0
  189. package/src/@types/expo-file-system-legacy.d.ts +13 -0
  190. package/src/api/client.ts +250 -0
  191. package/src/api/errors.ts +84 -0
  192. package/src/api/index.ts +15 -0
  193. package/src/api/retry.ts +99 -0
  194. package/src/attachments/FeedbackSheet.tsx +400 -0
  195. package/src/attachments/index.ts +70 -0
  196. package/src/components/AttachmentGrid.tsx +247 -0
  197. package/src/components/AttachmentPicker.tsx +391 -0
  198. package/src/components/AttachmentPreview.tsx +210 -0
  199. package/src/components/CategorySelector.tsx +174 -0
  200. package/src/components/FeedbackForm.tsx +216 -0
  201. package/src/components/FeedbackSheet.tsx +321 -0
  202. package/src/components/ThemedButton.tsx +127 -0
  203. package/src/components/ThemedText.tsx +65 -0
  204. package/src/components/ThemedTextInput.tsx +65 -0
  205. package/src/components/UploadStatusOverlay.tsx +440 -0
  206. package/src/components/index.ts +39 -0
  207. package/src/context/HarkenContext.tsx +129 -0
  208. package/src/context/index.ts +2 -0
  209. package/src/domain/index.ts +12 -0
  210. package/src/domain/upload-queue.ts +131 -0
  211. package/src/hooks/index.ts +10 -0
  212. package/src/hooks/useAnonymousId.ts +68 -0
  213. package/src/hooks/useAttachmentPicker.ts +243 -0
  214. package/src/hooks/useAttachmentStatus.ts +86 -0
  215. package/src/hooks/useAttachmentUpload.ts +370 -0
  216. package/src/hooks/useFeedback.ts +139 -0
  217. package/src/hooks/useHarkenContext.ts +35 -0
  218. package/src/hooks/useHarkenTheme.ts +36 -0
  219. package/src/index.ts +168 -0
  220. package/src/services/index.ts +11 -0
  221. package/src/services/uploadQueueService.ts +727 -0
  222. package/src/services/uploadQueueStorage.ts +78 -0
  223. package/src/storage/IdentityStore.ts +89 -0
  224. package/src/storage/SecureStoreAdapter.ts +59 -0
  225. package/src/storage/defaultStorage.ts +109 -0
  226. package/src/storage/index.ts +5 -0
  227. package/src/storage/types.ts +34 -0
  228. package/src/theme/defaults.ts +151 -0
  229. package/src/theme/index.ts +23 -0
  230. package/src/theme/types.ts +157 -0
  231. package/src/types/config.ts +112 -0
  232. package/src/types/index.ts +10 -0
  233. package/src/types/openapi.ts +601 -0
  234. package/src/utils/index.ts +1 -0
  235. package/src/utils/uuid.ts +77 -0
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FeedbackSheet = FeedbackSheet;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const hooks_1 = require("../hooks");
40
+ const ThemedText_1 = require("./ThemedText");
41
+ const ThemedTextInput_1 = require("./ThemedTextInput");
42
+ const ThemedButton_1 = require("./ThemedButton");
43
+ const CategorySelector_1 = require("./CategorySelector");
44
+ /**
45
+ * A batteries-included feedback form component.
46
+ *
47
+ * Unlike `FeedbackForm` which is a "dumb" UI component requiring manual
48
+ * wiring, `FeedbackSheet` handles everything internally:
49
+ * - API submission via `useFeedback` hook
50
+ * - Success/error alerts
51
+ * - Form state management
52
+ * - Keyboard handling
53
+ *
54
+ * For attachment support, import from '@harkenapp/sdk-react-native/attachments'.
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * // Minimal usage
59
+ * <FeedbackSheet onSuccess={() => navigation.goBack()} />
60
+ *
61
+ * // With customization
62
+ * <FeedbackSheet
63
+ * title="Report a Bug"
64
+ * requireCategory
65
+ * categories={[
66
+ * { value: 'crash', label: 'App Crash', icon: '💥' },
67
+ * { value: 'visual', label: 'Visual Bug', icon: '👁️' },
68
+ * ]}
69
+ * onSuccess={(result) => {
70
+ * analytics.track('feedback_submitted');
71
+ * navigation.goBack();
72
+ * }}
73
+ * onCancel={() => navigation.goBack()}
74
+ * />
75
+ * ```
76
+ */
77
+ function FeedbackSheet({ onSuccess, onError, onCancel, title = 'Send Feedback', placeholder = 'What would you like to share?', submitLabel = 'Submit', cancelLabel = 'Cancel', categories = CategorySelector_1.DEFAULT_CATEGORIES, requireCategory = false, minMessageLength = 1, maxMessageLength = 5000, successMessage = 'Thank you for your feedback!', showSuccessAlert = true, clearOnSuccess = true, containerStyle, formStyle, }) {
78
+ const theme = (0, hooks_1.useHarkenTheme)();
79
+ const { submitFeedback, isSubmitting, error, clearError, isInitializing } = (0, hooks_1.useFeedback)();
80
+ const [message, setMessage] = (0, react_1.useState)('');
81
+ const [category, setCategory] = (0, react_1.useState)(null);
82
+ const trimmedMessage = message.trim();
83
+ const isMessageValid = trimmedMessage.length >= minMessageLength &&
84
+ trimmedMessage.length <= maxMessageLength;
85
+ const isCategoryValid = !requireCategory || category !== null;
86
+ const canSubmit = isMessageValid && isCategoryValid && !isSubmitting && !isInitializing;
87
+ const resetForm = (0, react_1.useCallback)(() => {
88
+ setMessage('');
89
+ setCategory(null);
90
+ clearError();
91
+ }, [clearError]);
92
+ const handleSubmit = (0, react_1.useCallback)(async () => {
93
+ if (!canSubmit)
94
+ return;
95
+ clearError();
96
+ try {
97
+ const result = await submitFeedback({
98
+ message: trimmedMessage,
99
+ category: category ?? 'other',
100
+ });
101
+ if (showSuccessAlert && successMessage) {
102
+ react_native_1.Alert.alert('Success', successMessage, [
103
+ {
104
+ text: 'OK',
105
+ onPress: () => {
106
+ if (clearOnSuccess) {
107
+ resetForm();
108
+ }
109
+ onSuccess?.(result);
110
+ },
111
+ },
112
+ ]);
113
+ }
114
+ else {
115
+ if (clearOnSuccess) {
116
+ resetForm();
117
+ }
118
+ onSuccess?.(result);
119
+ }
120
+ }
121
+ catch (e) {
122
+ const errorMessage = e instanceof Error ? e.message : 'Failed to submit feedback. Please try again.';
123
+ react_native_1.Alert.alert('Submission Failed', errorMessage);
124
+ onError?.(e instanceof Error ? e : new Error(errorMessage));
125
+ }
126
+ }, [
127
+ canSubmit,
128
+ clearError,
129
+ submitFeedback,
130
+ trimmedMessage,
131
+ category,
132
+ showSuccessAlert,
133
+ successMessage,
134
+ clearOnSuccess,
135
+ resetForm,
136
+ onSuccess,
137
+ onError,
138
+ ]);
139
+ const handleCancel = (0, react_1.useCallback)(() => {
140
+ resetForm();
141
+ onCancel?.();
142
+ }, [resetForm, onCancel]);
143
+ const baseContainerStyle = {
144
+ flex: 1,
145
+ backgroundColor: theme.colors.background,
146
+ };
147
+ const contentStyle = {
148
+ flexGrow: 1,
149
+ padding: theme.spacing.lg,
150
+ };
151
+ const sectionStyle = {
152
+ marginBottom: theme.spacing.lg,
153
+ };
154
+ const buttonRowStyle = {
155
+ flexDirection: 'row',
156
+ gap: theme.spacing.sm,
157
+ marginTop: theme.spacing.md,
158
+ };
159
+ const characterCount = trimmedMessage.length;
160
+ const showCharacterWarning = characterCount > maxMessageLength * 0.9;
161
+ if (isInitializing) {
162
+ return (<react_native_1.View style={[baseContainerStyle, containerStyle, { justifyContent: 'center', alignItems: 'center' }]}>
163
+ <ThemedText_1.ThemedText variant="body" secondary>
164
+ Initializing...
165
+ </ThemedText_1.ThemedText>
166
+ </react_native_1.View>);
167
+ }
168
+ return (<react_native_1.KeyboardAvoidingView behavior={react_native_1.Platform.OS === 'ios' ? 'padding' : 'height'} style={[baseContainerStyle, containerStyle]}>
169
+ <react_native_1.ScrollView contentContainerStyle={[contentStyle, formStyle]} keyboardShouldPersistTaps="handled">
170
+ {/* Title */}
171
+ <react_native_1.View style={sectionStyle}>
172
+ <ThemedText_1.ThemedText variant="title">{title}</ThemedText_1.ThemedText>
173
+ </react_native_1.View>
174
+
175
+ {/* Category selector */}
176
+ <react_native_1.View style={sectionStyle}>
177
+ <ThemedText_1.ThemedText variant="label" secondary style={{ marginBottom: theme.spacing.sm }}>
178
+ Category{requireCategory ? '' : ' (optional)'}
179
+ </ThemedText_1.ThemedText>
180
+ <CategorySelector_1.CategorySelector value={category} onChange={setCategory} categories={categories} disabled={isSubmitting}/>
181
+ </react_native_1.View>
182
+
183
+ {/* Message input */}
184
+ <react_native_1.View style={sectionStyle}>
185
+ <ThemedText_1.ThemedText variant="label" secondary style={{ marginBottom: theme.spacing.sm }}>
186
+ Message
187
+ </ThemedText_1.ThemedText>
188
+ <ThemedTextInput_1.ThemedTextInput value={message} onChangeText={setMessage} placeholder={placeholder} multiline numberOfLines={4} textAlignVertical="top" editable={!isSubmitting} style={{ minHeight: 120 }} maxLength={maxMessageLength + 100}/>
189
+ {showCharacterWarning && (<ThemedText_1.ThemedText variant="caption" color={characterCount > maxMessageLength
190
+ ? theme.colors.error
191
+ : theme.colors.textSecondary} style={{ marginTop: theme.spacing.xs, textAlign: 'right' }}>
192
+ {characterCount}/{maxMessageLength}
193
+ </ThemedText_1.ThemedText>)}
194
+ </react_native_1.View>
195
+
196
+ {/* Error display */}
197
+ {error && (<react_native_1.View style={{ marginBottom: theme.spacing.md }}>
198
+ <ThemedText_1.ThemedText variant="caption" color={theme.colors.error}>
199
+ {error.message}
200
+ </ThemedText_1.ThemedText>
201
+ </react_native_1.View>)}
202
+
203
+ {/* Buttons */}
204
+ <react_native_1.View style={buttonRowStyle}>
205
+ {onCancel && (<react_native_1.View style={{ flex: 1 }}>
206
+ <ThemedButton_1.ThemedButton title={cancelLabel} variant="secondary" onPress={handleCancel} disabled={isSubmitting} fullWidth/>
207
+ </react_native_1.View>)}
208
+ <react_native_1.View style={{ flex: onCancel ? 1 : undefined }}>
209
+ <ThemedButton_1.ThemedButton title={submitLabel} variant="primary" onPress={handleSubmit} disabled={!canSubmit} loading={isSubmitting} fullWidth={!!onCancel}/>
210
+ </react_native_1.View>
211
+ </react_native_1.View>
212
+ </react_native_1.ScrollView>
213
+ </react_native_1.KeyboardAvoidingView>);
214
+ }
215
+ //# sourceMappingURL=FeedbackSheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeedbackSheet.js","sourceRoot":"","sources":["../../src/components/FeedbackSheet.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import type { PressableProps, ViewStyle, StyleProp } from 'react-native';
3
+ export type ButtonVariant = 'primary' | 'secondary' | 'ghost';
4
+ export interface ThemedButtonProps extends Omit<PressableProps, 'children' | 'style'> {
5
+ /** Button text */
6
+ title: string;
7
+ /** Button variant */
8
+ variant?: ButtonVariant;
9
+ /** Loading state */
10
+ loading?: boolean;
11
+ /** Full width button */
12
+ fullWidth?: boolean;
13
+ /**
14
+ * Additional styles for the button container.
15
+ * Note: Function styles are not supported; use static StyleProp<ViewStyle>.
16
+ */
17
+ style?: StyleProp<ViewStyle>;
18
+ }
19
+ /**
20
+ * Themed button component with Harken styling.
21
+ */
22
+ export declare function ThemedButton({ title, variant, loading, fullWidth, disabled, style, ...props }: ThemedButtonProps): React.JSX.Element;
23
+ //# sourceMappingURL=ThemedButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemedButton.d.ts","sourceRoot":"","sources":["../../src/components/ThemedButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAIzE,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC;IACnF,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,oBAAoB;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wBAAwB;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,OAAmB,EACnB,OAAe,EACf,SAAiB,EACjB,QAAQ,EACR,KAAK,EACL,GAAG,KAAK,EACT,EAAE,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAuFvC"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ThemedButton = ThemedButton;
7
+ const react_1 = __importDefault(require("react"));
8
+ const react_native_1 = require("react-native");
9
+ const hooks_1 = require("../hooks");
10
+ const ThemedText_1 = require("./ThemedText");
11
+ /**
12
+ * Themed button component with Harken styling.
13
+ */
14
+ function ThemedButton({ title, variant = 'primary', loading = false, fullWidth = false, disabled, style, ...props }) {
15
+ const theme = (0, hooks_1.useHarkenTheme)();
16
+ const getBackgroundColor = (pressed) => {
17
+ if (disabled) {
18
+ return variant === 'primary'
19
+ ? theme.colors.border
20
+ : 'transparent';
21
+ }
22
+ switch (variant) {
23
+ case 'primary':
24
+ return pressed ? theme.colors.primaryPressed : theme.colors.primary;
25
+ case 'secondary':
26
+ return pressed ? theme.colors.border : theme.colors.backgroundSecondary;
27
+ case 'ghost':
28
+ return pressed ? theme.colors.backgroundSecondary : 'transparent';
29
+ }
30
+ };
31
+ const getTextColor = () => {
32
+ if (disabled) {
33
+ return theme.colors.textPlaceholder;
34
+ }
35
+ switch (variant) {
36
+ case 'primary':
37
+ return theme.colors.textOnPrimary;
38
+ case 'secondary':
39
+ case 'ghost':
40
+ return theme.colors.text;
41
+ }
42
+ };
43
+ const getBorderColor = () => {
44
+ switch (variant) {
45
+ case 'secondary':
46
+ return theme.colors.border;
47
+ default:
48
+ return 'transparent';
49
+ }
50
+ };
51
+ // Flatten the style prop to handle arrays and registered styles
52
+ const flattenedStyle = style ? react_native_1.StyleSheet.flatten(style) : undefined;
53
+ return (<react_native_1.Pressable disabled={disabled || loading} style={({ pressed }) => {
54
+ const baseStyle = {
55
+ backgroundColor: getBackgroundColor(pressed),
56
+ borderWidth: variant === 'secondary' ? 1 : 0,
57
+ borderColor: getBorderColor(),
58
+ borderRadius: theme.radii.md,
59
+ paddingVertical: theme.spacing.sm + 4,
60
+ paddingHorizontal: theme.spacing.md,
61
+ alignItems: 'center',
62
+ justifyContent: 'center',
63
+ flexDirection: 'row',
64
+ minHeight: 48,
65
+ opacity: disabled ? 0.6 : 1,
66
+ };
67
+ if (fullWidth) {
68
+ baseStyle.width = '100%';
69
+ }
70
+ return [baseStyle, flattenedStyle];
71
+ }} {...props}>
72
+ {loading ? (<react_native_1.ActivityIndicator color={getTextColor()} size="small"/>) : (<ThemedText_1.ThemedText variant="label" color={getTextColor()}>
73
+ {title}
74
+ </ThemedText_1.ThemedText>)}
75
+ </react_native_1.Pressable>);
76
+ }
77
+ //# sourceMappingURL=ThemedButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemedButton.js","sourceRoot":"","sources":["../../src/components/ThemedButton.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import type { TextProps } from 'react-native';
3
+ export type TextVariant = 'title' | 'body' | 'label' | 'caption';
4
+ export interface ThemedTextProps extends TextProps {
5
+ /** Text variant determining size and weight */
6
+ variant?: TextVariant;
7
+ /** Text color override (defaults to theme text color) */
8
+ color?: string;
9
+ /** Whether to use secondary text color */
10
+ secondary?: boolean;
11
+ }
12
+ /**
13
+ * Themed text component that uses Harken theme typography.
14
+ */
15
+ export declare function ThemedText({ variant, color, secondary, style, children, ...props }: ThemedTextProps): React.JSX.Element;
16
+ //# sourceMappingURL=ThemedText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemedText.d.ts","sourceRoot":"","sources":["../../src/components/ThemedText.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,cAAc,CAAC;AAGzD,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,+CAA+C;IAC/C,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAgB,EAChB,KAAK,EACL,SAAiB,EACjB,KAAK,EACL,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,eAAe,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAsCrC"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ThemedText = ThemedText;
7
+ const react_1 = __importDefault(require("react"));
8
+ const react_native_1 = require("react-native");
9
+ const hooks_1 = require("../hooks");
10
+ /**
11
+ * Themed text component that uses Harken theme typography.
12
+ */
13
+ function ThemedText({ variant = 'body', color, secondary = false, style, children, ...props }) {
14
+ const theme = (0, hooks_1.useHarkenTheme)();
15
+ const variantStyles = {
16
+ title: {
17
+ fontSize: theme.typography.titleSize,
18
+ lineHeight: theme.typography.titleSize * theme.typography.titleLineHeight,
19
+ fontWeight: theme.typography.titleWeight,
20
+ fontFamily: theme.typography.fontFamilyHeading ?? theme.typography.fontFamily,
21
+ },
22
+ body: {
23
+ fontSize: theme.typography.bodySize,
24
+ lineHeight: theme.typography.bodySize * theme.typography.bodyLineHeight,
25
+ fontWeight: theme.typography.bodyWeight,
26
+ fontFamily: theme.typography.fontFamily,
27
+ },
28
+ label: {
29
+ fontSize: theme.typography.labelSize,
30
+ fontWeight: theme.typography.labelWeight,
31
+ fontFamily: theme.typography.fontFamily,
32
+ },
33
+ caption: {
34
+ fontSize: theme.typography.captionSize,
35
+ fontWeight: theme.typography.captionWeight,
36
+ fontFamily: theme.typography.fontFamily,
37
+ },
38
+ };
39
+ const textColor = color ?? (secondary ? theme.colors.textSecondary : theme.colors.text);
40
+ return (<react_native_1.Text style={[variantStyles[variant], { color: textColor }, style]} {...props}>
41
+ {children}
42
+ </react_native_1.Text>);
43
+ }
44
+ //# sourceMappingURL=ThemedText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemedText.js","sourceRoot":"","sources":["../../src/components/ThemedText.tsx"],"names":[],"mappings":";;;;;AAmBA,gCA6CC;AAhED,kDAA0B;AAC1B,+CAAoC;AAEpC,oCAA0C;AAa1C;;GAEG;AACH,SAAgB,UAAU,CAAC,EACzB,OAAO,GAAG,MAAM,EAChB,KAAK,EACL,SAAS,GAAG,KAAK,EACjB,KAAK,EACL,QAAQ,EACR,GAAG,KAAK,EACQ;IAChB,MAAM,KAAK,GAAG,IAAA,sBAAc,GAAE,CAAC;IAE/B,MAAM,aAAa,GAAmC;QACpD,KAAK,EAAE;YACL,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;YACpC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,GAAG,KAAK,CAAC,UAAU,CAAC,eAAe;YACzE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;YACxC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,iBAAiB,IAAI,KAAK,CAAC,UAAU,CAAC,UAAU;SAC9E;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ;YACnC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,cAAc;YACvE,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;YACvC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;SACxC;QACD,KAAK,EAAE;YACL,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS;YACpC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;YACxC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;SACxC;QACD,OAAO,EAAE;YACP,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,WAAW;YACtC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,aAAa;YAC1C,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;SACxC;KACF,CAAC;IAEF,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAExF,OAAO,CACL,CAAC,mBAAI,CACH,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC,CAC7D,IAAI,KAAK,CAAC,CAEV;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,mBAAI,CAAC,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import type { TextInputProps, ViewStyle, StyleProp } from 'react-native';
3
+ export interface ThemedTextInputProps extends TextInputProps {
4
+ /** Error state */
5
+ error?: boolean;
6
+ /** Container style override */
7
+ containerStyle?: StyleProp<ViewStyle>;
8
+ }
9
+ /**
10
+ * Themed text input component with Harken styling.
11
+ */
12
+ export declare function ThemedTextInput({ error, containerStyle, style, onFocus, onBlur, ...props }: ThemedTextInputProps): React.JSX.Element;
13
+ //# sourceMappingURL=ThemedTextInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemedTextInput.d.ts","sourceRoot":"","sources":["../../src/components/ThemedTextInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAa,SAAS,EAAE,MAAM,cAAc,CAAC;AAGpF,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IAC1D,kBAAkB;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+BAA+B;IAC/B,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAa,EACb,cAAc,EACd,KAAK,EACL,OAAO,EACP,MAAM,EACN,GAAG,KAAK,EACT,EAAE,oBAAoB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA0C1C"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ThemedTextInput = ThemedTextInput;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const hooks_1 = require("../hooks");
40
+ /**
41
+ * Themed text input component with Harken styling.
42
+ */
43
+ function ThemedTextInput({ error = false, containerStyle, style, onFocus, onBlur, ...props }) {
44
+ const theme = (0, hooks_1.useHarkenTheme)();
45
+ const [isFocused, setIsFocused] = (0, react_1.useState)(false);
46
+ const getBorderColor = () => {
47
+ if (error)
48
+ return theme.colors.error;
49
+ if (isFocused)
50
+ return theme.colors.borderFocused;
51
+ return theme.colors.border;
52
+ };
53
+ const inputStyle = {
54
+ fontSize: theme.typography.bodySize,
55
+ fontFamily: theme.typography.fontFamily,
56
+ color: theme.colors.text,
57
+ padding: theme.spacing.md,
58
+ minHeight: 44,
59
+ };
60
+ const containerStyles = {
61
+ backgroundColor: theme.colors.backgroundSecondary,
62
+ borderWidth: 1,
63
+ borderColor: getBorderColor(),
64
+ borderRadius: theme.radii.md,
65
+ };
66
+ return (<react_native_1.View style={[containerStyles, containerStyle]}>
67
+ <react_native_1.TextInput style={[inputStyle, style]} placeholderTextColor={theme.colors.textPlaceholder} onFocus={(e) => {
68
+ setIsFocused(true);
69
+ onFocus?.(e);
70
+ }} onBlur={(e) => {
71
+ setIsFocused(false);
72
+ onBlur?.(e);
73
+ }} {...props}/>
74
+ </react_native_1.View>);
75
+ }
76
+ //# sourceMappingURL=ThemedTextInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemedTextInput.js","sourceRoot":"","sources":["../../src/components/ThemedTextInput.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,0CAiDC;AAhED,+CAAwC;AACxC,+CAA+C;AAE/C,oCAA0C;AAS1C;;GAEG;AACH,SAAgB,eAAe,CAAC,EAC9B,KAAK,GAAG,KAAK,EACb,cAAc,EACd,KAAK,EACL,OAAO,EACP,MAAM,EACN,GAAG,KAAK,EACa;IACrB,MAAM,KAAK,GAAG,IAAA,sBAAc,GAAE,CAAC;IAC/B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,IAAA,gBAAQ,EAAC,KAAK,CAAC,CAAC;IAElD,MAAM,cAAc,GAAG,GAAG,EAAE;QAC1B,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;QACrC,IAAI,SAAS;YAAE,OAAO,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC;QACjD,OAAO,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;IAC7B,CAAC,CAAC;IAEF,MAAM,UAAU,GAAc;QAC5B,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,QAAQ;QACnC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,UAAU;QACvC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE;QACzB,SAAS,EAAE,EAAE;KACd,CAAC;IAEF,MAAM,eAAe,GAAc;QACjC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,mBAAmB;QACjD,WAAW,EAAE,CAAC;QACd,WAAW,EAAE,cAAc,EAAE;QAC7B,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE;KAC7B,CAAC;IAEF,OAAO,CACL,CAAC,mBAAI,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,CAC7C;MAAA,CAAC,wBAAS,CACR,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAC3B,oBAAoB,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,CACnD,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;YACb,YAAY,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACf,CAAC,CAAC,CACF,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;YACZ,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QACd,CAAC,CAAC,CACF,IAAI,KAAK,CAAC,EAEd;IAAA,EAAE,mBAAI,CAAC,CACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,82 @@
1
+ import React from 'react';
2
+ import type { ViewStyle, StyleProp } from 'react-native';
3
+ import { UploadPhase } from '../domain';
4
+ /**
5
+ * Customizable labels for upload status states.
6
+ */
7
+ export interface UploadStatusLabels {
8
+ /** Label for retry button (default: "Retry") */
9
+ retry?: string;
10
+ /** Label for remove/cancel button (default: "Remove") */
11
+ remove?: string;
12
+ /** Label for cancel during upload (default: "Cancel") */
13
+ cancel?: string;
14
+ /** Label while confirming (default: "Confirming...") */
15
+ confirming?: string;
16
+ /** Label while queued (default: "Waiting...") */
17
+ waiting?: string;
18
+ /** Default error message (default: "Upload failed") */
19
+ uploadFailed?: string;
20
+ }
21
+ export interface UploadStatusOverlayProps {
22
+ /** Current upload phase */
23
+ phase: UploadPhase;
24
+ /** Upload progress (0.0 - 1.0) */
25
+ progress: number;
26
+ /** Error message if failed */
27
+ error?: string;
28
+ /** Callback when retry is pressed */
29
+ onRetry?: () => void;
30
+ /** Callback when remove/cancel is pressed */
31
+ onRemove?: () => void;
32
+ /** Additional container style */
33
+ style?: StyleProp<ViewStyle>;
34
+ /** Custom labels for status text */
35
+ labels?: UploadStatusLabels;
36
+ /** Custom progress renderer */
37
+ renderProgress?: (progress: number) => React.ReactNode;
38
+ /** Custom error renderer */
39
+ renderError?: (error: string, onRetry?: () => void, onRemove?: () => void) => React.ReactNode;
40
+ /** Custom success/completed renderer */
41
+ renderSuccess?: (onRemove?: () => void) => React.ReactNode;
42
+ }
43
+ /**
44
+ * Overlay component showing upload status on attachments.
45
+ *
46
+ * Shows:
47
+ * - Progress bar during upload
48
+ * - Spinner during confirmation
49
+ * - Checkmark when complete
50
+ * - Error with retry button when failed
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * // Basic usage
55
+ * <UploadStatusOverlay
56
+ * phase={attachment.phase}
57
+ * progress={attachment.progress}
58
+ * onRetry={() => retryAttachment(attachment.attachmentId)}
59
+ * onRemove={() => removeAttachment(attachment.attachmentId)}
60
+ * />
61
+ *
62
+ * // With custom labels
63
+ * <UploadStatusOverlay
64
+ * phase={phase}
65
+ * progress={progress}
66
+ * labels={{
67
+ * retry: 'Try Again',
68
+ * remove: 'Delete',
69
+ * confirming: 'Processing...',
70
+ * }}
71
+ * />
72
+ *
73
+ * // With custom progress renderer
74
+ * <UploadStatusOverlay
75
+ * phase={phase}
76
+ * progress={progress}
77
+ * renderProgress={(p) => <CustomProgressBar value={p} />}
78
+ * />
79
+ * ```
80
+ */
81
+ export declare function UploadStatusOverlay({ phase, progress, error, onRetry, onRemove, style, labels, renderProgress, renderError, renderSuccess, }: UploadStatusOverlayProps): React.JSX.Element | null;
82
+ //# sourceMappingURL=UploadStatusOverlay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UploadStatusOverlay.d.ts","sourceRoot":"","sources":["../../src/components/UploadStatusOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,2BAA2B;IAC3B,KAAK,EAAE,WAAW,CAAC;IACnB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,iCAAiC;IACjC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,oCAAoC;IACpC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,+BAA+B;IAC/B,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;IACvD,4BAA4B;IAC5B,WAAW,CAAC,EAAE,CACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,IAAI,EACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,KAClB,KAAK,CAAC,SAAS,CAAC;IACrB,wCAAwC;IACxC,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAC;CAC5D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,QAAQ,EACR,KAAK,EACL,OAAO,EACP,QAAQ,EACR,KAAK,EACL,MAAM,EACN,cAAc,EACd,WAAW,EACX,aAAa,GACd,EAAE,wBAAwB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CA6OrD"}