@oxy.so/services 9.1.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/index.js +4 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/client.js +174 -0
- package/lib/commonjs/ui/client.js.map +1 -1
- package/lib/commonjs/ui/components/BenefitList.js +1 -1
- package/lib/commonjs/ui/components/BenefitList.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +2 -2
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/FollowTargetButton.js +13 -103
- package/lib/commonjs/ui/components/FollowTargetButton.js.map +1 -1
- package/lib/commonjs/ui/components/PeableButton.js +1 -2
- package/lib/commonjs/ui/components/PeableButton.js.map +1 -1
- package/lib/commonjs/ui/components/SurfaceHeaderAction.js +1 -1
- package/lib/commonjs/ui/components/SurfaceHeaderAction.js.map +1 -1
- package/lib/commonjs/ui/components/SurfaceScreen.js +1 -1
- package/lib/commonjs/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +1 -1
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/primitives.js +1 -1
- package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/requestSurfaces.js +1 -1
- package/lib/commonjs/ui/components/authChooser/requestSurfaces.js.map +1 -1
- package/lib/commonjs/ui/components/followRules.js +105 -0
- package/lib/commonjs/ui/components/followRules.js.map +1 -0
- package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js +2 -2
- package/lib/commonjs/ui/components/payment/PaymentDetailsStep.js.map +1 -1
- package/lib/commonjs/ui/components/payment/PaymentMethodStep.js +2 -2
- package/lib/commonjs/ui/components/payment/PaymentMethodStep.js.map +1 -1
- package/lib/commonjs/ui/components/payment/PaymentReviewStep.js +2 -2
- package/lib/commonjs/ui/components/payment/PaymentReviewStep.js.map +1 -1
- package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js +1 -1
- package/lib/commonjs/ui/components/payment/PaymentSuccessStep.js.map +1 -1
- package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js +2 -2
- package/lib/commonjs/ui/components/payment/PaymentSummaryStep.js.map +1 -1
- package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +1 -1
- package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -1
- package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js +1 -1
- package/lib/commonjs/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
- package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js +2 -2
- package/lib/commonjs/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
- package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js +2 -1
- package/lib/commonjs/ui/components/surfaces/ActionSheetSurface.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountMembersScreen.js +4 -4
- package/lib/commonjs/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js +1 -1
- package/lib/commonjs/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js +1 -1
- package/lib/commonjs/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/DomainsScreen.js +1 -1
- package/lib/commonjs/ui/screens/DomainsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +4 -2
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +5 -5
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js +1 -1
- package/lib/commonjs/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js +1 -1
- package/lib/commonjs/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js +1 -1
- package/lib/commonjs/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/NotificationsScreen.js +8 -8
- package/lib/commonjs/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js +1 -1
- package/lib/commonjs/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PreferencesScreen.js +2 -2
- package/lib/commonjs/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js +37 -37
- package/lib/commonjs/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js +1 -1
- package/lib/commonjs/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js +5 -5
- package/lib/commonjs/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/UserListScreen.js +1 -1
- package/lib/commonjs/ui/screens/UserListScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js +11 -11
- package/lib/commonjs/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/UploadBar.js +1 -1
- package/lib/commonjs/ui/screens/fileManagement/UploadBar.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js +1 -1
- package/lib/commonjs/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js +1 -1
- package/lib/commonjs/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/module/index.js +3 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/client.js +17 -4
- package/lib/module/ui/client.js.map +1 -1
- package/lib/module/ui/components/BenefitList.js +1 -1
- package/lib/module/ui/components/BenefitList.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +2 -2
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/FollowTargetButton.js +3 -91
- package/lib/module/ui/components/FollowTargetButton.js.map +1 -1
- package/lib/module/ui/components/PeableButton.js +2 -3
- package/lib/module/ui/components/PeableButton.js.map +1 -1
- package/lib/module/ui/components/SurfaceHeaderAction.js +1 -1
- package/lib/module/ui/components/SurfaceHeaderAction.js.map +1 -1
- package/lib/module/ui/components/SurfaceScreen.js +1 -1
- package/lib/module/ui/components/SurfaceScreen.js.map +1 -1
- package/lib/module/ui/components/authChooser/AccountsMenuView.js +1 -1
- package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/module/ui/components/authChooser/primitives.js +1 -1
- package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/module/ui/components/authChooser/requestSurfaces.js +1 -1
- package/lib/module/ui/components/authChooser/requestSurfaces.js.map +1 -1
- package/lib/module/ui/components/followRules.js +99 -0
- package/lib/module/ui/components/followRules.js.map +1 -0
- package/lib/module/ui/components/payment/PaymentDetailsStep.js +2 -2
- package/lib/module/ui/components/payment/PaymentDetailsStep.js.map +1 -1
- package/lib/module/ui/components/payment/PaymentMethodStep.js +2 -2
- package/lib/module/ui/components/payment/PaymentMethodStep.js.map +1 -1
- package/lib/module/ui/components/payment/PaymentReviewStep.js +2 -2
- package/lib/module/ui/components/payment/PaymentReviewStep.js.map +1 -1
- package/lib/module/ui/components/payment/PaymentSuccessStep.js +1 -1
- package/lib/module/ui/components/payment/PaymentSuccessStep.js.map +1 -1
- package/lib/module/ui/components/payment/PaymentSummaryStep.js +2 -2
- package/lib/module/ui/components/payment/PaymentSummaryStep.js.map +1 -1
- package/lib/module/ui/components/signIn/OxyAuthScreen.js +1 -1
- package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -1
- package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js +1 -1
- package/lib/module/ui/components/signIn/OxyLinkCommonsPanel.js.map +1 -1
- package/lib/module/ui/components/signIn/OxyPasswordPanel.js +2 -2
- package/lib/module/ui/components/signIn/OxyPasswordPanel.js.map +1 -1
- package/lib/module/ui/components/surfaces/ActionSheetSurface.js +2 -1
- package/lib/module/ui/components/surfaces/ActionSheetSurface.js.map +1 -1
- package/lib/module/ui/screens/AccountMembersScreen.js +4 -4
- package/lib/module/ui/screens/AccountMembersScreen.js.map +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js +1 -1
- package/lib/module/ui/screens/AccountVerificationScreen.js.map +1 -1
- package/lib/module/ui/screens/ConnectedAppsScreen.js +1 -1
- package/lib/module/ui/screens/ConnectedAppsScreen.js.map +1 -1
- package/lib/module/ui/screens/DomainsScreen.js +1 -1
- package/lib/module/ui/screens/DomainsScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +4 -2
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +5 -5
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js +1 -1
- package/lib/module/ui/screens/HistoryViewScreen.js.map +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js +1 -1
- package/lib/module/ui/screens/LanguageSelectorScreen.js.map +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js +1 -1
- package/lib/module/ui/screens/LegalDocumentsScreen.js.map +1 -1
- package/lib/module/ui/screens/NotificationsScreen.js +8 -8
- package/lib/module/ui/screens/NotificationsScreen.js.map +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js +1 -1
- package/lib/module/ui/screens/PaymentGatewayScreen.js.map +1 -1
- package/lib/module/ui/screens/PreferencesScreen.js +2 -2
- package/lib/module/ui/screens/PreferencesScreen.js.map +1 -1
- package/lib/module/ui/screens/PrivacySettingsScreen.js +37 -37
- package/lib/module/ui/screens/PrivacySettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/ProfileScreen.js +1 -1
- package/lib/module/ui/screens/ProfileScreen.js.map +1 -1
- package/lib/module/ui/screens/SearchSettingsScreen.js +5 -5
- package/lib/module/ui/screens/SearchSettingsScreen.js.map +1 -1
- package/lib/module/ui/screens/UserListScreen.js +1 -1
- package/lib/module/ui/screens/UserListScreen.js.map +1 -1
- package/lib/module/ui/screens/WelcomeNewUserScreen.js +11 -11
- package/lib/module/ui/screens/WelcomeNewUserScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/UploadBar.js +1 -1
- package/lib/module/ui/screens/fileManagement/UploadBar.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustCenterScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustRulesScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustRulesScreen.js.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/client.d.ts +19 -4
- package/lib/typescript/commonjs/ui/client.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/BenefitList.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts +3 -63
- package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/PeableButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/followRules.d.ts +71 -0
- package/lib/typescript/commonjs/ui/components/followRules.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/client.d.ts +19 -4
- package/lib/typescript/module/ui/client.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/BenefitList.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FollowButton.d.ts +1 -1
- package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FollowTargetButton.d.ts +3 -63
- package/lib/typescript/module/ui/components/FollowTargetButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/PeableButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/followRules.d.ts +71 -0
- package/lib/typescript/module/ui/components/followRules.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/surfaces/ActionSheetSurface.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/EditProfileFieldScreen.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +3 -3
- package/src/ui/client.ts +55 -4
- package/src/ui/components/BenefitList.tsx +1 -2
- package/src/ui/components/FollowButton.tsx +3 -3
- package/src/ui/components/FollowTargetButton.tsx +11 -115
- package/src/ui/components/PeableButton.tsx +3 -4
- package/src/ui/components/SurfaceHeaderAction.tsx +1 -1
- package/src/ui/components/SurfaceScreen.tsx +1 -1
- package/src/ui/components/__tests__/followButtonAccessibility.test.tsx +9 -0
- package/src/ui/components/__tests__/followTargetButton.test.ts +1 -1
- package/src/ui/components/authChooser/AccountsMenuView.tsx +1 -1
- package/src/ui/components/authChooser/primitives.tsx +1 -1
- package/src/ui/components/authChooser/requestSurfaces.tsx +1 -1
- package/src/ui/components/followRules.ts +121 -0
- package/src/ui/components/payment/PaymentDetailsStep.tsx +2 -2
- package/src/ui/components/payment/PaymentMethodStep.tsx +2 -2
- package/src/ui/components/payment/PaymentReviewStep.tsx +2 -2
- package/src/ui/components/payment/PaymentSuccessStep.tsx +1 -1
- package/src/ui/components/payment/PaymentSummaryStep.tsx +2 -2
- package/src/ui/components/signIn/OxyAuthScreen.tsx +1 -1
- package/src/ui/components/signIn/OxyLinkCommonsPanel.tsx +1 -1
- package/src/ui/components/signIn/OxyPasswordPanel.tsx +1 -1
- package/src/ui/components/surfaces/ActionSheetSurface.tsx +2 -1
- package/src/ui/screens/AccountMembersScreen.tsx +4 -4
- package/src/ui/screens/AccountVerificationScreen.tsx +1 -1
- package/src/ui/screens/ConnectedAppsScreen.tsx +1 -1
- package/src/ui/screens/DomainsScreen.tsx +1 -1
- package/src/ui/screens/EditProfileFieldScreen.tsx +1 -2
- package/src/ui/screens/FileManagementScreen.tsx +5 -5
- package/src/ui/screens/HistoryViewScreen.tsx +1 -1
- package/src/ui/screens/LanguageSelectorScreen.tsx +1 -1
- package/src/ui/screens/LegalDocumentsScreen.tsx +1 -1
- package/src/ui/screens/NotificationsScreen.tsx +8 -8
- package/src/ui/screens/PaymentGatewayScreen.tsx +1 -1
- package/src/ui/screens/PreferencesScreen.tsx +2 -2
- package/src/ui/screens/PrivacySettingsScreen.tsx +21 -21
- package/src/ui/screens/ProfileScreen.tsx +1 -1
- package/src/ui/screens/SearchSettingsScreen.tsx +5 -5
- package/src/ui/screens/UserListScreen.tsx +1 -1
- package/src/ui/screens/WelcomeNewUserScreen.tsx +11 -11
- package/src/ui/screens/fileManagement/UploadBar.tsx +1 -1
- package/src/ui/screens/trust/TrustCenterScreen.tsx +1 -1
- package/src/ui/screens/trust/TrustRulesScreen.tsx +1 -1
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
34
|
import { memo, useCallback, useMemo } from 'react';
|
|
35
|
-
import type {
|
|
35
|
+
import type { FollowStatus } from '@oxy.so/contracts';
|
|
36
36
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
37
37
|
import { View } from 'react-native';
|
|
38
38
|
import { FollowButton as BloomFollowButton } from '@oxy.so/bloom/media-header';
|
|
@@ -51,6 +51,13 @@ import {
|
|
|
51
51
|
import { toast } from '@oxy.so/bloom/toast';
|
|
52
52
|
import { useFollowTarget } from '../hooks/useFollowTarget';
|
|
53
53
|
import { useFollowTargetStore } from '../stores/followTargetStore';
|
|
54
|
+
import {
|
|
55
|
+
buildFollowMenuItems,
|
|
56
|
+
FOLLOW_ACTION_LEAVES_ACTIVE,
|
|
57
|
+
resolveFollowPrimaryAction,
|
|
58
|
+
type FollowDuration,
|
|
59
|
+
type FollowMenuItem,
|
|
60
|
+
} from './followRules';
|
|
54
61
|
|
|
55
62
|
/**
|
|
56
63
|
* The small vocabulary of verbs the ecosystem actually uses. An application
|
|
@@ -82,12 +89,6 @@ const VERB_LABELS: Record<FollowVerb, FollowLabels> = {
|
|
|
82
89
|
watch: { idle: 'Watch', active: 'Watching', pending: 'Requested', disabled: 'Off here' },
|
|
83
90
|
};
|
|
84
91
|
|
|
85
|
-
/** A timed-follow choice offered in the menu. */
|
|
86
|
-
export interface FollowDuration {
|
|
87
|
-
label: string;
|
|
88
|
-
seconds: number;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
92
|
const HOUR = 60 * 60;
|
|
92
93
|
|
|
93
94
|
/**
|
|
@@ -101,118 +102,13 @@ const DEFAULT_DURATIONS: FollowDuration[] = [
|
|
|
101
102
|
{ label: 'A week', seconds: 7 * 24 * HOUR },
|
|
102
103
|
];
|
|
103
104
|
|
|
104
|
-
/**
|
|
105
|
-
* Whether an action leaves the target ACTIVE in this application.
|
|
106
|
-
*
|
|
107
|
-
* One table, read by both the primary button and the menu, because the same
|
|
108
|
-
* action reached from two controls once reported differently — and a rule
|
|
109
|
-
* living in two switch statements is a rule that drifts. `Record` rather than
|
|
110
|
-
* a function with a default, so a new action is a compile error instead of a
|
|
111
|
-
* silent `false`.
|
|
112
|
-
*/
|
|
113
|
-
export const FOLLOW_ACTION_LEAVES_ACTIVE: Record<
|
|
114
|
-
'follow' | 'follow-timed' | 'enable-here' | 'disable-here' | 'unfollow',
|
|
115
|
-
boolean
|
|
116
|
-
> = {
|
|
117
|
-
follow: true,
|
|
118
|
-
'follow-timed': true,
|
|
119
|
-
// Re-enabling here does not change the global follow — the user already had
|
|
120
|
-
// it — but it does change whether this application acts on it, which is what
|
|
121
|
-
// a mirror is asking about.
|
|
122
|
-
'enable-here': true,
|
|
123
|
-
'disable-here': false,
|
|
124
|
-
unfollow: false,
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
/** One line in the disclosure menu. */
|
|
128
|
-
export interface FollowMenuItem {
|
|
129
|
-
key: string;
|
|
130
|
-
label: string;
|
|
131
|
-
/** What the component should call. Named so the table below stays pure. */
|
|
132
|
-
action:
|
|
133
|
-
| { type: 'follow-timed'; seconds: number; durationLabel: string }
|
|
134
|
-
| { type: 'enable-here' }
|
|
135
|
-
| { type: 'disable-here' }
|
|
136
|
-
| { type: 'unfollow' };
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Which choices exist, given the state.
|
|
141
|
-
*
|
|
142
|
-
* Pure and exported because this is the product decision, not a rendering
|
|
143
|
-
* detail: a timed follow is only offered before following, turning it off here
|
|
144
|
-
* is only offered while following, and NEITHER is offered before the server has
|
|
145
|
-
* answered — every one of them addresses a relationship that does not exist
|
|
146
|
-
* yet, so offering them mid-write would mean sending a guessed id.
|
|
147
|
-
*/
|
|
148
|
-
/**
|
|
149
|
-
* What the main button should do for the current state.
|
|
150
|
-
*
|
|
151
|
-
* Exported because the product rule is not obvious from the label alone: a
|
|
152
|
-
* follow switched off here still reads as "following" globally, so the primary
|
|
153
|
-
* press must re-enable here — not unfollow everywhere.
|
|
154
|
-
*/
|
|
155
|
-
export function resolveFollowPrimaryAction(input: {
|
|
156
|
-
isFollowing: boolean;
|
|
157
|
-
applicationMode: FollowApplicationMode;
|
|
158
|
-
}): 'follow' | 'unfollow' | 'enable-here' {
|
|
159
|
-
if (!input.isFollowing) return 'follow';
|
|
160
|
-
if (input.applicationMode === 'disabled') return 'enable-here';
|
|
161
|
-
return 'unfollow';
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function buildFollowMenuItems(input: {
|
|
165
|
-
following: boolean;
|
|
166
|
-
applicationMode: FollowApplicationMode;
|
|
167
|
-
hasRelationship: boolean;
|
|
168
|
-
isPending: boolean;
|
|
169
|
-
durations: FollowDuration[] | false;
|
|
170
|
-
idleVerb: string;
|
|
171
|
-
applicationName: string;
|
|
172
|
-
}): FollowMenuItem[] {
|
|
173
|
-
const items: FollowMenuItem[] = [];
|
|
174
|
-
|
|
175
|
-
if (!input.following) {
|
|
176
|
-
if (input.durations === false) return items;
|
|
177
|
-
for (const d of input.durations) {
|
|
178
|
-
items.push({
|
|
179
|
-
key: `for-${d.seconds}`,
|
|
180
|
-
label: `${input.idleVerb} for ${d.label.toLowerCase()}`,
|
|
181
|
-
action: { type: 'follow-timed', seconds: d.seconds, durationLabel: d.label },
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
return items;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (!input.hasRelationship || input.isPending) return items;
|
|
188
|
-
|
|
189
|
-
items.push(
|
|
190
|
-
input.applicationMode === 'disabled'
|
|
191
|
-
? { key: 'enable-here', label: `Show in ${input.applicationName}`, action: { type: 'enable-here' } }
|
|
192
|
-
: {
|
|
193
|
-
key: 'disable-here',
|
|
194
|
-
label: `Don’t show in ${input.applicationName}`,
|
|
195
|
-
action: { type: 'disable-here' },
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
items.push({
|
|
199
|
-
// Named for what it does. "Unfollow" beside "don't show here" would read as
|
|
200
|
-
// the same action twice, and the user would pick the wrong one.
|
|
201
|
-
key: 'unfollow-everywhere',
|
|
202
|
-
label: 'Unfollow everywhere',
|
|
203
|
-
action: { type: 'unfollow' },
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
return items;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
105
|
export interface FollowTargetButtonProps {
|
|
210
106
|
/** The registered target's id. Registration is separate — see the SDK. */
|
|
211
107
|
targetId: string;
|
|
212
108
|
verb?: FollowVerb;
|
|
213
109
|
/** Full override, for a verb the vocabulary above does not carry. */
|
|
214
110
|
labels?: Partial<FollowLabels>;
|
|
215
|
-
size?: '
|
|
111
|
+
size?: 'sm' | 'md' | 'lg';
|
|
216
112
|
style?: StyleProp<ViewStyle>;
|
|
217
113
|
disabled?: boolean;
|
|
218
114
|
/**
|
|
@@ -256,7 +152,7 @@ export const FollowTargetButton = memo(function FollowTargetButton({
|
|
|
256
152
|
targetId,
|
|
257
153
|
verb = 'follow',
|
|
258
154
|
labels,
|
|
259
|
-
size = '
|
|
155
|
+
size = 'md',
|
|
260
156
|
style,
|
|
261
157
|
disabled = false,
|
|
262
158
|
showOptions = true,
|
|
@@ -413,7 +309,7 @@ export const FollowTargetButton = memo(function FollowTargetButton({
|
|
|
413
309
|
<DropdownMenuTrigger asChild disabled={disabled || isUnknown}>
|
|
414
310
|
<Button
|
|
415
311
|
appearance="subtle" tone="support"
|
|
416
|
-
size={size === '
|
|
312
|
+
size={size === 'lg' ? 'lg' : 'sm'}
|
|
417
313
|
icon={<ChevronDown width={16} />}
|
|
418
314
|
disabled={disabled || isUnknown}
|
|
419
315
|
accessibilityLabel={`${label} options`}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import type { ViewStyle, TextStyle, StyleProp } from 'react-native';
|
|
3
3
|
import { useTheme } from '@oxy.so/bloom/theme';
|
|
4
|
-
import {
|
|
4
|
+
import { InverseButton } from '@oxy.so/bloom/button';
|
|
5
5
|
import type { PaymentItem, PaymentGatewayResult } from '../screens/PaymentGatewayScreen';
|
|
6
6
|
import { LogoIcon } from './logo/LogoIcon';
|
|
7
7
|
|
|
@@ -46,8 +46,7 @@ const PeableButton: React.FC<PeableButtonProps> = ({
|
|
|
46
46
|
const textColor = variant === 'black' || (color && isColorDark(color)) ? theme.colors.background : '#1b1f0a';
|
|
47
47
|
|
|
48
48
|
return (
|
|
49
|
-
<
|
|
50
|
-
variant="inverse"
|
|
49
|
+
<InverseButton
|
|
51
50
|
onPress={handlePress}
|
|
52
51
|
disabled={disabled}
|
|
53
52
|
style={[{ backgroundColor, borderColor: textColor, borderWidth: 1 }, style]}
|
|
@@ -55,7 +54,7 @@ const PeableButton: React.FC<PeableButtonProps> = ({
|
|
|
55
54
|
icon={<LogoIcon height={16} color={textColor} style={{ marginRight: 6 }} />}
|
|
56
55
|
>
|
|
57
56
|
{text}
|
|
58
|
-
</
|
|
57
|
+
</InverseButton>
|
|
59
58
|
);
|
|
60
59
|
};
|
|
61
60
|
|
|
@@ -12,7 +12,7 @@ export interface SurfaceHeaderActionProps {
|
|
|
12
12
|
|
|
13
13
|
/** Header actions share Bloom's sizing, surface, disabled and loading behavior. */
|
|
14
14
|
export const SurfaceHeaderAction: React.FC<SurfaceHeaderActionProps> = ({ label, onPress, loading, disabled }) => (
|
|
15
|
-
<Button size="
|
|
15
|
+
<Button size="md" onPress={onPress} loading={loading} disabled={disabled}>
|
|
16
16
|
{label}
|
|
17
17
|
</Button>
|
|
18
18
|
);
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from '../followButtonAccessibility';
|
|
17
17
|
|
|
18
18
|
interface BloomFollowProps {
|
|
19
|
+
size?: 'sm' | 'md' | 'lg';
|
|
19
20
|
following: boolean;
|
|
20
21
|
label?: string;
|
|
21
22
|
followingLabel?: string;
|
|
@@ -189,3 +190,11 @@ describe('FollowTargetButton names the state it shows', () => {
|
|
|
189
190
|
expect(lastBloomProps()?.accessibilityLabel).toBe(label);
|
|
190
191
|
});
|
|
191
192
|
});
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
it.each(['sm', 'md', 'lg'] as const)('forwards canonical %s geometry in both follow modes', size => {
|
|
196
|
+
render(<FollowButton userId="nate-id" size={size} />);
|
|
197
|
+
expect(lastBloomProps()?.size).toBe(size);
|
|
198
|
+
render(<FollowButton userIds={['a', 'b']} size={size} />);
|
|
199
|
+
expect(lastBloomProps()?.size).toBe(size);
|
|
200
|
+
});
|
|
@@ -40,7 +40,7 @@ const ROUTE_GLYPH_SIZE = 44;
|
|
|
40
40
|
*/
|
|
41
41
|
export const PreparingSurface: React.FC = () => {
|
|
42
42
|
const { t } = useI18n();
|
|
43
|
-
return <Loading variant="spinner" size="
|
|
43
|
+
return <Loading variant="spinner" size="lg" accessibilityLabel={t('common.status.loading')} />;
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
/** The leading glyph for a route whose surface is elsewhere (the phone, Commons). */
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The follow button's product rules, without the button.
|
|
3
|
+
*
|
|
4
|
+
* Pure: no React, no Bloom. `FollowTargetButton` renders them, and an
|
|
5
|
+
* application drawing its own affordance (a chip grid, a compact row) imports
|
|
6
|
+
* them from here — through `@oxy.so/services/ui/client` — without paying for the
|
|
7
|
+
* button's dropdown menu.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { FollowApplicationMode } from '@oxy.so/contracts';
|
|
11
|
+
|
|
12
|
+
/** A timed-follow choice offered in the menu. */
|
|
13
|
+
export interface FollowDuration {
|
|
14
|
+
label: string;
|
|
15
|
+
seconds: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Whether an action leaves the target ACTIVE in this application.
|
|
20
|
+
*
|
|
21
|
+
* One table, read by both the primary button and the menu, because the same
|
|
22
|
+
* action reached from two controls once reported differently — and a rule
|
|
23
|
+
* living in two switch statements is a rule that drifts. `Record` rather than
|
|
24
|
+
* a function with a default, so a new action is a compile error instead of a
|
|
25
|
+
* silent `false`.
|
|
26
|
+
*/
|
|
27
|
+
export const FOLLOW_ACTION_LEAVES_ACTIVE: Record<
|
|
28
|
+
'follow' | 'follow-timed' | 'enable-here' | 'disable-here' | 'unfollow',
|
|
29
|
+
boolean
|
|
30
|
+
> = {
|
|
31
|
+
follow: true,
|
|
32
|
+
'follow-timed': true,
|
|
33
|
+
// Re-enabling here does not change the global follow — the user already had
|
|
34
|
+
// it — but it does change whether this application acts on it, which is what
|
|
35
|
+
// a mirror is asking about.
|
|
36
|
+
'enable-here': true,
|
|
37
|
+
'disable-here': false,
|
|
38
|
+
unfollow: false,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** One line in the disclosure menu. */
|
|
42
|
+
export interface FollowMenuItem {
|
|
43
|
+
key: string;
|
|
44
|
+
label: string;
|
|
45
|
+
/** What the component should call. Named so the table below stays pure. */
|
|
46
|
+
action:
|
|
47
|
+
| { type: 'follow-timed'; seconds: number; durationLabel: string }
|
|
48
|
+
| { type: 'enable-here' }
|
|
49
|
+
| { type: 'disable-here' }
|
|
50
|
+
| { type: 'unfollow' };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Which choices exist, given the state.
|
|
55
|
+
*
|
|
56
|
+
* Pure and exported because this is the product decision, not a rendering
|
|
57
|
+
* detail: a timed follow is only offered before following, turning it off here
|
|
58
|
+
* is only offered while following, and NEITHER is offered before the server has
|
|
59
|
+
* answered — every one of them addresses a relationship that does not exist
|
|
60
|
+
* yet, so offering them mid-write would mean sending a guessed id.
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* What the main button should do for the current state.
|
|
64
|
+
*
|
|
65
|
+
* Exported because the product rule is not obvious from the label alone: a
|
|
66
|
+
* follow switched off here still reads as "following" globally, so the primary
|
|
67
|
+
* press must re-enable here — not unfollow everywhere.
|
|
68
|
+
*/
|
|
69
|
+
export function resolveFollowPrimaryAction(input: {
|
|
70
|
+
isFollowing: boolean;
|
|
71
|
+
applicationMode: FollowApplicationMode;
|
|
72
|
+
}): 'follow' | 'unfollow' | 'enable-here' {
|
|
73
|
+
if (!input.isFollowing) return 'follow';
|
|
74
|
+
if (input.applicationMode === 'disabled') return 'enable-here';
|
|
75
|
+
return 'unfollow';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function buildFollowMenuItems(input: {
|
|
79
|
+
following: boolean;
|
|
80
|
+
applicationMode: FollowApplicationMode;
|
|
81
|
+
hasRelationship: boolean;
|
|
82
|
+
isPending: boolean;
|
|
83
|
+
durations: FollowDuration[] | false;
|
|
84
|
+
idleVerb: string;
|
|
85
|
+
applicationName: string;
|
|
86
|
+
}): FollowMenuItem[] {
|
|
87
|
+
const items: FollowMenuItem[] = [];
|
|
88
|
+
|
|
89
|
+
if (!input.following) {
|
|
90
|
+
if (input.durations === false) return items;
|
|
91
|
+
for (const d of input.durations) {
|
|
92
|
+
items.push({
|
|
93
|
+
key: `for-${d.seconds}`,
|
|
94
|
+
label: `${input.idleVerb} for ${d.label.toLowerCase()}`,
|
|
95
|
+
action: { type: 'follow-timed', seconds: d.seconds, durationLabel: d.label },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return items;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!input.hasRelationship || input.isPending) return items;
|
|
102
|
+
|
|
103
|
+
items.push(
|
|
104
|
+
input.applicationMode === 'disabled'
|
|
105
|
+
? { key: 'enable-here', label: `Show in ${input.applicationName}`, action: { type: 'enable-here' } }
|
|
106
|
+
: {
|
|
107
|
+
key: 'disable-here',
|
|
108
|
+
label: `Don’t show in ${input.applicationName}`,
|
|
109
|
+
action: { type: 'disable-here' },
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
items.push({
|
|
113
|
+
// Named for what it does. "Unfollow" beside "don't show here" would read as
|
|
114
|
+
// the same action twice, and the user would pick the wrong one.
|
|
115
|
+
key: 'unfollow-everywhere',
|
|
116
|
+
label: 'Unfollow everywhere',
|
|
117
|
+
action: { type: 'unfollow' },
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return items;
|
|
121
|
+
}
|
|
@@ -214,13 +214,13 @@ const PaymentDetailsStep: React.FC<PaymentDetailsStepProps> = ({
|
|
|
214
214
|
</View>
|
|
215
215
|
|
|
216
216
|
<View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
|
|
217
|
-
<Button appearance="subtle" tone="neutral" onPress={onBack} size="
|
|
217
|
+
<Button appearance="subtle" tone="neutral" onPress={onBack} size="sm" icon={<Ionicons name="arrow-back" size={16} />}>
|
|
218
218
|
{t('payment.actions.back')}
|
|
219
219
|
</Button>
|
|
220
220
|
<Button
|
|
221
221
|
appearance="solid" tone="accent"
|
|
222
222
|
onPress={onNext}
|
|
223
|
-
size="
|
|
223
|
+
size="sm"
|
|
224
224
|
icon={<Ionicons name="arrow-forward" size={16} />}
|
|
225
225
|
iconPosition="right"
|
|
226
226
|
disabled={paymentMethod === 'card' && !isCardValid}
|
|
@@ -77,10 +77,10 @@ const PaymentMethodStep: React.FC<PaymentMethodStepProps> = ({
|
|
|
77
77
|
</View>
|
|
78
78
|
|
|
79
79
|
<View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
|
|
80
|
-
<Button appearance="subtle" tone="neutral" onPress={onBack} size="
|
|
80
|
+
<Button appearance="subtle" tone="neutral" onPress={onBack} size="sm" icon={<Ionicons name="arrow-back" size={16} />}>
|
|
81
81
|
{t('payment.actions.back')}
|
|
82
82
|
</Button>
|
|
83
|
-
<Button appearance="solid" tone="accent" onPress={onNext} size="
|
|
83
|
+
<Button appearance="solid" tone="accent" onPress={onNext} size="sm" icon={<Ionicons name="arrow-forward" size={16} />} iconPosition="right">
|
|
84
84
|
{t('payment.actions.continue')}
|
|
85
85
|
</Button>
|
|
86
86
|
</View>
|
|
@@ -105,13 +105,13 @@ const PaymentReviewStep: React.FC<PaymentReviewStepProps> = ({
|
|
|
105
105
|
</View>
|
|
106
106
|
|
|
107
107
|
<View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
|
|
108
|
-
<Button appearance="subtle" tone="neutral" onPress={onBack} size="
|
|
108
|
+
<Button appearance="subtle" tone="neutral" onPress={onBack} size="sm" disabled={isPaying} icon={<Ionicons name="arrow-back" size={16} />}>
|
|
109
109
|
{t('payment.actions.back')}
|
|
110
110
|
</Button>
|
|
111
111
|
<Button
|
|
112
112
|
appearance="solid" tone="accent"
|
|
113
113
|
onPress={onPay}
|
|
114
|
-
size="
|
|
114
|
+
size="sm"
|
|
115
115
|
disabled={isPaying}
|
|
116
116
|
icon={isPaying ? <ActivityIndicator size="small" color="#FFFFFF" /> : <Ionicons name="checkmark" size={16} />}
|
|
117
117
|
iconPosition="right"
|
|
@@ -57,7 +57,7 @@ const PaymentSuccessStep: React.FC<PaymentSuccessStepProps> = ({
|
|
|
57
57
|
</View>
|
|
58
58
|
</View>
|
|
59
59
|
|
|
60
|
-
<Button appearance="solid" tone="accent" onPress={onDone} size="
|
|
60
|
+
<Button appearance="solid" tone="accent" onPress={onDone} size="sm" icon={<Ionicons name="checkmark" size={16} />} iconPosition="right">
|
|
61
61
|
{t('payment.actions.done')}
|
|
62
62
|
</Button>
|
|
63
63
|
</Animated.View>
|
|
@@ -145,10 +145,10 @@ const PaymentSummaryStep: React.FC<PaymentSummaryStepProps> = ({
|
|
|
145
145
|
</View>
|
|
146
146
|
|
|
147
147
|
<View style={{ flexDirection: 'row', gap: 8, justifyContent: 'flex-end' }}>
|
|
148
|
-
<Button appearance="subtle" tone="neutral" onPress={onClose} size="
|
|
148
|
+
<Button appearance="subtle" tone="neutral" onPress={onClose} size="sm" icon={<Ionicons name="close" size={16} />}>
|
|
149
149
|
{t('payment.actions.close')}
|
|
150
150
|
</Button>
|
|
151
|
-
<Button appearance="solid" tone="accent" onPress={onNext} size="
|
|
151
|
+
<Button appearance="solid" tone="accent" onPress={onNext} size="sm" icon={<Ionicons name="arrow-forward" size={16} />} iconPosition="right">
|
|
152
152
|
{t('payment.actions.continue')}
|
|
153
153
|
</Button>
|
|
154
154
|
</View>
|
|
@@ -103,7 +103,7 @@ export const OxyAuthLoading: React.FC = () => {
|
|
|
103
103
|
const { t } = useI18n();
|
|
104
104
|
return (
|
|
105
105
|
<View className="min-h-[300px] items-center justify-center">
|
|
106
|
-
<Loading variant="spinner" size="
|
|
106
|
+
<Loading variant="spinner" size="lg" accessibilityLabel={t('common.status.loading')} testID="oxy-auth-loading" />
|
|
107
107
|
</View>
|
|
108
108
|
);
|
|
109
109
|
};
|
|
@@ -204,7 +204,7 @@ export const OxyLinkCommonsPanel: React.FC<OxyLinkCommonsPanelProps> = ({ onLink
|
|
|
204
204
|
<OxyAuthScreen>
|
|
205
205
|
<OxyAuthScreenHeader title={t('linkCommons.title')} description={t('linkCommons.subtitle')} />
|
|
206
206
|
<View style={styles.plateRow}>
|
|
207
|
-
<Loading variant="spinner" size="
|
|
207
|
+
<Loading variant="spinner" size="lg" accessibilityLabel={t('common.status.loading')} />
|
|
208
208
|
</View>
|
|
209
209
|
</OxyAuthScreen>
|
|
210
210
|
);
|
|
@@ -95,7 +95,7 @@ export const OxyPasswordPanel: React.FC<OxyPasswordPanelProps> = ({ onDone, onCa
|
|
|
95
95
|
{/* The field names the switch ("Sign out everywhere else, switch, off")
|
|
96
96
|
and, on web, its label toggles it. One row: label, then the switch. */}
|
|
97
97
|
<Field label={t('signInSecurity.password.signOutOthers')} style={styles.row}>
|
|
98
|
-
<Switch
|
|
98
|
+
<Switch checked={signOutOthers} onCheckedChange={setSignOutOthers} testID="password-sign-out-others" />
|
|
99
99
|
</Field>
|
|
100
100
|
</ReauthStep>
|
|
101
101
|
);
|
|
@@ -72,7 +72,8 @@ export function ActionSheetSurface<T extends string>({
|
|
|
72
72
|
{options.map((option) => (
|
|
73
73
|
<Button
|
|
74
74
|
key={option.value}
|
|
75
|
-
|
|
75
|
+
appearance="solid"
|
|
76
|
+
tone={option.destructive ? 'danger' : 'accent'}
|
|
76
77
|
onPress={() => surface.dismiss(option.value)}
|
|
77
78
|
>
|
|
78
79
|
{option.label}
|
|
@@ -291,7 +291,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
|
|
|
291
291
|
<Text className="text-caption font-caption text-text-secondary px-space-4">
|
|
292
292
|
{t('accounts.members.invite.roleLabel') || 'Role'}
|
|
293
293
|
</Text>
|
|
294
|
-
<SegmentedControl type="radio" label={t('accounts.members.invite.roleLabel') || 'Role'} value={inviteRole} onValueChange={setInviteRole} size="
|
|
294
|
+
<SegmentedControl type="radio" label={t('accounts.members.invite.roleLabel') || 'Role'} value={inviteRole} onValueChange={setInviteRole} size="sm">
|
|
295
295
|
{ASSIGNABLE_ROLES.map(role => <SegmentedControlItem key={role} value={role}>
|
|
296
296
|
<SegmentedControlItemText>{roleLabel(role)}</SegmentedControlItemText>
|
|
297
297
|
</SegmentedControlItem>)}
|
|
@@ -372,7 +372,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
|
|
|
372
372
|
{/* Role chips (editable) or static role label */}
|
|
373
373
|
{canEditThisRole ? (
|
|
374
374
|
<SegmentedControl type="radio" label={t('accounts.members.invite.roleLabel') || 'Role'}
|
|
375
|
-
value={member.role} onValueChange={role => handleChangeRole(member, role)} disabled={updateMutation.isPending} size="
|
|
375
|
+
value={member.role} onValueChange={role => handleChangeRole(member, role)} disabled={updateMutation.isPending} size="sm">
|
|
376
376
|
{ASSIGNABLE_ROLES.map(role => <SegmentedControlItem key={role} value={role}>
|
|
377
377
|
<SegmentedControlItemText>{roleLabel(role)}</SegmentedControlItemText>
|
|
378
378
|
</SegmentedControlItem>)}
|
|
@@ -387,7 +387,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
|
|
|
387
387
|
{(canTransferToThis || canRemoveThisMember) ? (
|
|
388
388
|
<View className="flex-row gap-space-16 pt-space-4">
|
|
389
389
|
{canTransferToThis ? (
|
|
390
|
-
<Button appearance="plain" tone="neutral" size="
|
|
390
|
+
<Button appearance="plain" tone="neutral" size="sm"
|
|
391
391
|
accessibilityRole="button"
|
|
392
392
|
accessibilityLabel={t('accounts.members.actions.transfer') || 'Transfer ownership'}
|
|
393
393
|
onPress={() => confirmTransfer(member)}
|
|
@@ -400,7 +400,7 @@ const AccountMembersScreen: React.FC<BaseScreenProps> = ({ onClose, goBack, acco
|
|
|
400
400
|
</Button>
|
|
401
401
|
) : null}
|
|
402
402
|
{canRemoveThisMember ? (
|
|
403
|
-
<Button appearance="plain" tone="neutral" size="
|
|
403
|
+
<Button appearance="plain" tone="neutral" size="sm"
|
|
404
404
|
accessibilityRole="button"
|
|
405
405
|
accessibilityLabel={t('accounts.members.actions.remove') || 'Remove member'}
|
|
406
406
|
onPress={() => confirmRemove(member)}
|
|
@@ -146,7 +146,7 @@ const ConnectedAppsScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) =>
|
|
|
146
146
|
return (
|
|
147
147
|
<View className="flex-1 bg-bg">
|
|
148
148
|
{isLoading && !apps ? (
|
|
149
|
-
<Loading size="
|
|
149
|
+
<Loading size="lg" color={bloomTheme.colors.primary} />
|
|
150
150
|
) : (
|
|
151
151
|
<FlatList
|
|
152
152
|
data={apps ?? []}
|
|
@@ -94,7 +94,7 @@ const DomainsScreen: React.FC<BaseScreenProps> = () => {
|
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
if (domains.isPending && isAuthenticated) {
|
|
97
|
-
return <Loading size="
|
|
97
|
+
return <Loading size="lg" color={bloomTheme.colors.primary} />;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
return (
|
|
@@ -704,11 +704,10 @@ const EditProfileFieldScreen: React.FC<EditProfileFieldScreenProps> = ({
|
|
|
704
704
|
</TextField>
|
|
705
705
|
</View>
|
|
706
706
|
<Button
|
|
707
|
-
variant="icon"
|
|
708
707
|
onPress={handleAddItem}
|
|
709
708
|
disabled={!newItemValue.trim()}
|
|
710
709
|
accessibilityLabel={addLabel}
|
|
711
|
-
icon={<Ionicons name="add" size={20} color={bloomTheme.colors.primaryForeground} />}
|
|
710
|
+
icon={<Ionicons name="add" size={20} color={bloomTheme.colors.primaryForeground} />} iconOnly tone="neutral" appearance="outline"
|
|
712
711
|
/>
|
|
713
712
|
</View>
|
|
714
713
|
|
|
@@ -776,13 +776,13 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
776
776
|
// Hide action buttons when selecting (in selectMode or bulk operations mode)
|
|
777
777
|
rightElement: (!selectMode && selectedIds.size === 0) ? (
|
|
778
778
|
<View className="flex-row items-center gap-1.5 ml-3">
|
|
779
|
-
{(isImage || isVideo || file.contentType.includes('pdf')) ? <Button appearance="subtle" tone="neutral" size="
|
|
779
|
+
{(isImage || isVideo || file.contentType.includes('pdf')) ? <Button appearance="subtle" tone="neutral" size="sm" iconOnly stopPropagation
|
|
780
780
|
accessibilityLabel={`Preview ${file.filename}`} onPress={() => handleFileOpen(file)}
|
|
781
781
|
icon={<Ionicons name="eye" size={18} color={colors.text} />} /> : null}
|
|
782
|
-
<Button appearance="subtle" tone="neutral" size="
|
|
782
|
+
<Button appearance="subtle" tone="neutral" size="sm" iconOnly stopPropagation
|
|
783
783
|
accessibilityLabel={`Download ${file.filename}`} onPress={() => handleFileDownload(file.id, file.filename)}
|
|
784
784
|
icon={<Ionicons name="download" size={18} color={colors.text} />} />
|
|
785
|
-
<Button appearance="subtle" tone="danger" size="
|
|
785
|
+
<Button appearance="subtle" tone="danger" size="sm" iconOnly stopPropagation loading={deletingId === file.id}
|
|
786
786
|
accessibilityLabel={`Delete ${file.filename}`} onPress={() => confirmFileDelete(file.id, file.filename)}
|
|
787
787
|
icon={<Ionicons name="trash" size={18} color={colors.error} />} />
|
|
788
788
|
</View>
|
|
@@ -1144,7 +1144,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1144
1144
|
style={{ maxWidth: '80%' }}
|
|
1145
1145
|
>
|
|
1146
1146
|
<SegmentedControl type="radio" label={t('fileManagement.viewMode') || 'File type'}
|
|
1147
|
-
value={viewMode} onValueChange={setViewMode} size="
|
|
1147
|
+
value={viewMode} onValueChange={setViewMode} size="sm">
|
|
1148
1148
|
{(['all', 'photos', 'videos', 'documents', 'audio'] as const).map(mode => (
|
|
1149
1149
|
<SegmentedControlItem key={mode} value={mode} accessibilityLabel={mode}>
|
|
1150
1150
|
<MaterialCommunityIcons
|
|
@@ -1154,7 +1154,7 @@ const FileManagementScreen: React.FC<FileManagementScreenProps> = ({
|
|
|
1154
1154
|
))}
|
|
1155
1155
|
</SegmentedControl>
|
|
1156
1156
|
</ScrollView>
|
|
1157
|
-
<Button appearance="subtle" tone="neutral" size="
|
|
1157
|
+
<Button appearance="subtle" tone="neutral" size="sm"
|
|
1158
1158
|
accessibilityRole="button"
|
|
1159
1159
|
accessibilityLabel={t('fileManagement.a11y.sortBy', {
|
|
1160
1160
|
field: sortBy,
|
|
@@ -109,7 +109,7 @@ const HistoryViewScreen: React.FC<BaseScreenProps> = ({ onClose, goBack }) => {
|
|
|
109
109
|
/>
|
|
110
110
|
</SettingsListGroup>
|
|
111
111
|
<SettingsListGroup title={t('history.recent') || 'Recent History'}>
|
|
112
|
-
{isLoading ? <Loading size="
|
|
112
|
+
{isLoading ? <Loading size="lg" color={bloomTheme.colors.text} text={t('history.loading') || 'Loading history...'} />
|
|
113
113
|
: history.length === 0 ? <Text className="text-text-secondary text-center p-space-40">{t('history.empty') || 'No history yet'}</Text>
|
|
114
114
|
: history.map(item => (
|
|
115
115
|
<SettingsListItem
|