@harkenapp/sdk-react-native 0.0.1-alpha.1 → 0.0.1-alpha.2
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/README.md +44 -7
- package/app.plugin.cjs +12 -17
- package/dist/__mocks__/async-storage.d.ts +16 -0
- package/dist/__mocks__/async-storage.d.ts.map +1 -0
- package/dist/__mocks__/async-storage.js +39 -0
- package/dist/__mocks__/async-storage.js.map +1 -0
- package/dist/__mocks__/expo-document-picker.d.ts +26 -0
- package/dist/__mocks__/expo-document-picker.d.ts.map +1 -0
- package/dist/__mocks__/expo-document-picker.js +25 -0
- package/dist/__mocks__/expo-document-picker.js.map +1 -0
- package/dist/__mocks__/expo-file-system.d.ts +42 -0
- package/dist/__mocks__/expo-file-system.d.ts.map +1 -0
- package/dist/__mocks__/expo-file-system.js +37 -0
- package/dist/__mocks__/expo-file-system.js.map +1 -0
- package/dist/__mocks__/expo-image-picker.d.ts +30 -0
- package/dist/__mocks__/expo-image-picker.d.ts.map +1 -0
- package/dist/__mocks__/expo-image-picker.js +30 -0
- package/dist/__mocks__/expo-image-picker.js.map +1 -0
- package/dist/__mocks__/expo-secure-store.d.ts +15 -0
- package/dist/__mocks__/expo-secure-store.d.ts.map +1 -0
- package/dist/__mocks__/expo-secure-store.js +30 -0
- package/dist/__mocks__/expo-secure-store.js.map +1 -0
- package/dist/__mocks__/react-native.d.ts +73 -0
- package/dist/__mocks__/react-native.d.ts.map +1 -0
- package/dist/__mocks__/react-native.js +45 -0
- package/dist/__mocks__/react-native.js.map +1 -0
- package/dist/api/client.d.ts +8 -8
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +17 -19
- package/dist/api/client.js.map +1 -1
- package/dist/api/client.test.d.ts +2 -0
- package/dist/api/client.test.d.ts.map +1 -0
- package/dist/api/client.test.js +417 -0
- package/dist/api/client.test.js.map +1 -0
- package/dist/api/errors.d.ts +3 -3
- package/dist/api/errors.d.ts.map +1 -1
- package/dist/api/errors.js +3 -3
- package/dist/api/errors.js.map +1 -1
- package/dist/api/errors.test.d.ts +2 -0
- package/dist/api/errors.test.d.ts.map +1 -0
- package/dist/api/errors.test.js +155 -0
- package/dist/api/errors.test.js.map +1 -0
- package/dist/api/index.d.ts +6 -6
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/retry.d.ts +1 -1
- package/dist/api/retry.d.ts.map +1 -1
- package/dist/api/retry.js.map +1 -1
- package/dist/api/retry.test.d.ts +2 -0
- package/dist/api/retry.test.d.ts.map +1 -0
- package/dist/api/retry.test.js +193 -0
- package/dist/api/retry.test.js.map +1 -0
- package/dist/attachments/FeedbackSheet.d.ts +36 -13
- package/dist/attachments/FeedbackSheet.d.ts.map +1 -1
- package/dist/attachments/FeedbackSheet.js +50 -30
- package/dist/attachments/FeedbackSheet.js.map +1 -1
- package/dist/attachments/index.d.ts +2 -2
- package/dist/components/AttachmentGrid.d.ts +12 -4
- package/dist/components/AttachmentGrid.d.ts.map +1 -1
- package/dist/components/AttachmentGrid.js +44 -34
- package/dist/components/AttachmentGrid.js.map +1 -1
- package/dist/components/AttachmentPicker.d.ts +3 -3
- package/dist/components/AttachmentPicker.d.ts.map +1 -1
- package/dist/components/AttachmentPicker.js +34 -36
- package/dist/components/AttachmentPicker.js.map +1 -1
- package/dist/components/AttachmentPreview.d.ts +10 -4
- package/dist/components/AttachmentPreview.d.ts.map +1 -1
- package/dist/components/AttachmentPreview.js +48 -34
- package/dist/components/AttachmentPreview.js.map +1 -1
- package/dist/components/CategorySelector.d.ts +3 -3
- package/dist/components/CategorySelector.d.ts.map +1 -1
- package/dist/components/CategorySelector.js +21 -27
- package/dist/components/CategorySelector.js.map +1 -1
- package/dist/components/FeedbackForm.d.ts +3 -3
- package/dist/components/FeedbackForm.d.ts.map +1 -1
- package/dist/components/FeedbackForm.js +7 -8
- package/dist/components/FeedbackForm.js.map +1 -1
- package/dist/components/FeedbackSheet.d.ts +34 -11
- package/dist/components/FeedbackSheet.d.ts.map +1 -1
- package/dist/components/FeedbackSheet.js +46 -28
- package/dist/components/FeedbackSheet.js.map +1 -1
- package/dist/components/ThemedButton.d.ts +16 -5
- package/dist/components/ThemedButton.d.ts.map +1 -1
- package/dist/components/ThemedButton.js +38 -29
- package/dist/components/ThemedButton.js.map +1 -1
- package/dist/components/ThemedText.d.ts +3 -3
- package/dist/components/ThemedText.d.ts.map +1 -1
- package/dist/components/ThemedText.js +1 -1
- package/dist/components/ThemedText.js.map +1 -1
- package/dist/components/ThemedTextInput.d.ts +11 -2
- package/dist/components/ThemedTextInput.d.ts.map +1 -1
- package/dist/components/ThemedTextInput.js +19 -9
- package/dist/components/ThemedTextInput.js.map +1 -1
- package/dist/components/UploadStatusOverlay.d.ts +11 -3
- package/dist/components/UploadStatusOverlay.d.ts.map +1 -1
- package/dist/components/UploadStatusOverlay.js +59 -76
- package/dist/components/UploadStatusOverlay.js.map +1 -1
- package/dist/components/index.d.ts +18 -18
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js.map +1 -1
- package/dist/context/HarkenContext.d.ts +20 -15
- package/dist/context/HarkenContext.d.ts.map +1 -1
- package/dist/context/HarkenContext.js +20 -17
- package/dist/context/HarkenContext.js.map +1 -1
- package/dist/context/index.d.ts +2 -2
- package/dist/domain/index.d.ts +2 -2
- package/dist/domain/index.d.ts.map +1 -1
- package/dist/domain/index.js.map +1 -1
- package/dist/hooks/index.d.ts +5 -5
- package/dist/hooks/useAnonymousId.js +1 -1
- package/dist/hooks/useAnonymousId.test.d.ts +2 -0
- package/dist/hooks/useAnonymousId.test.d.ts.map +1 -0
- package/dist/hooks/useAnonymousId.test.js +154 -0
- package/dist/hooks/useAnonymousId.test.js.map +1 -0
- package/dist/hooks/useAttachmentPicker.d.ts +3 -3
- package/dist/hooks/useAttachmentPicker.js +7 -7
- package/dist/hooks/useAttachmentStatus.d.ts +1 -1
- package/dist/hooks/useAttachmentStatus.d.ts.map +1 -1
- package/dist/hooks/useAttachmentStatus.js.map +1 -1
- package/dist/hooks/useAttachmentUpload.d.ts +2 -2
- package/dist/hooks/useAttachmentUpload.d.ts.map +1 -1
- package/dist/hooks/useAttachmentUpload.js +5 -5
- package/dist/hooks/useAttachmentUpload.js.map +1 -1
- package/dist/hooks/useAttachmentUpload.test.d.ts +2 -0
- package/dist/hooks/useAttachmentUpload.test.d.ts.map +1 -0
- package/dist/hooks/useAttachmentUpload.test.js +542 -0
- package/dist/hooks/useAttachmentUpload.test.js.map +1 -0
- package/dist/hooks/useFeedback.d.ts +4 -4
- package/dist/hooks/useFeedback.d.ts.map +1 -1
- package/dist/hooks/useFeedback.js +3 -5
- package/dist/hooks/useFeedback.js.map +1 -1
- package/dist/hooks/useFeedback.test.d.ts +2 -0
- package/dist/hooks/useFeedback.test.d.ts.map +1 -0
- package/dist/hooks/useFeedback.test.js +299 -0
- package/dist/hooks/useFeedback.test.js.map +1 -0
- package/dist/hooks/useHarkenContext.d.ts +1 -1
- package/dist/hooks/useHarkenContext.js +1 -1
- package/dist/hooks/useHarkenTheme.d.ts +27 -3
- package/dist/hooks/useHarkenTheme.d.ts.map +1 -1
- package/dist/hooks/useHarkenTheme.js +26 -2
- package/dist/hooks/useHarkenTheme.js.map +1 -1
- package/dist/index.d.ts +28 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/index.d.ts +3 -3
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js.map +1 -1
- package/dist/services/uploadQueueService.d.ts +2 -2
- package/dist/services/uploadQueueService.d.ts.map +1 -1
- package/dist/services/uploadQueueService.js +16 -17
- package/dist/services/uploadQueueService.js.map +1 -1
- package/dist/services/uploadQueueService.test.d.ts +2 -0
- package/dist/services/uploadQueueService.test.d.ts.map +1 -0
- package/dist/services/uploadQueueService.test.js +426 -0
- package/dist/services/uploadQueueService.test.js.map +1 -0
- package/dist/services/uploadQueueStorage.d.ts +1 -1
- package/dist/services/uploadQueueStorage.d.ts.map +1 -1
- package/dist/services/uploadQueueStorage.js +4 -4
- package/dist/services/uploadQueueStorage.js.map +1 -1
- package/dist/services/uploadQueueStorage.test.d.ts +2 -0
- package/dist/services/uploadQueueStorage.test.d.ts.map +1 -0
- package/dist/services/uploadQueueStorage.test.js +200 -0
- package/dist/services/uploadQueueStorage.test.js.map +1 -0
- package/dist/storage/IdentityStore.d.ts +1 -1
- package/dist/storage/IdentityStore.d.ts.map +1 -1
- package/dist/storage/IdentityStore.js.map +1 -1
- package/dist/storage/IdentityStore.test.d.ts +2 -0
- package/dist/storage/IdentityStore.test.d.ts.map +1 -0
- package/dist/storage/IdentityStore.test.js +176 -0
- package/dist/storage/IdentityStore.test.js.map +1 -0
- package/dist/storage/SecureStoreAdapter.d.ts +1 -1
- package/dist/storage/SecureStoreAdapter.test.d.ts +2 -0
- package/dist/storage/SecureStoreAdapter.test.d.ts.map +1 -0
- package/dist/storage/SecureStoreAdapter.test.js +114 -0
- package/dist/storage/SecureStoreAdapter.test.js.map +1 -0
- package/dist/storage/defaultStorage.d.ts +1 -1
- package/dist/storage/defaultStorage.js +4 -4
- package/dist/storage/defaultStorage.test.d.ts +2 -0
- package/dist/storage/defaultStorage.test.d.ts.map +1 -0
- package/dist/storage/defaultStorage.test.js +159 -0
- package/dist/storage/defaultStorage.test.js.map +1 -0
- package/dist/storage/index.d.ts +5 -5
- package/dist/storage/types.js +1 -1
- package/dist/theme/defaults.d.ts +14 -3
- package/dist/theme/defaults.d.ts.map +1 -1
- package/dist/theme/defaults.js +58 -43
- package/dist/theme/defaults.js.map +1 -1
- package/dist/theme/index.d.ts +3 -2
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +4 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/resolver.d.ts +16 -0
- package/dist/theme/resolver.d.ts.map +1 -0
- package/dist/theme/resolver.js +375 -0
- package/dist/theme/resolver.js.map +1 -0
- package/dist/theme/resolver.test.d.ts +2 -0
- package/dist/theme/resolver.test.d.ts.map +1 -0
- package/dist/theme/resolver.test.js +344 -0
- package/dist/theme/resolver.test.js.map +1 -0
- package/dist/theme/types.d.ts +378 -5
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -4
- package/dist/types/index.d.ts +2 -2
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/uuid.d.ts.map +1 -1
- package/dist/utils/uuid.js +4 -5
- package/dist/utils/uuid.js.map +1 -1
- package/dist/utils/uuid.test.d.ts +2 -0
- package/dist/utils/uuid.test.d.ts.map +1 -0
- package/dist/utils/uuid.test.js +78 -0
- package/dist/utils/uuid.test.js.map +1 -0
- package/package.json +21 -13
- package/src/@types/expo-file-system-legacy.d.ts +3 -3
- package/src/__mocks__/async-storage.ts +46 -0
- package/src/__mocks__/expo-document-picker.ts +41 -0
- package/src/__mocks__/expo-file-system.ts +62 -0
- package/src/__mocks__/expo-image-picker.ts +48 -0
- package/src/__mocks__/expo-secure-store.ts +29 -0
- package/src/__mocks__/react-native.ts +46 -0
- package/src/api/client.test.ts +515 -0
- package/src/api/client.ts +45 -64
- package/src/api/errors.test.ts +193 -0
- package/src/api/errors.ts +7 -11
- package/src/api/index.ts +6 -10
- package/src/api/retry.test.ts +251 -0
- package/src/api/retry.ts +3 -6
- package/src/attachments/FeedbackSheet.tsx +100 -80
- package/src/attachments/index.ts +2 -2
- package/src/components/AttachmentGrid.tsx +54 -45
- package/src/components/AttachmentPicker.tsx +43 -54
- package/src/components/AttachmentPreview.tsx +51 -47
- package/src/components/CategorySelector.tsx +29 -35
- package/src/components/FeedbackForm.tsx +23 -35
- package/src/components/FeedbackSheet.tsx +89 -68
- package/src/components/ThemedButton.tsx +49 -47
- package/src/components/ThemedText.tsx +7 -10
- package/src/components/ThemedTextInput.tsx +23 -13
- package/src/components/UploadStatusOverlay.tsx +66 -89
- package/src/components/index.ts +18 -21
- package/src/context/HarkenContext.tsx +29 -28
- package/src/context/index.ts +2 -2
- package/src/domain/index.ts +2 -5
- package/src/domain/upload-queue.ts +5 -5
- package/src/hooks/index.ts +5 -5
- package/src/hooks/useAnonymousId.test.ts +189 -0
- package/src/hooks/useAnonymousId.ts +3 -3
- package/src/hooks/useAttachmentPicker.ts +12 -12
- package/src/hooks/useAttachmentStatus.ts +12 -16
- package/src/hooks/useAttachmentUpload.test.ts +632 -0
- package/src/hooks/useAttachmentUpload.ts +45 -54
- package/src/hooks/useFeedback.test.ts +376 -0
- package/src/hooks/useFeedback.ts +12 -14
- package/src/hooks/useHarkenContext.ts +4 -4
- package/src/hooks/useHarkenTheme.ts +30 -6
- package/src/index.ts +28 -52
- package/src/services/index.ts +3 -9
- package/src/services/uploadQueueService.test.ts +489 -0
- package/src/services/uploadQueueService.ts +40 -56
- package/src/services/uploadQueueStorage.test.ts +243 -0
- package/src/services/uploadQueueStorage.ts +7 -9
- package/src/storage/IdentityStore.test.ts +173 -0
- package/src/storage/IdentityStore.ts +4 -5
- package/src/storage/SecureStoreAdapter.test.ts +147 -0
- package/src/storage/SecureStoreAdapter.ts +1 -1
- package/src/storage/defaultStorage.test.ts +159 -0
- package/src/storage/defaultStorage.ts +6 -6
- package/src/storage/index.ts +5 -5
- package/src/storage/types.ts +1 -1
- package/src/theme/defaults.ts +75 -46
- package/src/theme/index.ts +15 -2
- package/src/theme/resolver.test.ts +411 -0
- package/src/theme/resolver.ts +446 -0
- package/src/theme/types.ts +453 -15
- package/src/types/config.ts +4 -4
- package/src/types/index.ts +2 -2
- package/src/utils/index.ts +1 -1
- package/src/utils/uuid.test.ts +85 -0
- package/src/utils/uuid.ts +4 -7
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import { View, Pressable } from
|
|
3
|
-
import type { ViewStyle, StyleProp } from
|
|
4
|
-
import { useHarkenTheme } from
|
|
5
|
-
import { ThemedText } from
|
|
6
|
-
import type { FeedbackCategory } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View, Pressable } from "react-native";
|
|
3
|
+
import type { ViewStyle, StyleProp } from "react-native";
|
|
4
|
+
import { useHarkenTheme } from "../hooks";
|
|
5
|
+
import { ThemedText } from "./ThemedText";
|
|
6
|
+
import type { FeedbackCategory } from "../types";
|
|
7
7
|
|
|
8
8
|
export interface CategoryOption {
|
|
9
9
|
value: FeedbackCategory;
|
|
@@ -14,10 +14,10 @@ export interface CategoryOption {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export const DEFAULT_CATEGORIES: CategoryOption[] = [
|
|
17
|
-
{ value:
|
|
18
|
-
{ value:
|
|
19
|
-
{ value:
|
|
20
|
-
{ value:
|
|
17
|
+
{ value: "bug", label: "Bug", emoji: "🐛" },
|
|
18
|
+
{ value: "idea", label: "Idea", emoji: "💡" },
|
|
19
|
+
{ value: "ux", label: "UX", emoji: "✨" },
|
|
20
|
+
{ value: "other", label: "Other", emoji: "💬" },
|
|
21
21
|
];
|
|
22
22
|
|
|
23
23
|
export interface CategorySelectorProps {
|
|
@@ -100,11 +100,12 @@ export function CategorySelector({
|
|
|
100
100
|
selectedChipStyle,
|
|
101
101
|
}: CategorySelectorProps): React.JSX.Element {
|
|
102
102
|
const theme = useHarkenTheme();
|
|
103
|
+
const { chip } = theme.components;
|
|
103
104
|
|
|
104
105
|
const containerStyle: ViewStyle = {
|
|
105
|
-
flexDirection:
|
|
106
|
-
flexWrap:
|
|
107
|
-
gap:
|
|
106
|
+
flexDirection: "row",
|
|
107
|
+
flexWrap: "wrap",
|
|
108
|
+
gap: chip.gap,
|
|
108
109
|
};
|
|
109
110
|
|
|
110
111
|
return (
|
|
@@ -123,22 +124,18 @@ export function CategorySelector({
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
const baseChipStyle: ViewStyle = {
|
|
126
|
-
flexDirection:
|
|
127
|
-
alignItems:
|
|
128
|
-
paddingVertical:
|
|
129
|
-
paddingHorizontal:
|
|
130
|
-
borderRadius:
|
|
127
|
+
flexDirection: "row",
|
|
128
|
+
alignItems: "center",
|
|
129
|
+
paddingVertical: chip.paddingVertical,
|
|
130
|
+
paddingHorizontal: chip.paddingHorizontal,
|
|
131
|
+
borderRadius: chip.radius,
|
|
131
132
|
borderWidth: 1,
|
|
132
|
-
borderColor: isSelected ?
|
|
133
|
-
backgroundColor: isSelected
|
|
134
|
-
|
|
135
|
-
: theme.colors.backgroundSecondary,
|
|
136
|
-
opacity: disabled ? 0.6 : 1,
|
|
133
|
+
borderColor: isSelected ? chip.borderSelected : chip.border,
|
|
134
|
+
backgroundColor: isSelected ? chip.backgroundSelected : chip.background,
|
|
135
|
+
opacity: disabled ? theme.opacity.disabled : 1,
|
|
137
136
|
};
|
|
138
137
|
|
|
139
|
-
const textColor = isSelected
|
|
140
|
-
? theme.colors.textOnPrimary
|
|
141
|
-
: theme.colors.text;
|
|
138
|
+
const textColor = isSelected ? chip.textSelected : chip.text;
|
|
142
139
|
|
|
143
140
|
return (
|
|
144
141
|
<Pressable
|
|
@@ -149,19 +146,16 @@ export function CategorySelector({
|
|
|
149
146
|
baseChipStyle,
|
|
150
147
|
chipStyle,
|
|
151
148
|
isSelected && selectedChipStyle,
|
|
152
|
-
pressed &&
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
pressed &&
|
|
150
|
+
!disabled && {
|
|
151
|
+
opacity: theme.opacity.pressed,
|
|
152
|
+
},
|
|
155
153
|
]}
|
|
156
154
|
>
|
|
157
155
|
{category.icon ? (
|
|
158
|
-
<View style={{ marginRight: theme.spacing.xs }}>
|
|
159
|
-
{category.icon}
|
|
160
|
-
</View>
|
|
156
|
+
<View style={{ marginRight: theme.spacing.xs }}>{category.icon}</View>
|
|
161
157
|
) : category.emoji ? (
|
|
162
|
-
<ThemedText style={{ marginRight: theme.spacing.xs }}>
|
|
163
|
-
{category.emoji}
|
|
164
|
-
</ThemedText>
|
|
158
|
+
<ThemedText style={{ marginRight: theme.spacing.xs }}>{category.emoji}</ThemedText>
|
|
165
159
|
) : null}
|
|
166
160
|
<ThemedText variant="label" color={textColor}>
|
|
167
161
|
{category.label}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import React, { useState, useCallback } from
|
|
2
|
-
import { View, KeyboardAvoidingView, Platform, ScrollView } from
|
|
3
|
-
import type { ViewStyle } from
|
|
4
|
-
import { useHarkenTheme } from
|
|
5
|
-
import { ThemedText } from
|
|
6
|
-
import { ThemedTextInput } from
|
|
7
|
-
import { ThemedButton } from
|
|
8
|
-
import { CategorySelector } from
|
|
9
|
-
import type { CategoryOption } from
|
|
10
|
-
import type { FeedbackCategory } from
|
|
1
|
+
import React, { useState, useCallback } from "react";
|
|
2
|
+
import { View, KeyboardAvoidingView, Platform, ScrollView } from "react-native";
|
|
3
|
+
import type { ViewStyle } from "react-native";
|
|
4
|
+
import { useHarkenTheme } from "../hooks";
|
|
5
|
+
import { ThemedText } from "./ThemedText";
|
|
6
|
+
import { ThemedTextInput } from "./ThemedTextInput";
|
|
7
|
+
import { ThemedButton } from "./ThemedButton";
|
|
8
|
+
import { CategorySelector } from "./CategorySelector";
|
|
9
|
+
import type { CategoryOption } from "./CategorySelector";
|
|
10
|
+
import type { FeedbackCategory } from "../types";
|
|
11
11
|
|
|
12
12
|
export interface FeedbackFormData {
|
|
13
13
|
message: string;
|
|
@@ -59,10 +59,10 @@ export interface FeedbackFormProps {
|
|
|
59
59
|
export function FeedbackForm({
|
|
60
60
|
onSubmit,
|
|
61
61
|
onCancel,
|
|
62
|
-
title =
|
|
63
|
-
placeholder =
|
|
64
|
-
submitLabel =
|
|
65
|
-
cancelLabel =
|
|
62
|
+
title = "Send Feedback",
|
|
63
|
+
placeholder = "What would you like to share?",
|
|
64
|
+
submitLabel = "Submit",
|
|
65
|
+
cancelLabel = "Cancel",
|
|
66
66
|
categories,
|
|
67
67
|
requireCategory = false,
|
|
68
68
|
minMessageLength = 1,
|
|
@@ -72,7 +72,7 @@ export function FeedbackForm({
|
|
|
72
72
|
}: FeedbackFormProps): React.JSX.Element {
|
|
73
73
|
const theme = useHarkenTheme();
|
|
74
74
|
|
|
75
|
-
const [message, setMessage] = useState(initialValues?.message ??
|
|
75
|
+
const [message, setMessage] = useState(initialValues?.message ?? "");
|
|
76
76
|
const [category, setCategory] = useState<FeedbackCategory | null>(
|
|
77
77
|
initialValues?.category ?? null
|
|
78
78
|
);
|
|
@@ -80,8 +80,7 @@ export function FeedbackForm({
|
|
|
80
80
|
|
|
81
81
|
const trimmedMessage = message.trim();
|
|
82
82
|
const isMessageValid =
|
|
83
|
-
trimmedMessage.length >= minMessageLength &&
|
|
84
|
-
trimmedMessage.length <= maxMessageLength;
|
|
83
|
+
trimmedMessage.length >= minMessageLength && trimmedMessage.length <= maxMessageLength;
|
|
85
84
|
const isCategoryValid = !requireCategory || category !== null;
|
|
86
85
|
const canSubmit = isMessageValid && isCategoryValid && !loading && !isSubmitting;
|
|
87
86
|
|
|
@@ -110,7 +109,7 @@ export function FeedbackForm({
|
|
|
110
109
|
};
|
|
111
110
|
|
|
112
111
|
const buttonRowStyle: ViewStyle = {
|
|
113
|
-
flexDirection:
|
|
112
|
+
flexDirection: "row",
|
|
114
113
|
gap: theme.spacing.sm,
|
|
115
114
|
marginTop: theme.spacing.md,
|
|
116
115
|
};
|
|
@@ -120,13 +119,10 @@ export function FeedbackForm({
|
|
|
120
119
|
|
|
121
120
|
return (
|
|
122
121
|
<KeyboardAvoidingView
|
|
123
|
-
behavior={Platform.OS ===
|
|
122
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
124
123
|
style={{ flex: 1 }}
|
|
125
124
|
>
|
|
126
|
-
<ScrollView
|
|
127
|
-
contentContainerStyle={{ flexGrow: 1 }}
|
|
128
|
-
keyboardShouldPersistTaps="handled"
|
|
129
|
-
>
|
|
125
|
+
<ScrollView contentContainerStyle={{ flexGrow: 1 }} keyboardShouldPersistTaps="handled">
|
|
130
126
|
<View style={containerStyle}>
|
|
131
127
|
{/* Title */}
|
|
132
128
|
<View style={sectionStyle}>
|
|
@@ -135,12 +131,8 @@ export function FeedbackForm({
|
|
|
135
131
|
|
|
136
132
|
{/* Category selector */}
|
|
137
133
|
<View style={sectionStyle}>
|
|
138
|
-
<ThemedText
|
|
139
|
-
|
|
140
|
-
secondary
|
|
141
|
-
style={{ marginBottom: theme.spacing.sm }}
|
|
142
|
-
>
|
|
143
|
-
Category{requireCategory ? '' : ' (optional)'}
|
|
134
|
+
<ThemedText variant="label" secondary style={{ marginBottom: theme.spacing.sm }}>
|
|
135
|
+
Category{requireCategory ? "" : " (optional)"}
|
|
144
136
|
</ThemedText>
|
|
145
137
|
<CategorySelector
|
|
146
138
|
value={category}
|
|
@@ -152,11 +144,7 @@ export function FeedbackForm({
|
|
|
152
144
|
|
|
153
145
|
{/* Message input */}
|
|
154
146
|
<View style={sectionStyle}>
|
|
155
|
-
<ThemedText
|
|
156
|
-
variant="label"
|
|
157
|
-
secondary
|
|
158
|
-
style={{ marginBottom: theme.spacing.sm }}
|
|
159
|
-
>
|
|
147
|
+
<ThemedText variant="label" secondary style={{ marginBottom: theme.spacing.sm }}>
|
|
160
148
|
Message
|
|
161
149
|
</ThemedText>
|
|
162
150
|
<ThemedTextInput
|
|
@@ -178,7 +166,7 @@ export function FeedbackForm({
|
|
|
178
166
|
? theme.colors.error
|
|
179
167
|
: theme.colors.textSecondary
|
|
180
168
|
}
|
|
181
|
-
style={{ marginTop: theme.spacing.xs, textAlign:
|
|
169
|
+
style={{ marginTop: theme.spacing.xs, textAlign: "right" }}
|
|
182
170
|
>
|
|
183
171
|
{characterCount}/{maxMessageLength}
|
|
184
172
|
</ThemedText>
|
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
import React, { useState, useCallback } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from
|
|
9
|
-
import
|
|
10
|
-
import type {
|
|
11
|
-
import {
|
|
12
|
-
import { ThemedText } from './ThemedText';
|
|
13
|
-
import { ThemedTextInput } from './ThemedTextInput';
|
|
14
|
-
import { ThemedButton } from './ThemedButton';
|
|
15
|
-
import { CategorySelector, DEFAULT_CATEGORIES } from './CategorySelector';
|
|
16
|
-
import type { CategoryOption } from './CategorySelector';
|
|
17
|
-
import type { FeedbackCategory } from '../types';
|
|
1
|
+
import React, { useState, useCallback } from "react";
|
|
2
|
+
import { View, KeyboardAvoidingView, Platform, ScrollView, Alert } from "react-native";
|
|
3
|
+
import type { ViewStyle, StyleProp } from "react-native";
|
|
4
|
+
import type { components } from "../types/index.js";
|
|
5
|
+
import { useHarkenTheme, useFeedback } from "../hooks";
|
|
6
|
+
import { ThemedText } from "./ThemedText";
|
|
7
|
+
import { ThemedTextInput } from "./ThemedTextInput";
|
|
8
|
+
import { ThemedButton } from "./ThemedButton";
|
|
9
|
+
import { CategorySelector, DEFAULT_CATEGORIES } from "./CategorySelector";
|
|
10
|
+
import type { CategoryOption } from "./CategorySelector";
|
|
11
|
+
import type { FeedbackCategory } from "../types";
|
|
18
12
|
|
|
19
|
-
type FeedbackSubmissionResponse = components[
|
|
13
|
+
type FeedbackSubmissionResponse = components["schemas"]["FeedbackSubmissionResponse"];
|
|
20
14
|
|
|
21
15
|
export interface FeedbackSheetProps {
|
|
22
16
|
/** Called when feedback is successfully submitted */
|
|
@@ -26,7 +20,7 @@ export interface FeedbackSheetProps {
|
|
|
26
20
|
/** Called when user cancels/dismisses the form */
|
|
27
21
|
onCancel?: () => void;
|
|
28
22
|
|
|
29
|
-
/** Title text */
|
|
23
|
+
/** Title text. Set to empty string to hide title section entirely. */
|
|
30
24
|
title?: string;
|
|
31
25
|
/** Placeholder text for message input */
|
|
32
26
|
placeholder?: string;
|
|
@@ -52,10 +46,21 @@ export interface FeedbackSheetProps {
|
|
|
52
46
|
/** Whether to clear form on success. @default true */
|
|
53
47
|
clearOnSuccess?: boolean;
|
|
54
48
|
|
|
55
|
-
/**
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Layout mode for the container.
|
|
51
|
+
* - 'flex': Uses flex: 1 (default, requires parent with explicit height)
|
|
52
|
+
* - 'auto': Content determines height (for bottom sheet modal embedding)
|
|
53
|
+
*/
|
|
54
|
+
layout?: "flex" | "auto";
|
|
55
|
+
|
|
56
|
+
/** Container style override (outer KeyboardAvoidingView) */
|
|
57
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
58
|
+
/** Content style override (inner ScrollView content) */
|
|
59
|
+
contentStyle?: StyleProp<ViewStyle>;
|
|
60
|
+
/**
|
|
61
|
+
* @deprecated Use `contentStyle` instead
|
|
62
|
+
*/
|
|
63
|
+
formStyle?: StyleProp<ViewStyle>;
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
/**
|
|
@@ -70,11 +75,24 @@ export interface FeedbackSheetProps {
|
|
|
70
75
|
*
|
|
71
76
|
* For attachment support, import from '@harkenapp/sdk-react-native/attachments'.
|
|
72
77
|
*
|
|
78
|
+
* Uses the following theme tokens:
|
|
79
|
+
* - `colors.formBackground` for background
|
|
80
|
+
* - `spacing.formPadding` for padding
|
|
81
|
+
* - `spacing.sectionGap` for section gaps
|
|
82
|
+
* - `radii.form` for border radius
|
|
83
|
+
*
|
|
73
84
|
* @example
|
|
74
85
|
* ```tsx
|
|
75
86
|
* // Minimal usage
|
|
76
87
|
* <FeedbackSheet onSuccess={() => navigation.goBack()} />
|
|
77
88
|
*
|
|
89
|
+
* // For bottom sheet modal embedding
|
|
90
|
+
* <FeedbackSheet
|
|
91
|
+
* layout="auto"
|
|
92
|
+
* title=""
|
|
93
|
+
* onSuccess={() => closeModal()}
|
|
94
|
+
* />
|
|
95
|
+
*
|
|
78
96
|
* // With customization
|
|
79
97
|
* <FeedbackSheet
|
|
80
98
|
* title="Report a Bug"
|
|
@@ -95,36 +113,37 @@ export function FeedbackSheet({
|
|
|
95
113
|
onSuccess,
|
|
96
114
|
onError,
|
|
97
115
|
onCancel,
|
|
98
|
-
title =
|
|
99
|
-
placeholder =
|
|
100
|
-
submitLabel =
|
|
101
|
-
cancelLabel =
|
|
116
|
+
title = "Send Feedback",
|
|
117
|
+
placeholder = "What would you like to share?",
|
|
118
|
+
submitLabel = "Submit",
|
|
119
|
+
cancelLabel = "Cancel",
|
|
102
120
|
categories = DEFAULT_CATEGORIES,
|
|
103
121
|
requireCategory = false,
|
|
104
122
|
minMessageLength = 1,
|
|
105
123
|
maxMessageLength = 5000,
|
|
106
|
-
successMessage =
|
|
124
|
+
successMessage = "Thank you for your feedback!",
|
|
107
125
|
showSuccessAlert = true,
|
|
108
126
|
clearOnSuccess = true,
|
|
127
|
+
layout = "flex",
|
|
109
128
|
containerStyle,
|
|
129
|
+
contentStyle,
|
|
110
130
|
formStyle,
|
|
111
131
|
}: FeedbackSheetProps): React.JSX.Element {
|
|
112
132
|
const theme = useHarkenTheme();
|
|
113
|
-
const {
|
|
114
|
-
|
|
133
|
+
const { form } = theme.components;
|
|
134
|
+
const { submitFeedback, isSubmitting, error, clearError, isInitializing } = useFeedback();
|
|
115
135
|
|
|
116
|
-
const [message, setMessage] = useState(
|
|
136
|
+
const [message, setMessage] = useState("");
|
|
117
137
|
const [category, setCategory] = useState<FeedbackCategory | null>(null);
|
|
118
138
|
|
|
119
139
|
const trimmedMessage = message.trim();
|
|
120
140
|
const isMessageValid =
|
|
121
|
-
trimmedMessage.length >= minMessageLength &&
|
|
122
|
-
trimmedMessage.length <= maxMessageLength;
|
|
141
|
+
trimmedMessage.length >= minMessageLength && trimmedMessage.length <= maxMessageLength;
|
|
123
142
|
const isCategoryValid = !requireCategory || category !== null;
|
|
124
143
|
const canSubmit = isMessageValid && isCategoryValid && !isSubmitting && !isInitializing;
|
|
125
144
|
|
|
126
145
|
const resetForm = useCallback(() => {
|
|
127
|
-
setMessage(
|
|
146
|
+
setMessage("");
|
|
128
147
|
setCategory(null);
|
|
129
148
|
clearError();
|
|
130
149
|
}, [clearError]);
|
|
@@ -137,13 +156,13 @@ export function FeedbackSheet({
|
|
|
137
156
|
try {
|
|
138
157
|
const result = await submitFeedback({
|
|
139
158
|
message: trimmedMessage,
|
|
140
|
-
category: category ??
|
|
159
|
+
category: category ?? "other",
|
|
141
160
|
});
|
|
142
161
|
|
|
143
162
|
if (showSuccessAlert && successMessage) {
|
|
144
|
-
Alert.alert(
|
|
163
|
+
Alert.alert("Success", successMessage, [
|
|
145
164
|
{
|
|
146
|
-
text:
|
|
165
|
+
text: "OK",
|
|
147
166
|
onPress: () => {
|
|
148
167
|
if (clearOnSuccess) {
|
|
149
168
|
resetForm();
|
|
@@ -160,8 +179,8 @@ export function FeedbackSheet({
|
|
|
160
179
|
}
|
|
161
180
|
} catch (e) {
|
|
162
181
|
const errorMessage =
|
|
163
|
-
e instanceof Error ? e.message :
|
|
164
|
-
Alert.alert(
|
|
182
|
+
e instanceof Error ? e.message : "Failed to submit feedback. Please try again.";
|
|
183
|
+
Alert.alert("Submission Failed", errorMessage);
|
|
165
184
|
onError?.(e instanceof Error ? e : new Error(errorMessage));
|
|
166
185
|
}
|
|
167
186
|
}, [
|
|
@@ -184,21 +203,22 @@ export function FeedbackSheet({
|
|
|
184
203
|
}, [resetForm, onCancel]);
|
|
185
204
|
|
|
186
205
|
const baseContainerStyle: ViewStyle = {
|
|
187
|
-
flex: 1,
|
|
188
|
-
backgroundColor:
|
|
206
|
+
...(layout === "flex" ? { flex: 1 } : {}),
|
|
207
|
+
backgroundColor: form.background,
|
|
208
|
+
borderRadius: form.radius,
|
|
189
209
|
};
|
|
190
210
|
|
|
191
|
-
const
|
|
192
|
-
flexGrow: 1,
|
|
193
|
-
padding:
|
|
211
|
+
const scrollContentStyle: ViewStyle = {
|
|
212
|
+
...(layout === "flex" ? { flexGrow: 1 } : {}),
|
|
213
|
+
padding: form.padding,
|
|
194
214
|
};
|
|
195
215
|
|
|
196
216
|
const sectionStyle: ViewStyle = {
|
|
197
|
-
marginBottom:
|
|
217
|
+
marginBottom: form.sectionGap,
|
|
198
218
|
};
|
|
199
219
|
|
|
200
220
|
const buttonRowStyle: ViewStyle = {
|
|
201
|
-
flexDirection:
|
|
221
|
+
flexDirection: "row",
|
|
202
222
|
gap: theme.spacing.sm,
|
|
203
223
|
marginTop: theme.spacing.md,
|
|
204
224
|
};
|
|
@@ -206,9 +226,18 @@ export function FeedbackSheet({
|
|
|
206
226
|
const characterCount = trimmedMessage.length;
|
|
207
227
|
const showCharacterWarning = characterCount > maxMessageLength * 0.9;
|
|
208
228
|
|
|
229
|
+
// Support deprecated formStyle prop
|
|
230
|
+
const effectiveContentStyle = contentStyle ?? formStyle;
|
|
231
|
+
|
|
209
232
|
if (isInitializing) {
|
|
210
233
|
return (
|
|
211
|
-
<View
|
|
234
|
+
<View
|
|
235
|
+
style={[
|
|
236
|
+
baseContainerStyle,
|
|
237
|
+
containerStyle,
|
|
238
|
+
{ justifyContent: "center", alignItems: "center" },
|
|
239
|
+
]}
|
|
240
|
+
>
|
|
212
241
|
<ThemedText variant="body" secondary>
|
|
213
242
|
Initializing...
|
|
214
243
|
</ThemedText>
|
|
@@ -218,26 +247,24 @@ export function FeedbackSheet({
|
|
|
218
247
|
|
|
219
248
|
return (
|
|
220
249
|
<KeyboardAvoidingView
|
|
221
|
-
behavior={Platform.OS ===
|
|
250
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
222
251
|
style={[baseContainerStyle, containerStyle]}
|
|
223
252
|
>
|
|
224
253
|
<ScrollView
|
|
225
|
-
contentContainerStyle={[
|
|
254
|
+
contentContainerStyle={[scrollContentStyle, effectiveContentStyle]}
|
|
226
255
|
keyboardShouldPersistTaps="handled"
|
|
227
256
|
>
|
|
228
|
-
{/* Title */}
|
|
229
|
-
|
|
230
|
-
<
|
|
231
|
-
|
|
257
|
+
{/* Title - only render if provided */}
|
|
258
|
+
{title ? (
|
|
259
|
+
<View style={sectionStyle}>
|
|
260
|
+
<ThemedText variant="title">{title}</ThemedText>
|
|
261
|
+
</View>
|
|
262
|
+
) : null}
|
|
232
263
|
|
|
233
264
|
{/* Category selector */}
|
|
234
265
|
<View style={sectionStyle}>
|
|
235
|
-
<ThemedText
|
|
236
|
-
|
|
237
|
-
secondary
|
|
238
|
-
style={{ marginBottom: theme.spacing.sm }}
|
|
239
|
-
>
|
|
240
|
-
Category{requireCategory ? '' : ' (optional)'}
|
|
266
|
+
<ThemedText variant="label" secondary style={{ marginBottom: theme.spacing.sm }}>
|
|
267
|
+
Category{requireCategory ? "" : " (optional)"}
|
|
241
268
|
</ThemedText>
|
|
242
269
|
<CategorySelector
|
|
243
270
|
value={category}
|
|
@@ -249,11 +276,7 @@ export function FeedbackSheet({
|
|
|
249
276
|
|
|
250
277
|
{/* Message input */}
|
|
251
278
|
<View style={sectionStyle}>
|
|
252
|
-
<ThemedText
|
|
253
|
-
variant="label"
|
|
254
|
-
secondary
|
|
255
|
-
style={{ marginBottom: theme.spacing.sm }}
|
|
256
|
-
>
|
|
279
|
+
<ThemedText variant="label" secondary style={{ marginBottom: theme.spacing.sm }}>
|
|
257
280
|
Message
|
|
258
281
|
</ThemedText>
|
|
259
282
|
<ThemedTextInput
|
|
@@ -271,11 +294,9 @@ export function FeedbackSheet({
|
|
|
271
294
|
<ThemedText
|
|
272
295
|
variant="caption"
|
|
273
296
|
color={
|
|
274
|
-
characterCount > maxMessageLength
|
|
275
|
-
? theme.colors.error
|
|
276
|
-
: theme.colors.textSecondary
|
|
297
|
+
characterCount > maxMessageLength ? theme.colors.error : theme.colors.textSecondary
|
|
277
298
|
}
|
|
278
|
-
style={{ marginTop: theme.spacing.xs, textAlign:
|
|
299
|
+
style={{ marginTop: theme.spacing.xs, textAlign: "right" }}
|
|
279
300
|
>
|
|
280
301
|
{characterCount}/{maxMessageLength}
|
|
281
302
|
</ThemedText>
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from 'react-native';
|
|
7
|
-
import type { PressableProps, ViewStyle, StyleProp } from 'react-native';
|
|
8
|
-
import { useHarkenTheme } from '../hooks';
|
|
9
|
-
import { ThemedText } from './ThemedText';
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Pressable, ActivityIndicator, StyleSheet } from "react-native";
|
|
3
|
+
import type { PressableProps, ViewStyle, TextStyle, StyleProp } from "react-native";
|
|
4
|
+
import { useHarkenTheme } from "../hooks";
|
|
5
|
+
import { ThemedText } from "./ThemedText";
|
|
10
6
|
|
|
11
|
-
export type ButtonVariant =
|
|
7
|
+
export type ButtonVariant = "primary" | "secondary" | "ghost";
|
|
12
8
|
|
|
13
|
-
export interface ThemedButtonProps extends Omit<PressableProps,
|
|
9
|
+
export interface ThemedButtonProps extends Omit<PressableProps, "children" | "style"> {
|
|
14
10
|
/** Button text */
|
|
15
11
|
title: string;
|
|
16
12
|
/** Button variant */
|
|
@@ -24,36 +20,47 @@ export interface ThemedButtonProps extends Omit<PressableProps, 'children' | 'st
|
|
|
24
20
|
* Note: Function styles are not supported; use static StyleProp<ViewStyle>.
|
|
25
21
|
*/
|
|
26
22
|
style?: StyleProp<ViewStyle>;
|
|
23
|
+
/** Additional styles for the button text */
|
|
24
|
+
textStyle?: StyleProp<TextStyle>;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
/**
|
|
30
28
|
* Themed button component with Harken styling.
|
|
29
|
+
*
|
|
30
|
+
* Uses the following theme tokens:
|
|
31
|
+
* - `colors.buttonPrimary*` for primary variant
|
|
32
|
+
* - `colors.buttonSecondary*` for secondary variant
|
|
33
|
+
* - `colors.buttonGhostText` for ghost variant
|
|
34
|
+
* - `spacing.buttonPadding*` for padding
|
|
35
|
+
* - `radii.button` for border radius
|
|
36
|
+
* - `sizing.buttonMinHeight` for minimum height
|
|
37
|
+
* - `opacity.disabled` for disabled state
|
|
31
38
|
*/
|
|
32
39
|
export function ThemedButton({
|
|
33
40
|
title,
|
|
34
|
-
variant =
|
|
41
|
+
variant = "primary",
|
|
35
42
|
loading = false,
|
|
36
43
|
fullWidth = false,
|
|
37
44
|
disabled,
|
|
38
45
|
style,
|
|
46
|
+
textStyle,
|
|
39
47
|
...props
|
|
40
48
|
}: ThemedButtonProps): React.JSX.Element {
|
|
41
49
|
const theme = useHarkenTheme();
|
|
50
|
+
const { button } = theme.components;
|
|
42
51
|
|
|
43
52
|
const getBackgroundColor = (pressed: boolean): string => {
|
|
44
53
|
if (disabled) {
|
|
45
|
-
return variant ===
|
|
46
|
-
? theme.colors.border
|
|
47
|
-
: 'transparent';
|
|
54
|
+
return variant === "primary" ? theme.colors.border : "transparent";
|
|
48
55
|
}
|
|
49
56
|
|
|
50
57
|
switch (variant) {
|
|
51
|
-
case
|
|
52
|
-
return pressed ?
|
|
53
|
-
case
|
|
54
|
-
return pressed ? theme.colors.border :
|
|
55
|
-
case
|
|
56
|
-
return pressed ? theme.colors.
|
|
58
|
+
case "primary":
|
|
59
|
+
return pressed ? button.primary.backgroundPressed : button.primary.background;
|
|
60
|
+
case "secondary":
|
|
61
|
+
return pressed ? theme.colors.border : button.secondary.background;
|
|
62
|
+
case "ghost":
|
|
63
|
+
return pressed ? theme.colors.surface : "transparent";
|
|
57
64
|
}
|
|
58
65
|
};
|
|
59
66
|
|
|
@@ -63,20 +70,21 @@ export function ThemedButton({
|
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
switch (variant) {
|
|
66
|
-
case
|
|
67
|
-
return
|
|
68
|
-
case
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
case "primary":
|
|
74
|
+
return button.primary.text;
|
|
75
|
+
case "secondary":
|
|
76
|
+
return button.secondary.text;
|
|
77
|
+
case "ghost":
|
|
78
|
+
return button.ghost.text;
|
|
71
79
|
}
|
|
72
80
|
};
|
|
73
81
|
|
|
74
82
|
const getBorderColor = (): string => {
|
|
75
83
|
switch (variant) {
|
|
76
|
-
case
|
|
77
|
-
return
|
|
84
|
+
case "secondary":
|
|
85
|
+
return button.secondary.border;
|
|
78
86
|
default:
|
|
79
|
-
return
|
|
87
|
+
return "transparent";
|
|
80
88
|
}
|
|
81
89
|
};
|
|
82
90
|
|
|
@@ -89,20 +97,20 @@ export function ThemedButton({
|
|
|
89
97
|
style={({ pressed }) => {
|
|
90
98
|
const baseStyle: ViewStyle = {
|
|
91
99
|
backgroundColor: getBackgroundColor(pressed),
|
|
92
|
-
borderWidth: variant ===
|
|
100
|
+
borderWidth: variant === "secondary" ? 1 : 0,
|
|
93
101
|
borderColor: getBorderColor(),
|
|
94
|
-
borderRadius:
|
|
95
|
-
paddingVertical:
|
|
96
|
-
paddingHorizontal:
|
|
97
|
-
alignItems:
|
|
98
|
-
justifyContent:
|
|
99
|
-
flexDirection:
|
|
100
|
-
minHeight:
|
|
101
|
-
opacity: disabled ?
|
|
102
|
+
borderRadius: button.radius,
|
|
103
|
+
paddingVertical: button.paddingVertical + 4,
|
|
104
|
+
paddingHorizontal: button.paddingHorizontal,
|
|
105
|
+
alignItems: "center",
|
|
106
|
+
justifyContent: "center",
|
|
107
|
+
flexDirection: "row",
|
|
108
|
+
minHeight: button.minHeight,
|
|
109
|
+
opacity: disabled ? theme.opacity.disabled : 1,
|
|
102
110
|
};
|
|
103
111
|
|
|
104
112
|
if (fullWidth) {
|
|
105
|
-
baseStyle.width =
|
|
113
|
+
baseStyle.width = "100%";
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
return [baseStyle, flattenedStyle];
|
|
@@ -110,15 +118,9 @@ export function ThemedButton({
|
|
|
110
118
|
{...props}
|
|
111
119
|
>
|
|
112
120
|
{loading ? (
|
|
113
|
-
<ActivityIndicator
|
|
114
|
-
color={getTextColor()}
|
|
115
|
-
size="small"
|
|
116
|
-
/>
|
|
121
|
+
<ActivityIndicator color={getTextColor()} size="small" />
|
|
117
122
|
) : (
|
|
118
|
-
<ThemedText
|
|
119
|
-
variant="label"
|
|
120
|
-
color={getTextColor()}
|
|
121
|
-
>
|
|
123
|
+
<ThemedText variant="label" color={getTextColor()} style={textStyle}>
|
|
122
124
|
{title}
|
|
123
125
|
</ThemedText>
|
|
124
126
|
)}
|