@oxy.so/services 4.0.6 → 6.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/README.md +1 -1
- package/lib/commonjs/assets/assets/signIn/slide-1.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/lib/commonjs/assets/assets/signIn/slide-2.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/lib/commonjs/assets/assets/signIn/slide-3.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/lib/commonjs/assets/assets/signIn/slide-4.jpg +0 -0
- package/lib/commonjs/assets/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/lib/commonjs/assets/signIn/slide-1.jpg +0 -0
- package/lib/commonjs/assets/signIn/slide-2.jpg +0 -0
- package/lib/commonjs/assets/signIn/slide-3.jpg +0 -0
- package/lib/commonjs/assets/signIn/slide-4.jpg +0 -0
- package/lib/commonjs/index.js +45 -8
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/ui/components/FollowButton.js +26 -1
- package/lib/commonjs/ui/components/FollowButton.js.map +1 -1
- package/lib/commonjs/ui/components/FollowTargetButton.js +6 -1
- package/lib/commonjs/ui/components/FollowTargetButton.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js +11 -58
- package/lib/commonjs/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/commonjs/ui/components/OxyAuthChooser.js +36 -44
- package/lib/commonjs/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/commonjs/ui/components/OxyProvider.js +0 -2
- package/lib/commonjs/ui/components/OxyProvider.js.map +1 -1
- package/lib/commonjs/ui/components/ProfileButton.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js +29 -8
- package/lib/commonjs/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/primitives.js +7 -52
- package/lib/commonjs/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/signInFailureMessage.js +1 -7
- package/lib/commonjs/ui/components/authChooser/signInFailureMessage.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/styles.js +0 -31
- package/lib/commonjs/ui/components/authChooser/styles.js.map +1 -1
- package/lib/commonjs/ui/components/authChooser/types.js +2 -2
- package/lib/commonjs/ui/components/followButtonAccessibility.js +72 -0
- package/lib/commonjs/ui/components/followButtonAccessibility.js.map +1 -0
- package/lib/commonjs/ui/components/oauthNavigation.js +1 -1
- package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js +161 -0
- package/lib/commonjs/ui/components/signIn/InlineCommonsQr.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js +111 -0
- package/lib/commonjs/ui/components/signIn/OxyAccountPicker.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js +160 -0
- package/lib/commonjs/ui/components/signIn/OxyAuthScreen.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxySignInPanel.js +371 -0
- package/lib/commonjs/ui/components/signIn/OxySignInPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js +78 -0
- package/lib/commonjs/ui/components/signIn/OxySignUpPanel.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/artwork.js +21 -0
- package/lib/commonjs/ui/components/signIn/artwork.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/passkeyError.js +46 -0
- package/lib/commonjs/ui/components/signIn/passkeyError.js.map +1 -0
- package/lib/commonjs/ui/components/signIn/signInMethods.js +46 -0
- package/lib/commonjs/ui/components/signIn/signInMethods.js.map +1 -0
- package/lib/commonjs/ui/context/OxyContext.js +16 -16
- package/lib/commonjs/ui/context/OxyContext.js.map +1 -1
- package/lib/commonjs/ui/context/commitSessionFlow.js +0 -43
- package/lib/commonjs/ui/context/commitSessionFlow.js.map +1 -1
- package/lib/commonjs/ui/hooks/accountDialogSnapshot.js +15 -1
- package/lib/commonjs/ui/hooks/accountDialogSnapshot.js.map +1 -1
- package/lib/commonjs/ui/hooks/useDeviceSwitcher.js +1 -3
- package/lib/commonjs/ui/hooks/useDeviceSwitcher.js.map +1 -1
- package/lib/commonjs/ui/oauth/browserAuthTransport.js +11 -4
- package/lib/commonjs/ui/oauth/browserAuthTransport.js.map +1 -1
- package/lib/commonjs/ui/oauth/oauthHandshake.js +3 -0
- package/lib/commonjs/ui/oauth/oauthHandshake.js.map +1 -1
- package/lib/commonjs/ui/oauth/oauthPopup.js +2 -3
- package/lib/commonjs/ui/oauth/oauthPopup.js.map +1 -1
- package/lib/commonjs/ui/screens/ManageAccountScreen.js +2 -3
- package/lib/commonjs/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
- package/lib/commonjs/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/commonjs/ui/session/authStore.js +0 -21
- package/lib/commonjs/ui/session/authStore.js.map +1 -1
- package/lib/commonjs/ui/utils/accountDeletionHandoff.js +1 -1
- package/lib/commonjs/ui/utils/accountDeletionHandoff.js.map +1 -1
- package/lib/module/assets/assets/signIn/slide-1.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/lib/module/assets/assets/signIn/slide-2.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/lib/module/assets/assets/signIn/slide-3.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/lib/module/assets/assets/signIn/slide-4.jpg +0 -0
- package/lib/module/assets/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/lib/module/assets/signIn/slide-1.jpg +0 -0
- package/lib/module/assets/signIn/slide-2.jpg +0 -0
- package/lib/module/assets/signIn/slide-3.jpg +0 -0
- package/lib/module/assets/signIn/slide-4.jpg +0 -0
- package/lib/module/index.js +7 -6
- package/lib/module/index.js.map +1 -1
- package/lib/module/ui/components/FollowButton.js +26 -1
- package/lib/module/ui/components/FollowButton.js.map +1 -1
- package/lib/module/ui/components/FollowTargetButton.js +6 -1
- package/lib/module/ui/components/FollowTargetButton.js.map +1 -1
- package/lib/module/ui/components/OxyAccountDialogScreen.js +14 -59
- package/lib/module/ui/components/OxyAccountDialogScreen.js.map +1 -1
- package/lib/module/ui/components/OxyAuthChooser.js +37 -45
- package/lib/module/ui/components/OxyAuthChooser.js.map +1 -1
- package/lib/module/ui/components/OxyProvider.js +0 -2
- package/lib/module/ui/components/OxyProvider.js.map +1 -1
- package/lib/module/ui/components/ProfileButton.js.map +1 -1
- package/lib/module/ui/components/authChooser/AccountsMenuView.js +21 -2
- package/lib/module/ui/components/authChooser/AccountsMenuView.js.map +1 -1
- package/lib/module/ui/components/authChooser/primitives.js +1 -44
- package/lib/module/ui/components/authChooser/primitives.js.map +1 -1
- package/lib/module/ui/components/authChooser/signInFailureMessage.js +1 -7
- package/lib/module/ui/components/authChooser/signInFailureMessage.js.map +1 -1
- package/lib/module/ui/components/authChooser/styles.js +0 -31
- package/lib/module/ui/components/authChooser/styles.js.map +1 -1
- package/lib/module/ui/components/authChooser/types.js +2 -2
- package/lib/module/ui/components/followButtonAccessibility.js +66 -0
- package/lib/module/ui/components/followButtonAccessibility.js.map +1 -0
- package/lib/module/ui/components/oauthNavigation.js +1 -1
- package/lib/module/ui/components/signIn/InlineCommonsQr.js +157 -0
- package/lib/module/ui/components/signIn/InlineCommonsQr.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyAccountPicker.js +106 -0
- package/lib/module/ui/components/signIn/OxyAccountPicker.js.map +1 -0
- package/lib/module/ui/components/signIn/OxyAuthScreen.js +151 -0
- package/lib/module/ui/components/signIn/OxyAuthScreen.js.map +1 -0
- package/lib/module/ui/components/signIn/OxySignInPanel.js +366 -0
- package/lib/module/ui/components/signIn/OxySignInPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/OxySignUpPanel.js +75 -0
- package/lib/module/ui/components/signIn/OxySignUpPanel.js.map +1 -0
- package/lib/module/ui/components/signIn/artwork.js +16 -0
- package/lib/module/ui/components/signIn/artwork.js.map +1 -0
- package/lib/module/ui/components/signIn/passkeyError.js +40 -0
- package/lib/module/ui/components/signIn/passkeyError.js.map +1 -0
- package/lib/module/ui/components/signIn/signInMethods.js +42 -0
- package/lib/module/ui/components/signIn/signInMethods.js.map +1 -0
- package/lib/module/ui/context/OxyContext.js +17 -17
- package/lib/module/ui/context/OxyContext.js.map +1 -1
- package/lib/module/ui/context/commitSessionFlow.js +0 -42
- package/lib/module/ui/context/commitSessionFlow.js.map +1 -1
- package/lib/module/ui/hooks/accountDialogSnapshot.js +14 -1
- package/lib/module/ui/hooks/accountDialogSnapshot.js.map +1 -1
- package/lib/module/ui/hooks/useDeviceSwitcher.js +3 -5
- package/lib/module/ui/hooks/useDeviceSwitcher.js.map +1 -1
- package/lib/module/ui/oauth/browserAuthTransport.js +11 -4
- package/lib/module/ui/oauth/browserAuthTransport.js.map +1 -1
- package/lib/module/ui/oauth/oauthHandshake.js +3 -0
- package/lib/module/ui/oauth/oauthHandshake.js.map +1 -1
- package/lib/module/ui/oauth/oauthPopup.js +2 -3
- package/lib/module/ui/oauth/oauthPopup.js.map +1 -1
- package/lib/module/ui/screens/ManageAccountScreen.js +3 -4
- package/lib/module/ui/screens/ManageAccountScreen.js.map +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js +1 -1
- package/lib/module/ui/screens/trust/TrustLeaderboardScreen.js.map +1 -1
- package/lib/module/ui/session/authStore.js +1 -22
- package/lib/module/ui/session/authStore.js.map +1 -1
- package/lib/module/ui/utils/accountDeletionHandoff.js +2 -2
- package/lib/module/ui/utils/accountDeletionHandoff.js.map +1 -1
- package/lib/typescript/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/lib/typescript/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/lib/typescript/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/lib/typescript/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/lib/typescript/commonjs/index.d.ts +8 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts +6 -0
- package/lib/typescript/commonjs/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/FollowTargetButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts +5 -12
- package/lib/typescript/commonjs/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts +0 -19
- package/lib/typescript/commonjs/ui/components/authChooser/primitives.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/signInFailureMessage.d.ts +1 -5
- package/lib/typescript/commonjs/ui/components/authChooser/signInFailureMessage.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts +0 -31
- package/lib/typescript/commonjs/ui/components/authChooser/styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/components/authChooser/types.d.ts +3 -3
- package/lib/typescript/commonjs/ui/components/followButtonAccessibility.d.ts +48 -0
- package/lib/typescript/commonjs/ui/components/followButtonAccessibility.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/oauthNavigation.d.ts +1 -1
- package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts +20 -0
- package/lib/typescript/commonjs/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts +34 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts +43 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts +43 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignInPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts +17 -0
- package/lib/typescript/commonjs/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/artwork.d.ts +8 -0
- package/lib/typescript/commonjs/ui/components/signIn/artwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/passkeyError.d.ts +16 -0
- package/lib/typescript/commonjs/ui/components/signIn/passkeyError.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/signIn/signInMethods.d.ts +39 -0
- package/lib/typescript/commonjs/ui/components/signIn/signInMethods.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts +0 -40
- package/lib/typescript/commonjs/ui/context/commitSessionFlow.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +8 -9
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts +7 -1
- package/lib/typescript/commonjs/ui/hooks/accountDialogSnapshot.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/useDeviceSwitcher.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts +9 -0
- package/lib/typescript/commonjs/ui/oauth/browserAuthTransport.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts +3 -0
- package/lib/typescript/commonjs/ui/oauth/oauthHandshake.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts +2 -3
- package/lib/typescript/commonjs/ui/oauth/oauthPopup.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/session/authStore.d.ts +0 -30
- package/lib/typescript/commonjs/ui/session/authStore.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/types/navigation.d.ts +0 -26
- package/lib/typescript/commonjs/ui/types/navigation.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +8 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FollowButton.d.ts +6 -0
- package/lib/typescript/module/ui/components/FollowButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/FollowTargetButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAccountDialogScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts +5 -12
- package/lib/typescript/module/ui/components/OxyAuthChooser.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/OxyProvider.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts +1 -1
- package/lib/typescript/module/ui/components/ProfileButton.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/AccountsMenuView.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/primitives.d.ts +0 -19
- package/lib/typescript/module/ui/components/authChooser/primitives.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/signInFailureMessage.d.ts +1 -5
- package/lib/typescript/module/ui/components/authChooser/signInFailureMessage.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/styles.d.ts +0 -31
- package/lib/typescript/module/ui/components/authChooser/styles.d.ts.map +1 -1
- package/lib/typescript/module/ui/components/authChooser/types.d.ts +3 -3
- package/lib/typescript/module/ui/components/followButtonAccessibility.d.ts +48 -0
- package/lib/typescript/module/ui/components/followButtonAccessibility.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/oauthNavigation.d.ts +1 -1
- package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts +20 -0
- package/lib/typescript/module/ui/components/signIn/InlineCommonsQr.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts +34 -0
- package/lib/typescript/module/ui/components/signIn/OxyAccountPicker.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts +43 -0
- package/lib/typescript/module/ui/components/signIn/OxyAuthScreen.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts +43 -0
- package/lib/typescript/module/ui/components/signIn/OxySignInPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts +17 -0
- package/lib/typescript/module/ui/components/signIn/OxySignUpPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/artwork.d.ts +8 -0
- package/lib/typescript/module/ui/components/signIn/artwork.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/passkeyError.d.ts +16 -0
- package/lib/typescript/module/ui/components/signIn/passkeyError.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/signIn/signInMethods.d.ts +39 -0
- package/lib/typescript/module/ui/components/signIn/signInMethods.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/OxyContext.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/commitSessionFlow.d.ts +0 -40
- package/lib/typescript/module/ui/context/commitSessionFlow.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +8 -9
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts +7 -1
- package/lib/typescript/module/ui/hooks/accountDialogSnapshot.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/useDeviceSwitcher.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts +9 -0
- package/lib/typescript/module/ui/oauth/browserAuthTransport.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts +3 -0
- package/lib/typescript/module/ui/oauth/oauthHandshake.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/oauthPopup.d.ts +2 -3
- package/lib/typescript/module/ui/oauth/oauthPopup.d.ts.map +1 -1
- package/lib/typescript/module/ui/screens/ManageAccountScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/session/authStore.d.ts +0 -30
- package/lib/typescript/module/ui/session/authStore.d.ts.map +1 -1
- package/lib/typescript/module/ui/types/navigation.d.ts +0 -26
- package/lib/typescript/module/ui/types/navigation.d.ts.map +1 -1
- package/package.json +6 -9
- package/src/assets/signIn/slide-1.jpg +0 -0
- package/src/assets/signIn/slide-1.jpg.d.ts +3 -0
- package/src/assets/signIn/slide-2.jpg +0 -0
- package/src/assets/signIn/slide-2.jpg.d.ts +3 -0
- package/src/assets/signIn/slide-3.jpg +0 -0
- package/src/assets/signIn/slide-3.jpg.d.ts +3 -0
- package/src/assets/signIn/slide-4.jpg +0 -0
- package/src/assets/signIn/slide-4.jpg.d.ts +3 -0
- package/src/index.ts +16 -7
- package/src/ui/components/FollowButton.tsx +25 -0
- package/src/ui/components/FollowTargetButton.tsx +4 -0
- package/src/ui/components/OxyAccountDialogScreen.tsx +11 -72
- package/src/ui/components/OxyAuthChooser.tsx +37 -53
- package/src/ui/components/OxyProvider.tsx +0 -2
- package/src/ui/components/ProfileButton.tsx +1 -4
- package/src/ui/components/__tests__/followButtonAccessibility.test.tsx +191 -0
- package/src/ui/components/authChooser/AccountsMenuView.tsx +28 -1
- package/src/ui/components/authChooser/primitives.tsx +1 -39
- package/src/ui/components/authChooser/signInFailureMessage.ts +1 -7
- package/src/ui/components/authChooser/styles.ts +0 -31
- package/src/ui/components/authChooser/types.ts +3 -3
- package/src/ui/components/followButtonAccessibility.ts +83 -0
- package/src/ui/components/oauthNavigation.ts +1 -1
- package/src/ui/components/signIn/InlineCommonsQr.tsx +135 -0
- package/src/ui/components/signIn/OxyAccountPicker.tsx +129 -0
- package/src/ui/components/signIn/OxyAuthScreen.tsx +123 -0
- package/src/ui/components/signIn/OxySignInPanel.tsx +392 -0
- package/src/ui/components/signIn/OxySignUpPanel.tsx +86 -0
- package/src/ui/components/signIn/artwork.ts +13 -0
- package/src/ui/components/signIn/passkeyError.ts +44 -0
- package/src/ui/components/signIn/signInMethods.ts +51 -0
- package/src/ui/context/OxyContext.tsx +21 -18
- package/src/ui/context/__tests__/commitSessionFlow.test.ts +0 -89
- package/src/ui/context/commitSessionFlow.ts +0 -61
- package/src/ui/context/oxyContextTypes.ts +9 -9
- package/src/ui/hooks/accountDialogSnapshot.ts +20 -1
- package/src/ui/hooks/useDeviceSwitcher.ts +3 -11
- package/src/ui/oauth/__tests__/browserAuthTransport.test.ts +21 -0
- package/src/ui/oauth/browserAuthTransport.ts +14 -4
- package/src/ui/oauth/oauthHandshake.ts +4 -1
- package/src/ui/oauth/oauthPopup.ts +2 -3
- package/src/ui/screens/ManageAccountScreen.tsx +3 -4
- package/src/ui/screens/trust/TrustLeaderboardScreen.tsx +1 -1
- package/src/ui/session/authStore.ts +0 -37
- package/src/ui/types/navigation.ts +0 -26
- package/src/ui/utils/accountDeletionHandoff.ts +2 -2
- package/lib/commonjs/ui/components/authChooser/SignInEntryView.js +0 -132
- package/lib/commonjs/ui/components/authChooser/SignInEntryView.js.map +0 -1
- package/lib/commonjs/ui/components/authChooser/SignUpView.js +0 -77
- package/lib/commonjs/ui/components/authChooser/SignUpView.js.map +0 -1
- package/lib/commonjs/ui/components/passkeyHubPopup.js +0 -33
- package/lib/commonjs/ui/components/passkeyHubPopup.js.map +0 -1
- package/lib/commonjs/ui/oauth/legacyRedirectLanes.js +0 -48
- package/lib/commonjs/ui/oauth/legacyRedirectLanes.js.map +0 -1
- package/lib/module/ui/components/authChooser/SignInEntryView.js +0 -127
- package/lib/module/ui/components/authChooser/SignInEntryView.js.map +0 -1
- package/lib/module/ui/components/authChooser/SignUpView.js +0 -73
- package/lib/module/ui/components/authChooser/SignUpView.js.map +0 -1
- package/lib/module/ui/components/passkeyHubPopup.js +0 -29
- package/lib/module/ui/components/passkeyHubPopup.js.map +0 -1
- package/lib/module/ui/oauth/legacyRedirectLanes.js +0 -44
- package/lib/module/ui/oauth/legacyRedirectLanes.js.map +0 -1
- package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts +0 -39
- package/lib/typescript/commonjs/ui/components/authChooser/SignInEntryView.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts +0 -31
- package/lib/typescript/commonjs/ui/components/authChooser/SignUpView.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts +0 -23
- package/lib/typescript/commonjs/ui/components/passkeyHubPopup.d.ts.map +0 -1
- package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts +0 -40
- package/lib/typescript/commonjs/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts +0 -39
- package/lib/typescript/module/ui/components/authChooser/SignInEntryView.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts +0 -31
- package/lib/typescript/module/ui/components/authChooser/SignUpView.d.ts.map +0 -1
- package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts +0 -23
- package/lib/typescript/module/ui/components/passkeyHubPopup.d.ts.map +0 -1
- package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts +0 -40
- package/lib/typescript/module/ui/oauth/legacyRedirectLanes.d.ts.map +0 -1
- package/src/ui/components/authChooser/SignInEntryView.tsx +0 -157
- package/src/ui/components/authChooser/SignUpView.tsx +0 -76
- package/src/ui/components/passkeyHubPopup.ts +0 -28
- package/src/ui/oauth/legacyRedirectLanes.ts +0 -43
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import { useCallback, useEffect, useMemo } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
type StyleProp,
|
|
5
|
-
type ViewStyle,
|
|
6
|
-
} from 'react-native';
|
|
3
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
7
4
|
import { View } from 'react-native-css/components';
|
|
8
5
|
import { RiLoginBoxLine } from '@oxy.so/bloom/icons/RiLoginBoxLine';
|
|
9
6
|
import { RiMoreLine } from '@oxy.so/bloom/icons/RiMoreLine';
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The follow button's accessible name follows its state (OxyHQ/oxy#1375 item
|
|
3
|
+
* 22). On @nate's profile the button showed "Following" while TalkBack read
|
|
4
|
+
* "Follow": Bloom names the button by its idle label and leaves the state to
|
|
5
|
+
* the pressed flag, which TalkBack reads as "selected".
|
|
6
|
+
*
|
|
7
|
+
* The table pins what each state says; the render tests pin that both
|
|
8
|
+
* FollowButton modes and FollowTargetButton hand it to Bloom.
|
|
9
|
+
*/
|
|
10
|
+
import React from 'react';
|
|
11
|
+
import { render } from '@testing-library/react';
|
|
12
|
+
import {
|
|
13
|
+
describeFollowAllButton,
|
|
14
|
+
describeFollowButton,
|
|
15
|
+
formatHandle,
|
|
16
|
+
} from '../followButtonAccessibility';
|
|
17
|
+
|
|
18
|
+
interface BloomFollowProps {
|
|
19
|
+
following: boolean;
|
|
20
|
+
label?: string;
|
|
21
|
+
followingLabel?: string;
|
|
22
|
+
loading?: boolean;
|
|
23
|
+
accessibilityLabel?: string;
|
|
24
|
+
accessibilityHint?: string;
|
|
25
|
+
}
|
|
26
|
+
const mockBloomProps: BloomFollowProps[] = [];
|
|
27
|
+
const lastBloomProps = () => mockBloomProps[mockBloomProps.length - 1];
|
|
28
|
+
|
|
29
|
+
jest.mock('@oxy.so/bloom/media-header', () => ({
|
|
30
|
+
FollowButton: (props: BloomFollowProps) => {
|
|
31
|
+
mockBloomProps.push(props);
|
|
32
|
+
return null;
|
|
33
|
+
},
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
let mockFollowState = { isFollowing: false, isKnown: true, isLoading: false };
|
|
37
|
+
let mockMulti = { allFollowing: false, isAnyLoading: false };
|
|
38
|
+
jest.mock('../../hooks/useFollow', () => ({
|
|
39
|
+
useFollowForButton: () => ({
|
|
40
|
+
...mockFollowState,
|
|
41
|
+
toggleFollow: jest.fn(),
|
|
42
|
+
resolveStatus: jest.fn(),
|
|
43
|
+
}),
|
|
44
|
+
useFollow: () => ({
|
|
45
|
+
...mockMulti,
|
|
46
|
+
followAllUsers: jest.fn(),
|
|
47
|
+
unfollowAllUsers: jest.fn(),
|
|
48
|
+
fetchAllStatuses: jest.fn(),
|
|
49
|
+
}),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
jest.mock('../../context/OxyContext', () => ({
|
|
53
|
+
useOxy: () => ({ oxyServices: {}, canUsePrivateApi: true, user: { id: 'viewer' } }),
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
let mockTarget = {
|
|
57
|
+
status: { globalState: 'not_following', applicationMode: 'inherit', relationshipId: null },
|
|
58
|
+
isFollowing: false,
|
|
59
|
+
isUnknown: false,
|
|
60
|
+
isPending: false,
|
|
61
|
+
};
|
|
62
|
+
jest.mock('../../hooks/useFollowTarget', () => ({
|
|
63
|
+
useFollowTarget: () => ({
|
|
64
|
+
...mockTarget,
|
|
65
|
+
follow: jest.fn(),
|
|
66
|
+
unfollow: jest.fn(),
|
|
67
|
+
disableHere: jest.fn(),
|
|
68
|
+
enableHere: jest.fn(),
|
|
69
|
+
}),
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
import { FollowButton } from '../FollowButton';
|
|
73
|
+
import { FollowTargetButton } from '../FollowTargetButton';
|
|
74
|
+
|
|
75
|
+
describe('describeFollowButton', () => {
|
|
76
|
+
const known = { isKnown: true, isPending: false, username: 'nate' };
|
|
77
|
+
|
|
78
|
+
it.each([
|
|
79
|
+
[{ ...known, isFollowing: true }, 'Following @nate', 'Unfollows @nate'],
|
|
80
|
+
[{ ...known, isFollowing: false }, 'Follow @nate', undefined],
|
|
81
|
+
[{ ...known, isFollowing: true, isPending: true }, 'Following @nate', undefined],
|
|
82
|
+
[{ ...known, isFollowing: false, isPending: true }, 'Follow @nate', undefined],
|
|
83
|
+
[{ ...known, isKnown: false, isFollowing: false }, 'Checking whether you follow @nate', undefined],
|
|
84
|
+
[{ ...known, username: undefined, isFollowing: true }, 'Following', 'Unfollows this account'],
|
|
85
|
+
[{ ...known, username: undefined, isFollowing: false }, 'Follow', undefined],
|
|
86
|
+
[{ ...known, username: undefined, isKnown: false, isFollowing: false }, 'Checking follow status', undefined],
|
|
87
|
+
])('%o reads "%s"', (input, label, hint) => {
|
|
88
|
+
expect(describeFollowButton(input)).toEqual(
|
|
89
|
+
hint ? { accessibilityLabel: label, accessibilityHint: hint } : { accessibilityLabel: label },
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('accepts a handle with or without the @', () => {
|
|
94
|
+
expect(formatHandle('@nate')).toBe('@nate');
|
|
95
|
+
expect(formatHandle(' nate ')).toBe('@nate');
|
|
96
|
+
expect(formatHandle('')).toBeUndefined();
|
|
97
|
+
expect(formatHandle(undefined)).toBeUndefined();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('describeFollowAllButton', () => {
|
|
102
|
+
const labels = { followAllLabel: 'Follow all', followedAllLabel: 'Following' };
|
|
103
|
+
|
|
104
|
+
it('names the state and counts the accounts in the hint', () => {
|
|
105
|
+
expect(describeFollowAllButton({ ...labels, allFollowing: false, isPending: false, count: 3 })).toEqual({
|
|
106
|
+
accessibilityLabel: 'Follow all',
|
|
107
|
+
accessibilityHint: 'Follows all 3 accounts',
|
|
108
|
+
});
|
|
109
|
+
expect(describeFollowAllButton({ ...labels, allFollowing: true, isPending: false, count: 1 })).toEqual({
|
|
110
|
+
accessibilityLabel: 'Following',
|
|
111
|
+
accessibilityHint: 'Unfollows all 1 account',
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('drops the hint while the bulk write is in flight', () => {
|
|
116
|
+
expect(describeFollowAllButton({ ...labels, allFollowing: true, isPending: true, count: 3 })).toEqual({
|
|
117
|
+
accessibilityLabel: 'Following',
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('FollowButton hands Bloom a name that follows the state', () => {
|
|
123
|
+
beforeEach(() => {
|
|
124
|
+
mockBloomProps.length = 0;
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('reads "Following @nate" while it shows Following', () => {
|
|
128
|
+
mockFollowState = { isFollowing: true, isKnown: true, isLoading: false };
|
|
129
|
+
render(<FollowButton userId="nate-id" username="nate" />);
|
|
130
|
+
expect(lastBloomProps()).toMatchObject({
|
|
131
|
+
following: true,
|
|
132
|
+
accessibilityLabel: 'Following @nate',
|
|
133
|
+
accessibilityHint: 'Unfollows @nate',
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('reads "Follow @nate" while it shows Follow', () => {
|
|
138
|
+
mockFollowState = { isFollowing: false, isKnown: true, isLoading: false };
|
|
139
|
+
render(<FollowButton userId="nate-id" username="nate" />);
|
|
140
|
+
expect(lastBloomProps()).toMatchObject({ following: false, accessibilityLabel: 'Follow @nate' });
|
|
141
|
+
expect(lastBloomProps()?.accessibilityHint).toBeUndefined();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('keeps the shown state while a write is pending', () => {
|
|
145
|
+
mockFollowState = { isFollowing: true, isKnown: true, isLoading: true };
|
|
146
|
+
render(<FollowButton userId="nate-id" username="nate" />);
|
|
147
|
+
expect(lastBloomProps()).toMatchObject({ loading: true, accessibilityLabel: 'Following @nate' });
|
|
148
|
+
expect(lastBloomProps()?.accessibilityHint).toBeUndefined();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('says it is checking while the status is unknown', () => {
|
|
152
|
+
mockFollowState = { isFollowing: false, isKnown: false, isLoading: false };
|
|
153
|
+
render(<FollowButton userId="nate-id" username="nate" />);
|
|
154
|
+
expect(lastBloomProps()).toMatchObject({
|
|
155
|
+
loading: true,
|
|
156
|
+
accessibilityLabel: 'Checking whether you follow @nate',
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('names the "Follow all" button by its state too', () => {
|
|
161
|
+
mockMulti = { allFollowing: true, isAnyLoading: false };
|
|
162
|
+
render(<FollowButton userIds={['a', 'b']} />);
|
|
163
|
+
expect(lastBloomProps()).toMatchObject({
|
|
164
|
+
following: true,
|
|
165
|
+
accessibilityLabel: 'Following',
|
|
166
|
+
accessibilityHint: 'Unfollows all 2 accounts',
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe('FollowTargetButton names the state it shows', () => {
|
|
172
|
+
beforeEach(() => {
|
|
173
|
+
mockBloomProps.length = 0;
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it.each([
|
|
177
|
+
['following', { globalState: 'following', applicationMode: 'inherit' }, true, 'Following'],
|
|
178
|
+
['requested', { globalState: 'requested', applicationMode: 'inherit' }, true, 'Requested'],
|
|
179
|
+
['off here', { globalState: 'following', applicationMode: 'disabled' }, true, 'Off here'],
|
|
180
|
+
['not following', { globalState: 'not_following', applicationMode: 'inherit' }, false, 'Follow'],
|
|
181
|
+
])('%s', (_name, status, isFollowing, label) => {
|
|
182
|
+
mockTarget = {
|
|
183
|
+
status: { ...status, relationshipId: null },
|
|
184
|
+
isFollowing,
|
|
185
|
+
isUnknown: false,
|
|
186
|
+
isPending: false,
|
|
187
|
+
};
|
|
188
|
+
render(<FollowTargetButton targetId="t1" showOptions={false} />);
|
|
189
|
+
expect(lastBloomProps()?.accessibilityLabel).toBe(label);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
@@ -51,7 +51,6 @@ import {
|
|
|
51
51
|
type SwitcherPrincipalRow,
|
|
52
52
|
} from '@oxy.so/core';
|
|
53
53
|
import AvatarCameraBadge from '../AvatarCameraBadge';
|
|
54
|
-
import { HoverPressable } from './primitives';
|
|
55
54
|
import { authChooserStyles as styles } from './styles';
|
|
56
55
|
import {
|
|
57
56
|
resolveAccentHex,
|
|
@@ -63,6 +62,34 @@ import {
|
|
|
63
62
|
type Translate,
|
|
64
63
|
} from './types';
|
|
65
64
|
|
|
65
|
+
type HoverPressableProps = Omit<React.ComponentProps<typeof Pressable>, 'className'> & {
|
|
66
|
+
baseClassName: string;
|
|
67
|
+
hoverClassName: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* A `Pressable` that appends a hover-tint NativeWind token while pointer-hovered.
|
|
72
|
+
* The Metro web pipeline here does NOT emit NativeWind `hover:` variants, so hover
|
|
73
|
+
* is driven by RN's cross-platform `onHoverIn`/`onHoverOut` (they fire only on web
|
|
74
|
+
* via react-native-web; a no-op on native) toggling a plain background token —
|
|
75
|
+
* the tint stays a NativeWind class, only the trigger is JS.
|
|
76
|
+
*/
|
|
77
|
+
const HoverPressable: React.FC<HoverPressableProps> = ({
|
|
78
|
+
baseClassName,
|
|
79
|
+
hoverClassName,
|
|
80
|
+
...rest
|
|
81
|
+
}) => {
|
|
82
|
+
const [hovered, setHovered] = useState(false);
|
|
83
|
+
return (
|
|
84
|
+
<Pressable
|
|
85
|
+
{...rest}
|
|
86
|
+
className={hovered ? `${baseClassName} ${hoverClassName}` : baseClassName}
|
|
87
|
+
onHoverIn={() => setHovered(true)}
|
|
88
|
+
onHoverOut={() => setHovered(false)}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
66
93
|
/**
|
|
67
94
|
* Leading glyph for the rows that live in a Bloom grouped section (the MENU
|
|
68
95
|
* block) and for the storage card's cloud, which lines its title up with them.
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type React from 'react';
|
|
8
|
-
import {
|
|
9
|
-
import { Pressable, View } from 'react-native-css/components';
|
|
8
|
+
import { Pressable, View } from 'react-native';
|
|
10
9
|
import MaterialCommunityIcons from '../../icons/MaterialCommunityIcons';
|
|
11
10
|
import { Avatar } from '@oxy.so/bloom/avatar';
|
|
12
11
|
import { BloomColorScope } from '@oxy.so/bloom/theme';
|
|
@@ -18,34 +17,6 @@ import { resolveAccentHex, toPreset, type Theme } from './types';
|
|
|
18
17
|
/** Diameter of a row avatar (the sign-in view's account rows). */
|
|
19
18
|
const ROW_AVATAR_SIZE = 40;
|
|
20
19
|
|
|
21
|
-
type HoverPressableProps = Omit<React.ComponentProps<typeof Pressable>, 'className'> & {
|
|
22
|
-
baseClassName: string;
|
|
23
|
-
hoverClassName: string;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* A `Pressable` that appends a hover-tint NativeWind token while pointer-hovered.
|
|
28
|
-
* The Metro web pipeline here does NOT emit NativeWind `hover:` variants, so hover
|
|
29
|
-
* is driven by RN's cross-platform `onHoverIn`/`onHoverOut` (they fire only on web
|
|
30
|
-
* via react-native-web; a no-op on native) toggling a plain background token —
|
|
31
|
-
* the tint stays a NativeWind class, only the trigger is JS.
|
|
32
|
-
*/
|
|
33
|
-
export const HoverPressable: React.FC<HoverPressableProps> = ({
|
|
34
|
-
baseClassName,
|
|
35
|
-
hoverClassName,
|
|
36
|
-
...rest
|
|
37
|
-
}) => {
|
|
38
|
-
const [hovered, setHovered] = useState(false);
|
|
39
|
-
return (
|
|
40
|
-
<Pressable
|
|
41
|
-
{...rest}
|
|
42
|
-
className={hovered ? `${baseClassName} ${hoverClassName}` : baseClassName}
|
|
43
|
-
onHoverIn={() => setHovered(true)}
|
|
44
|
-
onHoverOut={() => setHovered(false)}
|
|
45
|
-
/>
|
|
46
|
-
);
|
|
47
|
-
};
|
|
48
|
-
|
|
49
20
|
/**
|
|
50
21
|
* A SUBORDINATE action: a small centred text link, never a button.
|
|
51
22
|
*
|
|
@@ -73,15 +44,6 @@ export const SubtleLink: React.FC<{
|
|
|
73
44
|
</Pressable>
|
|
74
45
|
);
|
|
75
46
|
|
|
76
|
-
/** A labelled hairline separating two blocks ("or"). */
|
|
77
|
-
export const Dividerish: React.FC<{ theme: Theme; label: string }> = ({ theme, label }) => (
|
|
78
|
-
<View style={styles.dividerRow}>
|
|
79
|
-
<View style={[styles.dividerLine, { backgroundColor: theme.colors.border }]} />
|
|
80
|
-
<Text style={[styles.dividerText, { color: theme.colors.textSecondary }]}>{label}</Text>
|
|
81
|
-
<View style={[styles.dividerLine, { backgroundColor: theme.colors.border }]} />
|
|
82
|
-
</View>
|
|
83
|
-
);
|
|
84
|
-
|
|
85
47
|
/**
|
|
86
48
|
* A `principal acting as account` row on the sign-in entry — "continue as one of
|
|
87
49
|
* these" rather than a choice of authentication METHOD, which is why it stays
|
|
@@ -9,18 +9,12 @@
|
|
|
9
9
|
import type { SignInFailureReason } from '@oxy.so/core';
|
|
10
10
|
import type { Translate } from './types';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* The toast for `failure`, or `null` when there is nothing to report: a
|
|
14
|
-
* `'cancelled'` attempt is the user's own choice (they closed the window), and
|
|
15
|
-
* the surface already offers "Try again" without scolding them for it.
|
|
16
|
-
*/
|
|
12
|
+
/** The toast for `failure`, or `null` when there is nothing to report. */
|
|
17
13
|
export function signInFailureMessage(
|
|
18
14
|
failure: SignInFailureReason | null,
|
|
19
15
|
t: Translate,
|
|
20
16
|
): string | null {
|
|
21
17
|
switch (failure) {
|
|
22
|
-
case 'cancelled':
|
|
23
|
-
return null;
|
|
24
18
|
case 'denied':
|
|
25
19
|
return t('accountSwitcher.signInFailures.denied');
|
|
26
20
|
case 'expired':
|
|
@@ -140,42 +140,11 @@ export const authChooserStyles = StyleSheet.create({
|
|
|
140
140
|
fontSize: 14,
|
|
141
141
|
fontWeight: '600',
|
|
142
142
|
},
|
|
143
|
-
signInBlock: {
|
|
144
|
-
width: '100%',
|
|
145
|
-
},
|
|
146
143
|
primaryButton: {
|
|
147
144
|
width: '100%',
|
|
148
145
|
borderRadius: 14,
|
|
149
146
|
marginTop: 8,
|
|
150
147
|
},
|
|
151
|
-
secondaryButton: {
|
|
152
|
-
width: '100%',
|
|
153
|
-
borderRadius: 14,
|
|
154
|
-
marginTop: 10,
|
|
155
|
-
},
|
|
156
|
-
usernameInput: {
|
|
157
|
-
width: '100%',
|
|
158
|
-
borderWidth: StyleSheet.hairlineWidth,
|
|
159
|
-
borderRadius: 14,
|
|
160
|
-
paddingVertical: 12,
|
|
161
|
-
paddingHorizontal: 14,
|
|
162
|
-
fontSize: 16,
|
|
163
|
-
marginTop: 8,
|
|
164
|
-
},
|
|
165
|
-
dividerRow: {
|
|
166
|
-
flexDirection: 'row',
|
|
167
|
-
alignItems: 'center',
|
|
168
|
-
width: '100%',
|
|
169
|
-
marginVertical: 14,
|
|
170
|
-
},
|
|
171
|
-
dividerLine: {
|
|
172
|
-
flex: 1,
|
|
173
|
-
height: StyleSheet.hairlineWidth,
|
|
174
|
-
},
|
|
175
|
-
dividerText: {
|
|
176
|
-
marginHorizontal: 12,
|
|
177
|
-
fontSize: 13,
|
|
178
|
-
},
|
|
179
148
|
centeredBlock: {
|
|
180
149
|
alignItems: 'center',
|
|
181
150
|
justifyContent: 'center',
|
|
@@ -96,7 +96,7 @@ export interface AccountsMenuActions {
|
|
|
96
96
|
onTerms: () => void;
|
|
97
97
|
onSignOut: () => void;
|
|
98
98
|
/**
|
|
99
|
-
* Open the person's identity at
|
|
99
|
+
* Open the person's identity at auth.oxy.so/identity (recovery phrase,
|
|
100
100
|
* recovery, account deletion). Web only — `undefined` hides the row.
|
|
101
101
|
*/
|
|
102
102
|
onOpenIdentity?: () => void;
|
|
@@ -111,8 +111,8 @@ export interface AccountsMenuActions {
|
|
|
111
111
|
/**
|
|
112
112
|
* Where a passkey sign-in or sign-up can run from the current surface.
|
|
113
113
|
*
|
|
114
|
-
* `'hub'` = web: it runs
|
|
115
|
-
* every web origin
|
|
114
|
+
* `'hub'` = web: it runs in auth.oxy.so's window over the app
|
|
115
|
+
* (`continueOnAuth`), on every web origin.
|
|
116
116
|
* `'none'` = native, where Commons owns identity.
|
|
117
117
|
*/
|
|
118
118
|
export type PasskeyMode = 'hub' | 'none';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a screen reader hears for a follow button.
|
|
3
|
+
*
|
|
4
|
+
* Bloom's `FollowButton` names itself "Follow" in both states and carries the
|
|
5
|
+
* state in its pressed flag. Android TalkBack reads that flag as "selected",
|
|
6
|
+
* so a button that SHOWS "Following" was announced as "Follow, selected", and a
|
|
7
|
+
* TalkBack user could not tell they already follow the account
|
|
8
|
+
* (OxyHQ/oxy#1375 item 22). The name now says the state, and who it is for
|
|
9
|
+
* when the caller knows the handle.
|
|
10
|
+
*
|
|
11
|
+
* Pure, and kept apart from the components, so every state is pinned by a
|
|
12
|
+
* table test rather than by a render that can only see one state at a time.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export interface FollowButtonAccessibility {
|
|
16
|
+
accessibilityLabel: string;
|
|
17
|
+
accessibilityHint?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** `@nate` from `nate` or `@nate`; `undefined` when there is no handle. */
|
|
21
|
+
export function formatHandle(username: string | undefined): string | undefined {
|
|
22
|
+
const bare = username?.trim().replace(/^@+/, '');
|
|
23
|
+
return bare ? `@${bare}` : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The single-user button.
|
|
28
|
+
*
|
|
29
|
+
* - `isKnown: false`: the status is still being fetched and the button is
|
|
30
|
+
* inert, so it says so rather than offering a "Follow" it would ignore.
|
|
31
|
+
* - `isPending`: a follow or unfollow is in flight. The name keeps the state
|
|
32
|
+
* the button still shows; the busy flag says the rest, and there is no hint
|
|
33
|
+
* because a press does nothing until the write settles.
|
|
34
|
+
* - Following: "Following @nate", hinted "Unfollows @nate", because pressing
|
|
35
|
+
* it unfollows, which the visible "Following" does not say.
|
|
36
|
+
*/
|
|
37
|
+
export function describeFollowButton(input: {
|
|
38
|
+
isKnown: boolean;
|
|
39
|
+
isFollowing: boolean;
|
|
40
|
+
isPending: boolean;
|
|
41
|
+
username?: string;
|
|
42
|
+
}): FollowButtonAccessibility {
|
|
43
|
+
const handle = formatHandle(input.username);
|
|
44
|
+
|
|
45
|
+
if (!input.isKnown) {
|
|
46
|
+
return {
|
|
47
|
+
accessibilityLabel: handle
|
|
48
|
+
? `Checking whether you follow ${handle}`
|
|
49
|
+
: 'Checking follow status',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const accessibilityLabel = input.isFollowing
|
|
54
|
+
? handle ? `Following ${handle}` : 'Following'
|
|
55
|
+
: handle ? `Follow ${handle}` : 'Follow';
|
|
56
|
+
|
|
57
|
+
if (input.isPending || !input.isFollowing) return { accessibilityLabel };
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
accessibilityLabel,
|
|
61
|
+
accessibilityHint: handle ? `Unfollows ${handle}` : 'Unfollows this account',
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The "Follow all" button. The labels are the caller's, since a starter pack
|
|
67
|
+
* and a feed's member list word it differently; the hint carries the count.
|
|
68
|
+
*/
|
|
69
|
+
export function describeFollowAllButton(input: {
|
|
70
|
+
allFollowing: boolean;
|
|
71
|
+
isPending: boolean;
|
|
72
|
+
count: number;
|
|
73
|
+
followAllLabel: string;
|
|
74
|
+
followedAllLabel: string;
|
|
75
|
+
}): FollowButtonAccessibility {
|
|
76
|
+
const accessibilityLabel = input.allFollowing ? input.followedAllLabel : input.followAllLabel;
|
|
77
|
+
if (input.isPending) return { accessibilityLabel };
|
|
78
|
+
const accounts = input.count === 1 ? '1 account' : `${input.count} accounts`;
|
|
79
|
+
return {
|
|
80
|
+
accessibilityLabel,
|
|
81
|
+
accessibilityHint: input.allFollowing ? `Unfollows all ${accounts}` : `Follows all ${accounts}`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -52,7 +52,7 @@ export interface OpenAuthorizeOptions {
|
|
|
52
52
|
* (see `normalizeOAuthRedirectUri`), so the IdP always returns the tab to `/`,
|
|
53
53
|
* and the return handlers restore this path. Doing it here rather than at each
|
|
54
54
|
* call site is deliberate: every web authorize redirect — silent restore,
|
|
55
|
-
* interactive sign-in,
|
|
55
|
+
* interactive sign-in, `continueOnAuth` — funnels through this function, so a
|
|
56
56
|
* new flow cannot forget to preserve the page the visitor came from.
|
|
57
57
|
*/
|
|
58
58
|
export function redirectToAuthorize(url: string): void {
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sign-in entry's embedded QR, over the split card's photo carousel: scan
|
|
3
|
+
* it with Commons on a phone and this screen is signed in.
|
|
4
|
+
*
|
|
5
|
+
* It owns one QR-only request (`controller.startInlineQr()`): started the
|
|
6
|
+
* first time the block is actually laid out on screen — never while its column
|
|
7
|
+
* is hidden below `md` — renewed when it expires, and withdrawn when the block
|
|
8
|
+
* goes away while it is still approvable. It never pushes to a phone or opens Commons —
|
|
9
|
+
* the person did not ask for either by opening the screen. Any other sign-in
|
|
10
|
+
* they choose supersedes it like any new attempt.
|
|
11
|
+
*
|
|
12
|
+
* Anti-phishing: the plate encodes `signIn.qrPayload` and renders nothing
|
|
13
|
+
* derived from it; the approver resolves the app server-side.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type React from 'react';
|
|
17
|
+
import { useEffect, useState } from 'react';
|
|
18
|
+
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
|
19
|
+
import QRCode from 'react-native-qrcode-svg';
|
|
20
|
+
import { Button } from '@oxy.so/bloom/button';
|
|
21
|
+
import { RiCheckboxCircleLine } from '@oxy.so/bloom/icons/RiCheckboxCircleLine';
|
|
22
|
+
import { RiRefreshLine } from '@oxy.so/bloom/icons/RiRefreshLine';
|
|
23
|
+
import { useTheme } from '@oxy.so/bloom/theme';
|
|
24
|
+
import { Text } from '@oxy.so/bloom/typography';
|
|
25
|
+
import type { AccountDialogController } from '@oxy.so/core';
|
|
26
|
+
import { useI18n } from '../../hooks/useI18n';
|
|
27
|
+
import { useAccountDialogSnapshot } from '../../hooks/accountDialogSnapshot';
|
|
28
|
+
|
|
29
|
+
/** High-contrast, un-themed on purpose: scan reliability. */
|
|
30
|
+
const QR_PLATE_BG = '#FFFFFF';
|
|
31
|
+
const QR_FOREGROUND = '#000000';
|
|
32
|
+
const QR_SIZE = 112;
|
|
33
|
+
const PLATE_PADDING = 8;
|
|
34
|
+
const PLATE_SIZE = QR_SIZE + PLATE_PADDING * 2;
|
|
35
|
+
|
|
36
|
+
export const InlineCommonsQr: React.FC<{ controller: AccountDialogController | null }> = ({ controller }) => {
|
|
37
|
+
const theme = useTheme();
|
|
38
|
+
const { t } = useI18n();
|
|
39
|
+
const { signIn } = useAccountDialogSnapshot(controller);
|
|
40
|
+
const live = signIn.inline && (signIn.phase === 'starting' || signIn.phase === 'waiting');
|
|
41
|
+
const expired = signIn.inline && signIn.phase === 'error' && signIn.failure === 'expired';
|
|
42
|
+
|
|
43
|
+
// Laid out with a size only where its column shows (`display: none` below
|
|
44
|
+
// `md` lays out empty), so that is when a request is worth having.
|
|
45
|
+
const [shown, setShown] = useState(false);
|
|
46
|
+
|
|
47
|
+
// One request for as long as the block is on screen. Withdrawn on the way
|
|
48
|
+
// out only while it is still ours and still approvable: an attempt the
|
|
49
|
+
// person started meanwhile (a passkey window, "Continue with Oxy") is theirs.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!controller || !shown) return;
|
|
52
|
+
const { signIn: current } = controller.getSnapshot();
|
|
53
|
+
if (!(current.inline && (current.phase === 'starting' || current.phase === 'waiting'))) {
|
|
54
|
+
void controller.startInlineQr();
|
|
55
|
+
}
|
|
56
|
+
return () => {
|
|
57
|
+
const { signIn: last } = controller.getSnapshot();
|
|
58
|
+
if (last.inline && (last.phase === 'starting' || last.phase === 'waiting')) controller.cancelSignIn();
|
|
59
|
+
};
|
|
60
|
+
}, [controller, shown]);
|
|
61
|
+
|
|
62
|
+
// A code only lives a few minutes; an expired one is replaced, not reported.
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (controller && expired) void controller.startInlineQr();
|
|
65
|
+
}, [controller, expired]);
|
|
66
|
+
|
|
67
|
+
let plate: React.ReactNode;
|
|
68
|
+
if (signIn.inline && signIn.progress === 'identity-confirmed') {
|
|
69
|
+
plate = <RiCheckboxCircleLine size="3xl" fill={theme.colors.success} />;
|
|
70
|
+
} else if (live && signIn.qrPayload && signIn.progress !== 'confirming-identity') {
|
|
71
|
+
plate = <QRCode value={signIn.qrPayload} size={QR_SIZE} backgroundColor={QR_PLATE_BG} color={QR_FOREGROUND} />;
|
|
72
|
+
} else if (live || expired || (signIn.inline && signIn.phase === 'completed')) {
|
|
73
|
+
plate = <ActivityIndicator size="large" color={QR_FOREGROUND} />;
|
|
74
|
+
} else {
|
|
75
|
+
// Failed for a reason renewing will not fix by itself, or superseded and
|
|
76
|
+
// then withdrawn: one press for a new code.
|
|
77
|
+
plate = (
|
|
78
|
+
<Button
|
|
79
|
+
appearance="plain"
|
|
80
|
+
tone="neutral"
|
|
81
|
+
size="sm"
|
|
82
|
+
iconOnly
|
|
83
|
+
leadingIcon={RiRefreshLine}
|
|
84
|
+
accessibilityLabel={t('signin.qr.renew')}
|
|
85
|
+
onPress={() => void controller?.startInlineQr()}
|
|
86
|
+
testID="inline-qr-renew"
|
|
87
|
+
/>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View
|
|
93
|
+
style={styles.block}
|
|
94
|
+
testID="inline-commons-qr"
|
|
95
|
+
onLayout={(event) => {
|
|
96
|
+
if (event.nativeEvent.layout.width > 0) setShown(true);
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
<View style={[styles.plate, { borderColor: theme.colors.border }]}>{plate}</View>
|
|
100
|
+
<Text style={[styles.caption, styles.captionOnMedia]}>
|
|
101
|
+
{t('signin.qr.caption')}
|
|
102
|
+
</Text>
|
|
103
|
+
</View>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const styles = StyleSheet.create({
|
|
108
|
+
block: {
|
|
109
|
+
width: PLATE_SIZE,
|
|
110
|
+
alignItems: 'center',
|
|
111
|
+
gap: 6,
|
|
112
|
+
},
|
|
113
|
+
plate: {
|
|
114
|
+
width: PLATE_SIZE,
|
|
115
|
+
height: PLATE_SIZE,
|
|
116
|
+
padding: PLATE_PADDING,
|
|
117
|
+
borderRadius: 12,
|
|
118
|
+
borderWidth: StyleSheet.hairlineWidth,
|
|
119
|
+
backgroundColor: QR_PLATE_BG,
|
|
120
|
+
alignItems: 'center',
|
|
121
|
+
justifyContent: 'center',
|
|
122
|
+
},
|
|
123
|
+
caption: {
|
|
124
|
+
fontSize: 12,
|
|
125
|
+
lineHeight: 16,
|
|
126
|
+
textAlign: 'center',
|
|
127
|
+
},
|
|
128
|
+
captionOnMedia: {
|
|
129
|
+
color: '#FFFFFF',
|
|
130
|
+
fontWeight: '500',
|
|
131
|
+
textShadowColor: 'rgba(0, 0, 0, 0.6)',
|
|
132
|
+
textShadowOffset: { width: 0, height: 1 },
|
|
133
|
+
textShadowRadius: 4,
|
|
134
|
+
},
|
|
135
|
+
});
|