An ATproto social media client -- with an independent Appview.
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add custom feeds selector, rework search, simplify onboarding (#325)

* Get home screen's swipable pager working with the drawer

* Add tab bar to pager

* Implement popular & following views on home screen

* Visual tune-up

* Move the feed selector to the footer

* Fix to 'new posts' poll

* Add the view header as a feed item

* Use the native driver on the tabbar indicator to improve perf

* Reduce home polling to the currently active page; also reuse some code

* Add soft reset on tap selected in tab bar

* Remove explicit 'onboarding' flow

* Choose good stuff based on service

* Add foaf-based follow discovery

* Fall back to who to follow

* Fix backgrounds

* Switch to the off-spec goodstuff route

* 1.8

* Fix for dev & staging

* Swap the tab bar items and rename suggested to what's hot

* Go to whats-hot by default if you have no follows

* Implement pager and tabbar for desktop web

* Pin deps to make expo happy

* Add language filtering to goodstuff

authored by

Paul Frazee and committed by
GitHub
1de724b2 c31ffdac

+1634 -692
+1 -1
app.json
··· 2 2 "expo": { 3 3 "name": "bluesky", 4 4 "slug": "bluesky", 5 - "version": "1.7.0", 5 + "version": "1.8.0", 6 6 "orientation": "portrait", 7 7 "icon": "./assets/icon.png", 8 8 "userInterfaceStyle": "light",
+28 -22
ios/Podfile.lock
··· 19 19 - EXJSONUtils (0.5.1) 20 20 - EXManifests (0.5.2): 21 21 - EXJSONUtils 22 - - EXMediaLibrary (15.2.2): 22 + - EXMediaLibrary (15.2.3): 23 23 - ExpoModulesCore 24 24 - React-Core 25 - - Expo (48.0.6): 25 + - Expo (48.0.7): 26 26 - ExpoModulesCore 27 27 - expo-dev-client (2.1.5): 28 28 - EXManifests ··· 100 100 - ExpoModulesCore 101 101 - ExpoKeepAwake (12.0.1): 102 102 - ExpoModulesCore 103 - - ExpoModulesCore (1.2.4): 103 + - ExpoModulesCore (1.2.5): 104 104 - React-Core 105 105 - React-RCTAppDelegate 106 106 - ReactCommon/turbomodule/core ··· 384 384 - glog 385 385 - react-native-blur (4.3.0): 386 386 - React-Core 387 - - react-native-cameraroll (5.2.4): 387 + - react-native-cameraroll (5.3.1): 388 388 - React-Core 389 389 - react-native-image-resizer (3.0.5): 390 + - React-Core 391 + - react-native-pager-view (6.1.2): 390 392 - React-Core 391 393 - react-native-paste-input (0.6.2): 392 394 - React-Core ··· 401 403 - React-Core 402 404 - react-native-version-number (0.3.6): 403 405 - React 404 - - react-native-webview (11.26.1): 406 + - react-native-webview (11.26.0): 405 407 - React-Core 406 408 - React-perflogger (0.71.3) 407 409 - React-RCTActionSheet (0.71.3): ··· 489 491 - React-perflogger (= 0.71.3) 490 492 - rn-fetch-blob (0.12.0): 491 493 - React-Core 492 - - RNBackgroundFetch (4.1.8): 494 + - RNBackgroundFetch (4.1.9): 493 495 - React-Core 494 - - RNCAsyncStorage (1.17.11): 496 + - RNCAsyncStorage (1.17.12): 495 497 - React-Core 496 498 - RNCClipboard (1.11.2): 497 499 - React-Core ··· 514 516 - TOCropViewController 515 517 - RNInAppBrowser (3.7.0): 516 518 - React-Core 517 - - RNNotifee (7.5.0): 519 + - RNNotifee (7.6.1): 518 520 - React-Core 519 - - RNNotifee/NotifeeCore (= 7.5.0) 520 - - RNNotifee/NotifeeCore (7.5.0): 521 + - RNNotifee/NotifeeCore (= 7.6.1) 522 + - RNNotifee/NotifeeCore (7.6.1): 521 523 - React-Core 522 524 - RNReactNativeHapticFeedback (1.14.0): 523 525 - React-Core ··· 551 553 - RNScreens (3.20.0): 552 554 - React-Core 553 555 - React-RCTImage 554 - - RNSVG (13.8.0): 556 + - RNSVG (13.4.0): 555 557 - React-Core 556 558 - SDWebImage (5.11.1): 557 559 - SDWebImage/Core (= 5.11.1) ··· 559 561 - SDWebImageWebPCoder (0.8.5): 560 562 - libwebp (~> 1.0) 561 563 - SDWebImage/Core (~> 5.10) 562 - - segment-analytics-react-native (2.13.1): 564 + - segment-analytics-react-native (2.13.4): 563 565 - React-Core 564 566 - sovran-react-native 565 567 - sovran-react-native (0.4.5): ··· 614 616 - "react-native-blur (from `../node_modules/@react-native-community/blur`)" 615 617 - "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)" 616 618 - "react-native-image-resizer (from `../node_modules/@bam.tech/react-native-image-resizer`)" 619 + - react-native-pager-view (from `../node_modules/react-native-pager-view`) 617 620 - "react-native-paste-input (from `../node_modules/@mattermost/react-native-paste-input`)" 618 621 - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) 619 622 - react-native-splash-screen (from `../node_modules/react-native-splash-screen`) ··· 747 750 :path: "../node_modules/@react-native-camera-roll/camera-roll" 748 751 react-native-image-resizer: 749 752 :path: "../node_modules/@bam.tech/react-native-image-resizer" 753 + react-native-pager-view: 754 + :path: "../node_modules/react-native-pager-view" 750 755 react-native-paste-input: 751 756 :path: "../node_modules/@mattermost/react-native-paste-input" 752 757 react-native-safe-area-context: ··· 830 835 EXImageLoader: fd053169a8ee932dd83bf1fe5487a50c26d27c2b 831 836 EXJSONUtils: 48b1e764ac35160e6f54d21ab60d7d9501f3e473 832 837 EXManifests: 500666d48e8dd7ca5a482c9e729e4a7a6c34081b 833 - EXMediaLibrary: 792fe9b828b5bfa2c5a8b629730f175af2938285 834 - Expo: 04ba1ddde0be07aff4306ae636a1804810679145 838 + EXMediaLibrary: 587cd8aad27a6fc8d7c38b950bc75bc1845a7480 839 + Expo: 707f9b0039eacc6a1dce90c08c9e37b9c417bba2 835 840 expo-dev-client: 7c1ef51516853465f4d448c14ddf365167d20361 836 841 expo-dev-launcher: 90de99d9e5d1a883d81355ca10e87c2f3c81d46e 837 842 expo-dev-menu: d4369e74d8d21a0ccdee35f7c732e7118b0fee16 838 843 expo-dev-menu-interface: 6c82ae323c4b8724dead4763ce3ff24a2108bdb1 839 844 ExpoImagePicker: 270dea232b3a072d981dd564e2cafc63a864edb1 840 845 ExpoKeepAwake: 69f5f627670d62318410392d03e0b5db0f85759a 841 - ExpoModulesCore: 1667335d4f4c9b7801990930e6f0eea42c916a21 846 + ExpoModulesCore: 397fc99e9d6c9dcc010f36d5802097c17b90424c 842 847 EXSplashScreen: cd7fb052dff5ba8311d5c2455ecbebffe1b7a8ca 843 848 EXUpdatesInterface: dd699d1930e28639dcbd70a402caea98e86364ca 844 849 FBLazyVector: 60195509584153283780abdac5569feffb8f08cc ··· 863 868 React-jsinspector: 9f7c9137605e72ca0343db4cea88006cb94856dd 864 869 React-logger: 957e5dc96d9dbffc6e0f15e0ee4d2b42829ff207 865 870 react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3 866 - react-native-cameraroll: cb752fda6d5268f1646b4390bd5be1f27706b9a0 871 + react-native-cameraroll: f3050460fe1708378698c16686bfaa5f34099be2 867 872 react-native-image-resizer: 00ceb0e05586c7aadf061eea676957a6c2ec60fa 873 + react-native-pager-view: 54bed894cecebe28cede54c01038d9d1e122de43 868 874 react-native-paste-input: 3392800944a47c00dddbff23c31c281482209679 869 875 react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc 870 876 react-native-splash-screen: 4312f786b13a81b5169ef346d76d33bc0c6dc457 871 877 react-native-version-number: b415bbec6a13f2df62bf978e85bc0d699462f37f 872 - react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1 878 + react-native-webview: 994b9f8fbb504d6314dc40d83f94f27c6831b3bf 873 879 React-perflogger: af8a3d31546077f42d729b949925cc4549f14def 874 880 React-RCTActionSheet: 57cc5adfefbaaf0aae2cf7e10bccd746f2903673 875 881 React-RCTAnimation: 11c61e94da700c4dc915cf134513764d87fc5e2b ··· 884 890 React-runtimeexecutor: 7bf0dafc7b727d93c8cb94eb00a9d3753c446c3e 885 891 ReactCommon: 6f65ea5b7d84deb9e386f670dd11ce499ded7b40 886 892 rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba 887 - RNBackgroundFetch: 8e16176ff415daac743a6eb57afc8e9e14dbe623 888 - RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60 893 + RNBackgroundFetch: 642777e4e76435773c149d565a043d66f1781237 894 + RNCAsyncStorage: 09fc8595e6d6f6d5abf16b23a56b257d9c6b7c5b 889 895 RNCClipboard: 3f0451a8100393908bea5c5c5b16f96d45f30bfc 890 896 RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8 891 897 RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 892 898 RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39 893 899 RNImageCropPicker: 648356d68fbf9911a1016b3e3723885d28373eda 894 900 RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364 895 - RNNotifee: 053c0ace9c73634709a0214fd9c436a5777a562f 901 + RNNotifee: bdc064c29f4d558046f51f0c3ae02bab4fd3cd85 896 902 RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c 897 903 RNReanimated: cc5e3aa479cb9170bcccf8204291a6950a3be128 898 904 RNScreens: 218801c16a2782546d30bd2026bb625c0302d70f 899 - RNSVG: c1e76b81c76cdcd34b4e1188852892dc280eb902 905 + RNSVG: 07dbd870b0dcdecc99b3a202fa37c8ca163caec2 900 906 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d 901 907 SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d 902 - segment-analytics-react-native: f962dff3a084655a29f9403b8c139c75a3362524 908 + segment-analytics-react-native: cc12d9422f7ce863ee57c1b650ab48eec4b6d5bd 903 909 sovran-react-native: fd3dc8f1a4b14acdc4ad25fc6b4ac4f52a2a2a15 904 910 Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b 905 911 TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863
+1 -1
ios/bluesky/Info.plist
··· 21 21 <key>CFBundlePackageType</key> 22 22 <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> 23 23 <key>CFBundleShortVersionString</key> 24 - <string>1.7</string> 24 + <string>1.8</string> 25 25 <key>CFBundleSignature</key> 26 26 <string>????</string> 27 27 <key>CFBundleURLTypes</key>
+9 -5
package.json
··· 1 1 { 2 2 "name": "bsky.app", 3 - "version": "1.7.0", 3 + "version": "1.8.0", 4 4 "private": true, 5 5 "scripts": { 6 + "postinstall": "patch-package", 6 7 "android": "expo run:android", 7 8 "ios": "expo run:ios", 8 9 "web": "expo start --web", ··· 58 59 "expo-camera": "~13.2.1", 59 60 "expo-dev-client": "~2.1.1", 60 61 "expo-image-picker": "~14.1.1", 61 - "expo-media-library": "~15.2.1", 62 + "expo-media-library": "~15.2.3", 62 63 "expo-splash-screen": "~0.18.1", 63 64 "expo-status-bar": "~1.4.4", 64 65 "he": "^1.2.0", 65 66 "history": "^5.3.0", 66 67 "js-sha256": "^0.9.0", 68 + "lande": "^1.0.10", 67 69 "lodash.chunk": "^4.2.0", 68 70 "lodash.clonedeep": "^4.5.0", 69 71 "lodash.debounce": "^4.0.8", ··· 75 77 "mobx": "^6.6.1", 76 78 "mobx-react-lite": "^3.4.0", 77 79 "normalize-url": "^8.0.0", 80 + "patch-package": "^6.5.1", 81 + "postinstall-postinstall": "^2.1.0", 78 82 "react": "18.2.0", 79 83 "react-avatar-editor": "^13.0.0", 80 84 "react-circular-progressbar": "^2.1.0", ··· 90 94 "react-native-image-crop-picker": "^0.38.1", 91 95 "react-native-inappbrowser-reborn": "^3.6.3", 92 96 "react-native-linear-gradient": "^2.6.2", 97 + "react-native-pager-view": "6.1.2", 93 98 "react-native-progress": "bluesky-social/react-native-progress", 94 99 "react-native-reanimated": "~2.14.4", 95 100 "react-native-root-siblings": "^4.1.1", 96 101 "react-native-safe-area-context": "^4.4.1", 97 102 "react-native-screens": "^3.13.1", 98 103 "react-native-splash-screen": "^3.3.0", 99 - "react-native-svg": "^13.4.0", 100 - "react-native-tab-view": "^3.3.0", 104 + "react-native-svg": "13.4.0", 101 105 "react-native-url-polyfill": "^1.3.0", 102 106 "react-native-uuid": "^2.0.1", 103 107 "react-native-version-number": "^0.3.6", 104 108 "react-native-web": "^0.18.11", 105 109 "react-native-web-linear-gradient": "^1.1.2", 106 110 "react-native-web-webview": "^1.0.2", 107 - "react-native-webview": "^11.26.1", 111 + "react-native-webview": "11.26.0", 108 112 "react-native-youtube-iframe": "^2.2.2", 109 113 "rn-fetch-blob": "^0.12.0", 110 114 "tippy.js": "^6.3.7",
+54
patches/react-native-pager-view+6.1.4.patch
··· 1 + diff --git a/node_modules/react-native-pager-view/ios/ReactNativePageView.m b/node_modules/react-native-pager-view/ios/ReactNativePageView.m 2 + index ab0fc7f..fbbf19f 100644 3 + --- a/node_modules/react-native-pager-view/ios/ReactNativePageView.m 4 + +++ b/node_modules/react-native-pager-view/ios/ReactNativePageView.m 5 + @@ -1,6 +1,6 @@ 6 + 7 + #import "ReactNativePageView.h" 8 + -#import "React/RCTLog.h" 9 + +#import <React/RCTLog.h> 10 + #import <React/RCTViewManager.h> 11 + 12 + #import "UIViewController+CreateExtension.h" 13 + @@ -9,7 +9,7 @@ 14 + #import "RCTOnPageSelected.h" 15 + #import <math.h> 16 + 17 + -@interface ReactNativePageView () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate> 18 + +@interface ReactNativePageView () <UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate, UIGestureRecognizerDelegate> 19 + 20 + @property(nonatomic, strong) UIPageViewController *reactPageViewController; 21 + @property(nonatomic, strong) RCTEventDispatcher *eventDispatcher; 22 + @@ -80,6 +80,10 @@ 23 + [self setupInitialController]; 24 + } 25 + 26 + + UIPanGestureRecognizer* panGestureRecognizer = [UIPanGestureRecognizer new]; 27 + + panGestureRecognizer.delegate = self; 28 + + [self addGestureRecognizer: panGestureRecognizer]; 29 + + 30 + if (self.reactViewController.navigationController != nil && self.reactViewController.navigationController.interactivePopGestureRecognizer != nil) { 31 + [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:self.reactViewController.navigationController.interactivePopGestureRecognizer]; 32 + } 33 + @@ -463,4 +467,21 @@ 34 + - (BOOL)isLtrLayout { 35 + return [_layoutDirection isEqualToString:@"ltr"]; 36 + } 37 + + 38 + +- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 39 + + if (otherGestureRecognizer == self.scrollView.panGestureRecognizer) { 40 + + UIPanGestureRecognizer* p = (UIPanGestureRecognizer*) gestureRecognizer; 41 + + CGPoint velocity = [p velocityInView:self]; 42 + + if (self.currentIndex == 0 && velocity.x > 0) { 43 + + self.scrollView.panGestureRecognizer.enabled = false; 44 + + return NO; 45 + + } else { 46 + + self.scrollView.panGestureRecognizer.enabled = self.scrollEnabled; 47 + + } 48 + + } else { 49 + + self.scrollView.panGestureRecognizer.enabled = self.scrollEnabled; 50 + + } 51 + + 52 + + return YES; 53 + +} 54 + @end
+7 -3
src/App.native.tsx
··· 4 4 import {RootSiblingParent} from 'react-native-root-siblings' 5 5 import SplashScreen from 'react-native-splash-screen' 6 6 import {SafeAreaProvider} from 'react-native-safe-area-context' 7 + import {GestureHandlerRootView} from 'react-native-gesture-handler' 7 8 import {observer} from 'mobx-react-lite' 8 9 import {ThemeProvider} from 'lib/ThemeContext' 10 + import {s} from 'lib/styles' 9 11 import * as view from './view/index' 10 12 import {RootStoreModel, setupState, RootStoreProvider} from './state' 11 13 import {Shell} from './view/shell' ··· 51 53 <RootSiblingParent> 52 54 <analytics.Provider> 53 55 <RootStoreProvider value={rootStore}> 54 - <SafeAreaProvider> 55 - <Shell /> 56 - </SafeAreaProvider> 56 + <GestureHandlerRootView style={s.h100pct}> 57 + <SafeAreaProvider> 58 + <Shell /> 59 + </SafeAreaProvider> 60 + </GestureHandlerRootView> 57 61 </RootStoreProvider> 58 62 </analytics.Provider> 59 63 </RootSiblingParent>
+31 -1
src/lib/api/feed-manip.ts
··· 1 1 import {AppBskyFeedFeedViewPost} from '@atproto/api' 2 + import lande from 'lande' 2 3 type FeedViewPost = AppBskyFeedFeedViewPost.Main 4 + import {hasProp} from '@atproto/lexicon' 3 5 4 6 export type FeedTunerFn = ( 5 7 tuner: FeedTuner, ··· 140 142 for (const item of slice.items) { 141 143 this.seenUris.add(item.post.uri) 142 144 } 143 - slice.logSelf() 145 + // DEBUG uncomment to get a quick view of the data 146 + // slice.logSelf() 144 147 } 145 148 146 149 return slices ··· 173 176 const item = slices[i].rootItem 174 177 const isRepost = Boolean(item.reason) 175 178 if (item.reply && !isRepost && item.post.upvoteCount === 0) { 179 + slices.splice(i, 1) 180 + } 181 + } 182 + } 183 + 184 + static englishOnly(tuner: FeedTuner, slices: FeedViewPostsSlice[]) { 185 + // TEMP 186 + // remove slices with no english in them 187 + // we very soon need to get the local user's language and filter 188 + // according to their preferences, but for the moment 189 + // we're just rolling with english 190 + // -prf 191 + for (let i = slices.length - 1; i >= 0; i--) { 192 + let hasEnglish = false 193 + for (const item of slices[i].items) { 194 + if ( 195 + hasProp(item.post.record, 'text') && 196 + typeof item.post.record.text === 'string' 197 + ) { 198 + const res = lande(item.post.record.text) 199 + if (res[0][0] === 'eng') { 200 + hasEnglish = true 201 + break 202 + } 203 + } 204 + } 205 + if (!hasEnglish) { 176 206 slices.splice(i, 1) 177 207 } 178 208 }
+4
src/lib/hooks/usePalette.ts
··· 4 4 export interface UsePaletteValue { 5 5 colors: PaletteColor 6 6 view: ViewStyle 7 + viewLight: ViewStyle 7 8 btn: ViewStyle 8 9 border: ViewStyle 9 10 borderDark: ViewStyle ··· 19 20 colors: palette, 20 21 view: { 21 22 backgroundColor: palette.background, 23 + }, 24 + viewLight: { 25 + backgroundColor: palette.backgroundLight, 22 26 }, 23 27 btn: { 24 28 backgroundColor: palette.backgroundLight,
+1
src/lib/styles.ts
··· 70 70 borderRight1: {borderRightWidth: 1}, 71 71 borderBottom1: {borderBottomWidth: 1}, 72 72 borderLeft1: {borderLeftWidth: 1}, 73 + hidden: {display: 'none'}, 73 74 74 75 // font weights 75 76 fw600: {fontWeight: '600'},
+110
src/state/models/discovery/foafs.ts
··· 1 + import {AppBskyActorProfile, AppBskyActorRef} from '@atproto/api' 2 + import {makeAutoObservable, runInAction} from 'mobx' 3 + import sampleSize from 'lodash.samplesize' 4 + import {bundleAsync} from 'lib/async/bundle' 5 + import {RootStoreModel} from '../root-store' 6 + 7 + export type RefWithInfoAndFollowers = AppBskyActorRef.WithInfo & { 8 + followers: AppBskyActorProfile.View[] 9 + } 10 + 11 + export type ProfileViewFollows = AppBskyActorProfile.View & { 12 + follows: AppBskyActorRef.WithInfo[] 13 + } 14 + 15 + export class FoafsModel { 16 + isLoading = false 17 + hasData = false 18 + sources: string[] = [] 19 + foafs: Map<string, ProfileViewFollows> = new Map() 20 + popular: RefWithInfoAndFollowers[] = [] 21 + 22 + constructor(public rootStore: RootStoreModel) { 23 + makeAutoObservable(this) 24 + } 25 + 26 + get hasContent() { 27 + if (this.popular.length > 0) { 28 + return true 29 + } 30 + for (const foaf of this.foafs.values()) { 31 + if (foaf.follows.length) { 32 + return true 33 + } 34 + } 35 + return false 36 + } 37 + 38 + fetch = bundleAsync(async () => { 39 + try { 40 + this.isLoading = true 41 + await this.rootStore.me.follows.fetchIfNeeded() 42 + // grab 10 of the users followed by the user 43 + this.sources = sampleSize( 44 + Object.keys(this.rootStore.me.follows.followDidToRecordMap), 45 + 10, 46 + ) 47 + if (this.sources.length === 0) { 48 + return 49 + } 50 + this.foafs.clear() 51 + this.popular.length = 0 52 + 53 + // fetch their profiles 54 + const profiles = await this.rootStore.api.app.bsky.actor.getProfiles({ 55 + actors: this.sources, 56 + }) 57 + 58 + // fetch their follows 59 + const results = await Promise.allSettled( 60 + this.sources.map(source => 61 + this.rootStore.api.app.bsky.graph.getFollows({user: source}), 62 + ), 63 + ) 64 + 65 + // store the follows and construct a "most followed" set 66 + const popular: RefWithInfoAndFollowers[] = [] 67 + for (let i = 0; i < results.length; i++) { 68 + const res = results[i] 69 + const profile = profiles.data.profiles[i] 70 + const source = this.sources[i] 71 + if (res.status === 'fulfilled' && profile) { 72 + // filter out users already followed by the user or that *is* the user 73 + res.value.data.follows = res.value.data.follows.filter(follow => { 74 + return ( 75 + follow.did !== this.rootStore.me.did && 76 + !this.rootStore.me.follows.isFollowing(follow.did) 77 + ) 78 + }) 79 + 80 + runInAction(() => { 81 + this.foafs.set(source, { 82 + ...profile, 83 + follows: res.value.data.follows, 84 + }) 85 + }) 86 + for (const follow of res.value.data.follows) { 87 + let item = popular.find(p => p.did === follow.did) 88 + if (!item) { 89 + item = {...follow, followers: []} 90 + popular.push(item) 91 + } 92 + item.followers.push(profile) 93 + } 94 + } 95 + } 96 + 97 + popular.sort((a, b) => b.followers.length - a.followers.length) 98 + runInAction(() => { 99 + this.popular = popular.filter(p => p.followers.length > 1).slice(0, 20) 100 + }) 101 + this.hasData = true 102 + } catch (e) { 103 + console.error('Failed to fetch FOAFs', e) 104 + } finally { 105 + runInAction(() => { 106 + this.isLoading = false 107 + }) 108 + } 109 + }) 110 + }
+71 -14
src/state/models/feed-view.ts
··· 257 257 258 258 constructor( 259 259 public rootStore: RootStoreModel, 260 - public feedType: 'home' | 'author' | 'suggested', 260 + public feedType: 'home' | 'author' | 'suggested' | 'goodstuff', 261 261 params: GetTimeline.QueryParams | GetAuthorFeed.QueryParams, 262 262 ) { 263 263 makeAutoObservable( ··· 336 336 return this.setup() 337 337 } 338 338 339 + private get feedTuners() { 340 + if (this.feedType === 'goodstuff') { 341 + return [ 342 + FeedTuner.dedupReposts, 343 + FeedTuner.likedRepliesOnly, 344 + FeedTuner.englishOnly, 345 + ] 346 + } 347 + if (this.feedType === 'home') { 348 + return [FeedTuner.dedupReposts, FeedTuner.likedRepliesOnly] 349 + } 350 + return [] 351 + } 352 + 339 353 /** 340 354 * Load for first render 341 355 */ ··· 399 413 params: this.params, 400 414 e, 401 415 }) 416 + this.hasMore = false 402 417 } 403 418 } finally { 404 419 this.lock.release() ··· 476 491 } 477 492 const res = await this._getFeed({limit: 1}) 478 493 const currentLatestUri = this.pollCursor 479 - const item = res.data.feed[0] 494 + const slices = this.tuner.tune(res.data.feed, this.feedTuners) 495 + const item = slices[0]?.rootItem 480 496 if (!item) { 481 497 return 482 498 } ··· 541 557 this.loadMoreCursor = res.data.cursor 542 558 this.hasMore = !!this.loadMoreCursor 543 559 544 - const slices = this.tuner.tune( 545 - res.data.feed, 546 - this.feedType === 'home' 547 - ? [FeedTuner.dedupReposts, FeedTuner.likedRepliesOnly] 548 - : [], 549 - ) 560 + const slices = this.tuner.tune(res.data.feed, this.feedTuners) 550 561 551 562 const toAppend: FeedSliceModel[] = [] 552 563 for (const slice of slices) { ··· 571 582 ) { 572 583 this.pollCursor = res.data.feed[0]?.post.uri 573 584 574 - const slices = this.tuner.tune( 575 - res.data.feed, 576 - this.feedType === 'home' 577 - ? [FeedTuner.dedupReposts, FeedTuner.likedRepliesOnly] 578 - : [], 579 - ) 585 + const slices = this.tuner.tune(res.data.feed, this.feedTuners) 580 586 581 587 const toPrepend: FeedSliceModel[] = [] 582 588 for (const slice of slices) { ··· 634 640 return this.rootStore.api.app.bsky.feed.getTimeline( 635 641 params as GetTimeline.QueryParams, 636 642 ) 643 + } else if (this.feedType === 'goodstuff') { 644 + const res = await getGoodStuff( 645 + this.rootStore.session.currentSession?.accessJwt || '', 646 + params as GetTimeline.QueryParams, 647 + ) 648 + res.data.feed = (res.data.feed || []).filter( 649 + item => !item.post.author.viewer?.muted, 650 + ) 651 + return res 637 652 } else { 638 653 return this.rootStore.api.app.bsky.feed.getAuthorFeed( 639 654 params as GetAuthorFeed.QueryParams, ··· 641 656 } 642 657 } 643 658 } 659 + 660 + // HACK 661 + // temporary off-spec route to get the good stuff 662 + // -prf 663 + async function getGoodStuff( 664 + accessJwt: string, 665 + params: GetTimeline.QueryParams, 666 + ): Promise<GetTimeline.Response> { 667 + const controller = new AbortController() 668 + const to = setTimeout(() => controller.abort(), 15e3) 669 + 670 + const uri = new URL('https://bsky.social/xrpc/app.bsky.unspecced.getPopular') 671 + let k: keyof GetTimeline.QueryParams 672 + for (k in params) { 673 + if (typeof params[k] !== 'undefined') { 674 + uri.searchParams.set(k, String(params[k])) 675 + } 676 + } 677 + 678 + const res = await fetch(String(uri), { 679 + method: 'get', 680 + headers: { 681 + accept: 'application/json', 682 + authorization: `Bearer ${accessJwt}`, 683 + }, 684 + signal: controller.signal, 685 + }) 686 + 687 + const resHeaders: Record<string, string> = {} 688 + res.headers.forEach((value: string, key: string) => { 689 + resHeaders[key] = value 690 + }) 691 + let resBody = await res.json() 692 + 693 + clearTimeout(to) 694 + 695 + return { 696 + success: res.status === 200, 697 + headers: resHeaders, 698 + data: resBody, 699 + } 700 + }
+1
src/state/models/me.ts
··· 33 33 clear() { 34 34 this.mainFeed.clear() 35 35 this.notifications.clear() 36 + this.follows.clear() 36 37 this.did = '' 37 38 this.handle = '' 38 39 this.displayName = ''
+6
src/state/models/my-follows.ts
··· 35 35 // public api 36 36 // = 37 37 38 + clear() { 39 + this.followDidToRecordMap = {} 40 + this.lastSync = 0 41 + this.myDid = undefined 42 + } 43 + 38 44 fetchIfNeeded = bundleAsync(async () => { 39 45 if ( 40 46 this.myDid !== this.rootStore.me.did ||
+5 -6
src/state/models/session.ts
··· 154 154 /** 155 155 * Sets the active session 156 156 */ 157 - setActiveSession(agent: AtpAgent, did: string) { 157 + async setActiveSession(agent: AtpAgent, did: string) { 158 158 this._log('SessionModel:setActiveSession') 159 159 this.data = { 160 160 service: agent.service.toString(), 161 161 did, 162 162 } 163 - this.rootStore.handleSessionChange(agent) 163 + await this.rootStore.handleSessionChange(agent) 164 164 } 165 165 166 166 /** ··· 304 304 return false 305 305 } 306 306 307 - this.setActiveSession(agent, account.did) 307 + await this.setActiveSession(agent, account.did) 308 308 return true 309 309 } 310 310 ··· 337 337 }, 338 338 ) 339 339 340 - this.setActiveSession(agent, did) 340 + await this.setActiveSession(agent, did) 341 341 this._log('SessionModel:login succeeded') 342 342 } 343 343 ··· 376 376 }, 377 377 ) 378 378 379 - this.setActiveSession(agent, did) 380 - this.rootStore.shell.setOnboarding(true) 379 + await this.setActiveSession(agent, did) 381 380 this._log('SessionModel:createAccount succeeded') 382 381 } 383 382
+5 -10
src/state/models/ui/shell.ts
··· 122 122 darkMode = false 123 123 minimalShellMode = false 124 124 isDrawerOpen = false 125 + isDrawerSwipeDisabled = false 125 126 isModalActive = false 126 127 activeModals: Modal[] = [] 127 128 isLightboxActive = false 128 129 activeLightbox: ProfileImageLightbox | ImagesLightbox | undefined 129 130 isComposerActive = false 130 131 composerOpts: ComposerOpts | undefined 131 - isOnboarding = false 132 132 133 133 constructor(public rootStore: RootStoreModel) { 134 134 makeAutoObservable(this, { ··· 168 168 this.isDrawerOpen = false 169 169 } 170 170 171 + setIsDrawerSwipeDisabled(v: boolean) { 172 + this.isDrawerSwipeDisabled = v 173 + } 174 + 171 175 openModal(modal: Modal) { 172 176 this.rootStore.emitNavigation() 173 177 this.isModalActive = true ··· 199 203 closeComposer() { 200 204 this.isComposerActive = false 201 205 this.composerOpts = undefined 202 - } 203 - 204 - setOnboarding(v: boolean) { 205 - this.isOnboarding = v 206 - if (this.isOnboarding) { 207 - this.rootStore.me.mainFeed.switchFeedType('suggested') 208 - } else { 209 - this.rootStore.me.mainFeed.switchFeedType('home') 210 - } 211 206 } 212 207 }
+56 -104
src/view/com/discover/SuggestedFollows.tsx
··· 1 1 import React from 'react' 2 - import {ActivityIndicator, StyleSheet, View} from 'react-native' 3 - import {CenteredView, FlatList} from '../util/Views' 4 - import {observer} from 'mobx-react-lite' 5 - import {ErrorScreen} from '../util/error/ErrorScreen' 2 + import {StyleSheet, View} from 'react-native' 3 + import {AppBskyActorRef, AppBskyActorProfile} from '@atproto/api' 4 + import {RefWithInfoAndFollowers} from 'state/models/discovery/foafs' 6 5 import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' 7 - import {useStores} from 'state/index' 8 - import { 9 - SuggestedActorsViewModel, 10 - SuggestedActor, 11 - } from 'state/models/suggested-actors-view' 12 - import {s} from 'lib/styles' 6 + import {Text} from '../util/text/Text' 13 7 import {usePalette} from 'lib/hooks/usePalette' 14 8 15 - export const SuggestedFollows = observer( 16 - ({onNoSuggestions}: {onNoSuggestions?: () => void}) => { 17 - const pal = usePalette('default') 18 - const store = useStores() 19 - 20 - const view = React.useMemo<SuggestedActorsViewModel>( 21 - () => new SuggestedActorsViewModel(store), 22 - [store], 23 - ) 24 - 25 - React.useEffect(() => { 26 - view 27 - .loadMore() 28 - .catch((err: any) => 29 - store.log.error('Failed to fetch suggestions', err), 30 - ) 31 - }, [view, store.log]) 32 - 33 - React.useEffect(() => { 34 - if (!view.isLoading && !view.hasError && !view.hasContent) { 35 - onNoSuggestions?.() 36 - } 37 - }, [view, view.isLoading, view.hasError, view.hasContent, onNoSuggestions]) 38 - 39 - const onRefresh = () => { 40 - view 41 - .refresh() 42 - .catch((err: any) => 43 - store.log.error('Failed to fetch suggestions', err), 44 - ) 45 - } 46 - const onEndReached = () => { 47 - view 48 - .loadMore() 49 - .catch(err => 50 - view?.rootStore.log.error('Failed to load more suggestions', err), 51 - ) 52 - } 53 - 54 - const renderItem = ({item}: {item: SuggestedActor}) => { 55 - return ( 56 - <ProfileCardWithFollowBtn 57 - key={item.did} 58 - did={item.did} 59 - declarationCid={item.declaration.cid} 60 - handle={item.handle} 61 - displayName={item.displayName} 62 - avatar={item.avatar} 63 - description={item.description} 64 - /> 65 - ) 66 - } 67 - return ( 68 - <View style={styles.container}> 69 - {view.hasError ? ( 70 - <CenteredView> 71 - <ErrorScreen 72 - title="Failed to load suggestions" 73 - message="There was an error while trying to load suggested follows." 74 - details={view.error} 75 - onPressTryAgain={onRefresh} 76 - /> 77 - </CenteredView> 78 - ) : view.isEmpty ? ( 79 - <View /> 80 - ) : ( 81 - <View style={[styles.suggestionsContainer, pal.view]}> 82 - <FlatList 83 - data={view.suggestions} 84 - keyExtractor={item => item.did} 85 - refreshing={view.isRefreshing} 86 - onRefresh={onRefresh} 87 - onEndReached={onEndReached} 88 - renderItem={renderItem} 89 - initialNumToRender={15} 90 - ListFooterComponent={() => ( 91 - <View style={styles.footer}> 92 - {view.isLoading && <ActivityIndicator />} 93 - </View> 94 - )} 95 - contentContainerStyle={s.contentContainer} 96 - /> 97 - </View> 98 - )} 99 - </View> 100 - ) 101 - }, 102 - ) 9 + export const SuggestedFollows = ({ 10 + title, 11 + suggestions, 12 + }: { 13 + title: string 14 + suggestions: (AppBskyActorRef.WithInfo | RefWithInfoAndFollowers)[] 15 + }) => { 16 + const pal = usePalette('default') 17 + return ( 18 + <View style={[styles.container, pal.view]}> 19 + <Text type="title" style={[styles.heading, pal.text]}> 20 + {title} 21 + </Text> 22 + {suggestions.map(item => ( 23 + <View key={item.did} style={[styles.card, pal.view, pal.border]}> 24 + <ProfileCardWithFollowBtn 25 + key={item.did} 26 + did={item.did} 27 + declarationCid={item.declaration.cid} 28 + handle={item.handle} 29 + displayName={item.displayName} 30 + avatar={item.avatar} 31 + noBg 32 + noBorder 33 + description="" 34 + followers={ 35 + item.followers 36 + ? (item.followers as AppBskyActorProfile.View[]) 37 + : undefined 38 + } 39 + /> 40 + </View> 41 + ))} 42 + </View> 43 + ) 44 + } 103 45 104 46 const styles = StyleSheet.create({ 105 47 container: { 106 - height: '100%', 48 + paddingVertical: 10, 49 + paddingHorizontal: 4, 107 50 }, 108 51 109 - suggestionsContainer: { 110 - height: '100%', 52 + heading: { 53 + fontWeight: 'bold', 54 + paddingHorizontal: 4, 55 + paddingBottom: 8, 111 56 }, 112 - footer: { 113 - height: 200, 114 - paddingTop: 20, 57 + 58 + card: { 59 + borderRadius: 12, 60 + marginBottom: 2, 61 + borderWidth: 1, 62 + }, 63 + 64 + loadMore: { 65 + paddingLeft: 16, 66 + paddingVertical: 12, 115 67 }, 116 68 })
+13 -61
src/view/com/posts/Feed.tsx
··· 7 7 StyleSheet, 8 8 ViewStyle, 9 9 } from 'react-native' 10 - import {useNavigation} from '@react-navigation/native' 11 - import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 12 - import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' 13 10 import {CenteredView, FlatList} from '../util/Views' 14 11 import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' 15 - import {Text} from '../util/text/Text' 12 + import {ViewHeader} from '../util/ViewHeader' 16 13 import {ErrorMessage} from '../util/error/ErrorMessage' 17 - import {Button} from '../util/forms/Button' 18 14 import {FeedModel} from 'state/models/feed-view' 19 15 import {FeedSlice} from './FeedSlice' 20 16 import {OnScrollCb} from 'lib/hooks/useOnMainScroll' 21 17 import {s} from 'lib/styles' 22 18 import {useAnalytics} from 'lib/analytics' 23 - import {usePalette} from 'lib/hooks/usePalette' 24 - import {MagnifyingGlassIcon} from 'lib/icons' 25 - import {NavigationProp} from 'lib/routes/types' 26 19 20 + const HEADER_ITEM = {_reactKey: '__header__'} 27 21 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} 28 22 const ERROR_FEED_ITEM = {_reactKey: '__error__'} 29 23 ··· 34 28 scrollElRef, 35 29 onPressTryAgain, 36 30 onScroll, 31 + renderEmptyState, 37 32 testID, 38 33 headerOffset = 0, 39 34 }: { ··· 43 38 scrollElRef?: MutableRefObject<FlatList<any> | null> 44 39 onPressTryAgain?: () => void 45 40 onScroll?: OnScrollCb 41 + renderEmptyState?: () => JSX.Element 46 42 testID?: string 47 43 headerOffset?: number 48 44 }) { 49 - const pal = usePalette('default') 50 - const palInverted = usePalette('inverted') 51 45 const {track} = useAnalytics() 52 46 const [isRefreshing, setIsRefreshing] = React.useState(false) 53 - const navigation = useNavigation<NavigationProp>() 54 47 55 48 const data = React.useMemo(() => { 56 - let feedItems: any[] = [] 49 + let feedItems: any[] = [HEADER_ITEM] 57 50 if (feed.hasLoaded) { 58 51 if (feed.hasError) { 59 52 feedItems = feedItems.concat([ERROR_FEED_ITEM]) ··· 80 73 } 81 74 setIsRefreshing(false) 82 75 }, [feed, track, setIsRefreshing]) 76 + 83 77 const onEndReached = React.useCallback(async () => { 84 78 track('Feed:onEndReached') 85 79 try { ··· 95 89 const renderItem = React.useCallback( 96 90 ({item}: {item: any}) => { 97 91 if (item === EMPTY_FEED_ITEM) { 98 - return ( 99 - <View style={styles.emptyContainer}> 100 - <View style={styles.emptyIconContainer}> 101 - <MagnifyingGlassIcon 102 - style={[styles.emptyIcon, pal.text]} 103 - size={62} 104 - /> 105 - </View> 106 - <Text type="xl-medium" style={[s.textCenter, pal.text]}> 107 - Your feed is empty! You should follow some accounts to fix this. 108 - </Text> 109 - <Button 110 - type="inverted" 111 - style={styles.emptyBtn} 112 - onPress={ 113 - () => 114 - navigation.navigate( 115 - 'SearchTab', 116 - ) /* TODO make sure it goes to root of the tab */ 117 - }> 118 - <Text type="lg-medium" style={palInverted.text}> 119 - Find accounts 120 - </Text> 121 - <FontAwesomeIcon 122 - icon="angle-right" 123 - style={palInverted.text as FontAwesomeIconStyle} 124 - size={14} 125 - /> 126 - </Button> 127 - </View> 128 - ) 92 + if (renderEmptyState) { 93 + return renderEmptyState() 94 + } 95 + return <View /> 129 96 } else if (item === ERROR_FEED_ITEM) { 130 97 return ( 131 98 <ErrorMessage ··· 133 100 onPressTryAgain={onPressTryAgain} 134 101 /> 135 102 ) 103 + } else if (item === HEADER_ITEM) { 104 + return <ViewHeader title="Bluesky" canGoBack={false} /> 136 105 } 137 106 return <FeedSlice slice={item} showFollowBtn={showPostFollowBtn} /> 138 107 }, 139 - [feed, onPressTryAgain, showPostFollowBtn, pal, palInverted, navigation], 108 + [feed, onPressTryAgain, showPostFollowBtn, renderEmptyState], 140 109 ) 141 110 142 111 const FeedFooter = React.useCallback( ··· 183 152 184 153 const styles = StyleSheet.create({ 185 154 feedFooter: {paddingTop: 20}, 186 - emptyContainer: { 187 - paddingVertical: 40, 188 - paddingHorizontal: 30, 189 - }, 190 - emptyIconContainer: { 191 - marginBottom: 16, 192 - }, 193 - emptyIcon: { 194 - marginLeft: 'auto', 195 - marginRight: 'auto', 196 - }, 197 - emptyBtn: { 198 - marginTop: 20, 199 - flexDirection: 'row', 200 - alignItems: 'center', 201 - justifyContent: 'space-between', 202 - }, 203 155 })
+81
src/view/com/posts/FollowingEmptyState.tsx
··· 1 + import React from 'react' 2 + import {StyleSheet, View} from 'react-native' 3 + import {useNavigation} from '@react-navigation/native' 4 + import { 5 + FontAwesomeIcon, 6 + FontAwesomeIconStyle, 7 + } from '@fortawesome/react-native-fontawesome' 8 + import {Text} from '../util/text/Text' 9 + import {Button} from '../util/forms/Button' 10 + import {MagnifyingGlassIcon} from 'lib/icons' 11 + import {NavigationProp} from 'lib/routes/types' 12 + import {usePalette} from 'lib/hooks/usePalette' 13 + import {s} from 'lib/styles' 14 + 15 + export function FollowingEmptyState() { 16 + const pal = usePalette('default') 17 + const palInverted = usePalette('inverted') 18 + const navigation = useNavigation<NavigationProp>() 19 + 20 + const onPressFindAccounts = React.useCallback(() => { 21 + navigation.navigate('SearchTab') 22 + navigation.popToTop() 23 + }, [navigation]) 24 + 25 + return ( 26 + <View style={styles.emptyContainer}> 27 + <View style={styles.emptyIconContainer}> 28 + <MagnifyingGlassIcon style={[styles.emptyIcon, pal.text]} size={62} /> 29 + </View> 30 + <Text type="xl-medium" style={[s.textCenter, pal.text]}> 31 + Your following feed is empty! Find some accounts to follow to fix this. 32 + </Text> 33 + <Button 34 + type="inverted" 35 + style={styles.emptyBtn} 36 + onPress={onPressFindAccounts}> 37 + <Text type="lg-medium" style={palInverted.text}> 38 + Find accounts to follow 39 + </Text> 40 + <FontAwesomeIcon 41 + icon="angle-right" 42 + style={palInverted.text as FontAwesomeIconStyle} 43 + size={14} 44 + /> 45 + </Button> 46 + </View> 47 + ) 48 + } 49 + const styles = StyleSheet.create({ 50 + emptyContainer: { 51 + // flex: 1, 52 + height: '100%', 53 + paddingVertical: 40, 54 + paddingHorizontal: 30, 55 + }, 56 + emptyIconContainer: { 57 + marginBottom: 16, 58 + }, 59 + emptyIcon: { 60 + marginLeft: 'auto', 61 + marginRight: 'auto', 62 + }, 63 + emptyBtn: { 64 + marginVertical: 20, 65 + flexDirection: 'row', 66 + alignItems: 'center', 67 + justifyContent: 'space-between', 68 + paddingVertical: 18, 69 + paddingHorizontal: 24, 70 + borderRadius: 30, 71 + }, 72 + 73 + feedsTip: { 74 + position: 'absolute', 75 + left: 22, 76 + }, 77 + feedsTipArrow: { 78 + marginLeft: 32, 79 + marginTop: 8, 80 + }, 81 + })
+4 -2
src/view/com/profile/FollowButton.tsx
··· 1 1 import React from 'react' 2 2 import {observer} from 'mobx-react-lite' 3 - import {Button} from '../util/forms/Button' 3 + import {Button, ButtonType} from '../util/forms/Button' 4 4 import {useStores} from 'state/index' 5 5 import * as apilib from 'lib/api/index' 6 6 import * as Toast from '../util/Toast' 7 7 8 8 const FollowButton = observer( 9 9 ({ 10 + type = 'inverted', 10 11 did, 11 12 declarationCid, 12 13 onToggleFollow, 13 14 }: { 15 + type?: ButtonType 14 16 did: string 15 17 declarationCid: string 16 18 onToggleFollow?: (v: boolean) => void ··· 42 44 43 45 return ( 44 46 <Button 45 - type={isFollowing ? 'default' : 'primary'} 47 + type={isFollowing ? 'default' : type} 46 48 onPress={onToggleFollowInner} 47 49 label={isFollowing ? 'Unfollow' : 'Follow'} 48 50 />
+59 -3
src/view/com/profile/ProfileCard.tsx
··· 1 1 import React from 'react' 2 2 import {StyleSheet, View} from 'react-native' 3 3 import {observer} from 'mobx-react-lite' 4 + import {AppBskyActorProfile} from '@atproto/api' 4 5 import {Link} from '../util/Link' 5 6 import {Text} from '../util/text/Text' 6 7 import {UserAvatar} from '../util/UserAvatar' ··· 15 16 avatar, 16 17 description, 17 18 isFollowedBy, 19 + noBg, 18 20 noBorder, 21 + followers, 19 22 renderButton, 20 23 }: { 21 24 handle: string ··· 23 26 avatar?: string 24 27 description?: string 25 28 isFollowedBy?: boolean 29 + noBg?: boolean 26 30 noBorder?: boolean 31 + followers?: AppBskyActorProfile.View[] | undefined 27 32 renderButton?: () => JSX.Element 28 33 }) { 29 34 const pal = usePalette('default') ··· 31 36 <Link 32 37 style={[ 33 38 styles.outer, 34 - pal.view, 35 39 pal.border, 36 40 noBorder && styles.outerNoBorder, 41 + !noBg && pal.view, 37 42 ]} 38 43 href={`/profile/${handle}`} 39 44 title={handle} ··· 73 78 </Text> 74 79 </View> 75 80 ) : undefined} 81 + {followers?.length ? ( 82 + <View style={styles.followedBy}> 83 + <Text 84 + type="sm" 85 + style={[styles.followsByDesc, pal.textLight]} 86 + numberOfLines={2} 87 + lineHeight={1.2}> 88 + Followed by{' '} 89 + {followers.map(f => f.displayName || f.handle).join(', ')} 90 + </Text> 91 + {followers.slice(0, 3).map(f => ( 92 + <View key={f.did} style={styles.followedByAviContainer}> 93 + <View style={[styles.followedByAvi, pal.view]}> 94 + <UserAvatar avatar={f.avatar} size={32} /> 95 + </View> 96 + </View> 97 + ))} 98 + </View> 99 + ) : undefined} 76 100 </Link> 77 101 ) 78 102 } ··· 86 110 avatar, 87 111 description, 88 112 isFollowedBy, 113 + noBg, 114 + noBorder, 115 + followers, 89 116 }: { 90 117 did: string 91 118 declarationCid: string ··· 94 121 avatar?: string 95 122 description?: string 96 123 isFollowedBy?: boolean 124 + noBg?: boolean 125 + noBorder?: boolean 126 + followers?: AppBskyActorProfile.View[] | undefined 97 127 }) => { 98 128 const store = useStores() 99 129 const isMe = store.me.handle === handle ··· 105 135 avatar={avatar} 106 136 description={description} 107 137 isFollowedBy={isFollowedBy} 138 + noBg={noBg} 139 + noBorder={noBorder} 140 + followers={followers} 108 141 renderButton={ 109 142 isMe 110 143 ? undefined ··· 128 161 alignItems: 'center', 129 162 }, 130 163 layoutAvi: { 131 - width: 60, 132 - paddingLeft: 10, 164 + width: 54, 165 + paddingLeft: 4, 133 166 paddingTop: 8, 134 167 paddingBottom: 10, 135 168 }, ··· 163 196 borderRadius: 50, 164 197 marginLeft: 6, 165 198 paddingHorizontal: 14, 199 + }, 200 + 201 + followedBy: { 202 + flexDirection: 'row', 203 + alignItems: 'flex-start', 204 + paddingLeft: 54, 205 + paddingRight: 20, 206 + marginBottom: 10, 207 + marginTop: -6, 208 + }, 209 + followedByAviContainer: { 210 + width: 24, 211 + height: 36, 212 + }, 213 + followedByAvi: { 214 + width: 36, 215 + height: 36, 216 + borderRadius: 18, 217 + padding: 2, 218 + }, 219 + followsByDesc: { 220 + flex: 1, 221 + paddingRight: 10, 166 222 }, 167 223 })
+49
src/view/com/util/LoadingPlaceholder.tsx
··· 128 128 ) 129 129 } 130 130 131 + export function ProfileCardLoadingPlaceholder({ 132 + style, 133 + }: { 134 + style?: StyleProp<ViewStyle> 135 + }) { 136 + const pal = usePalette('default') 137 + return ( 138 + <View style={[styles.profileCard, pal.view, style]}> 139 + <LoadingPlaceholder 140 + width={40} 141 + height={40} 142 + style={styles.profileCardAvi} 143 + /> 144 + <View> 145 + <LoadingPlaceholder width={140} height={8} style={[s.mb5]} /> 146 + <LoadingPlaceholder width={120} height={8} style={[s.mb10]} /> 147 + <LoadingPlaceholder width={220} height={8} style={[s.mb5]} /> 148 + </View> 149 + </View> 150 + ) 151 + } 152 + 153 + export function ProfileCardFeedLoadingPlaceholder() { 154 + return ( 155 + <> 156 + <ProfileCardLoadingPlaceholder /> 157 + <ProfileCardLoadingPlaceholder /> 158 + <ProfileCardLoadingPlaceholder /> 159 + <ProfileCardLoadingPlaceholder /> 160 + <ProfileCardLoadingPlaceholder /> 161 + <ProfileCardLoadingPlaceholder /> 162 + <ProfileCardLoadingPlaceholder /> 163 + <ProfileCardLoadingPlaceholder /> 164 + <ProfileCardLoadingPlaceholder /> 165 + <ProfileCardLoadingPlaceholder /> 166 + <ProfileCardLoadingPlaceholder /> 167 + </> 168 + ) 169 + } 170 + 131 171 const styles = StyleSheet.create({ 132 172 loadingPlaceholder: { 133 173 borderRadius: 6, ··· 146 186 padding: 10, 147 187 paddingLeft: 46, 148 188 margin: 1, 189 + }, 190 + profileCard: { 191 + flexDirection: 'row', 192 + padding: 10, 193 + margin: 1, 194 + }, 195 + profileCardAvi: { 196 + borderRadius: 20, 197 + marginRight: 10, 149 198 }, 150 199 smallAvatar: { 151 200 borderRadius: 15,
+9 -2
src/view/com/util/PostMeta.tsx
··· 44 44 // two-liner with follow button 45 45 return ( 46 46 <View style={styles.metaTwoLine}> 47 - <View> 47 + <View style={styles.metaTwoLineLeft}> 48 48 <View style={styles.metaTwoLineTop}> 49 49 <DesktopWebTextLink 50 50 type="lg-bold" ··· 69 69 type="md" 70 70 style={[styles.metaItem, pal.textLight]} 71 71 lineHeight={1.2} 72 + numberOfLines={1} 72 73 text={`@${handle}`} 73 74 href={`/profile/${opts.authorHandle}`} 74 75 /> ··· 76 77 77 78 <View> 78 79 <FollowButton 80 + type="default" 79 81 did={opts.did} 80 82 declarationCid={opts.declarationCid} 81 83 onToggleFollow={onToggleFollow} ··· 134 136 flexDirection: 'row', 135 137 alignItems: 'center', 136 138 justifyContent: 'space-between', 137 - paddingBottom: 2, 139 + width: '100%', 140 + paddingBottom: 4, 141 + }, 142 + metaTwoLineLeft: { 143 + flex: 1, 144 + paddingRight: 40, 138 145 }, 139 146 metaTwoLineTop: { 140 147 flexDirection: 'row',
+162
src/view/com/util/TabBar.tsx
··· 1 + import React, {createRef, useState, useMemo} from 'react' 2 + import { 3 + Animated, 4 + StyleSheet, 5 + TouchableWithoutFeedback, 6 + View, 7 + } from 'react-native' 8 + import {Text} from './text/Text' 9 + import {usePalette} from 'lib/hooks/usePalette' 10 + import {isDesktopWeb} from 'platform/detection' 11 + 12 + interface Layout { 13 + x: number 14 + width: number 15 + } 16 + 17 + export interface TabBarProps { 18 + selectedPage: number 19 + items: string[] 20 + position: Animated.Value 21 + offset: Animated.Value 22 + indicatorPosition?: 'top' | 'bottom' 23 + indicatorColor?: string 24 + onSelect?: (index: number) => void 25 + onPressSelected?: () => void 26 + } 27 + 28 + export function TabBar({ 29 + selectedPage, 30 + items, 31 + position, 32 + offset, 33 + indicatorPosition = 'bottom', 34 + indicatorColor, 35 + onSelect, 36 + onPressSelected, 37 + }: TabBarProps) { 38 + const pal = usePalette('default') 39 + const [itemLayouts, setItemLayouts] = useState<Layout[]>( 40 + items.map(() => ({x: 0, width: 0})), 41 + ) 42 + const itemRefs = useMemo( 43 + () => Array.from({length: items.length}).map(() => createRef<View>()), 44 + [items.length], 45 + ) 46 + const panX = Animated.add(position, offset) 47 + 48 + const indicatorStyle = { 49 + backgroundColor: indicatorColor || pal.colors.link, 50 + bottom: 51 + indicatorPosition === 'bottom' ? (isDesktopWeb ? 0 : -1) : undefined, 52 + top: indicatorPosition === 'top' ? (isDesktopWeb ? 0 : -1) : undefined, 53 + transform: [ 54 + { 55 + translateX: panX.interpolate({ 56 + inputRange: items.map((_item, i) => i), 57 + outputRange: itemLayouts.map(l => l.x + l.width / 2), 58 + }), 59 + }, 60 + { 61 + scaleX: panX.interpolate({ 62 + inputRange: items.map((_item, i) => i), 63 + outputRange: itemLayouts.map(l => l.width), 64 + }), 65 + }, 66 + ], 67 + } 68 + 69 + const onLayout = () => { 70 + const promises = [] 71 + for (let i = 0; i < items.length; i++) { 72 + promises.push( 73 + new Promise<Layout>(resolve => { 74 + itemRefs[i].current?.measure( 75 + (x: number, _y: number, width: number) => { 76 + resolve({x, width}) 77 + }, 78 + ) 79 + }), 80 + ) 81 + } 82 + Promise.all(promises).then((layouts: Layout[]) => { 83 + setItemLayouts(layouts) 84 + }) 85 + } 86 + 87 + const onPressItem = (index: number) => { 88 + onSelect?.(index) 89 + if (index === selectedPage) { 90 + onPressSelected?.() 91 + } 92 + } 93 + 94 + return ( 95 + <View style={[pal.view, styles.outer]} onLayout={onLayout}> 96 + <Animated.View style={[styles.indicator, indicatorStyle]} /> 97 + {items.map((item, i) => { 98 + const selected = i === selectedPage 99 + return ( 100 + <TouchableWithoutFeedback key={i} onPress={() => onPressItem(i)}> 101 + <View 102 + style={ 103 + indicatorPosition === 'top' ? styles.itemTop : styles.itemBottom 104 + } 105 + ref={itemRefs[i]}> 106 + <Text type="xl-bold" style={selected ? pal.text : pal.textLight}> 107 + {item} 108 + </Text> 109 + </View> 110 + </TouchableWithoutFeedback> 111 + ) 112 + })} 113 + </View> 114 + ) 115 + } 116 + 117 + const styles = isDesktopWeb 118 + ? StyleSheet.create({ 119 + outer: { 120 + flexDirection: 'row', 121 + paddingHorizontal: 18, 122 + }, 123 + itemTop: { 124 + paddingTop: 16, 125 + paddingBottom: 14, 126 + marginRight: 24, 127 + }, 128 + itemBottom: { 129 + paddingTop: 14, 130 + paddingBottom: 16, 131 + marginRight: 24, 132 + }, 133 + indicator: { 134 + position: 'absolute', 135 + left: 0, 136 + width: 1, 137 + height: 3, 138 + }, 139 + }) 140 + : StyleSheet.create({ 141 + outer: { 142 + flexDirection: 'row', 143 + paddingHorizontal: 14, 144 + }, 145 + itemTop: { 146 + paddingTop: 10, 147 + paddingBottom: 10, 148 + marginRight: 24, 149 + }, 150 + itemBottom: { 151 + paddingTop: 8, 152 + paddingBottom: 12, 153 + marginRight: 24, 154 + }, 155 + indicator: { 156 + position: 'absolute', 157 + left: 0, 158 + width: 1, 159 + height: 3, 160 + borderRadius: 4, 161 + }, 162 + })
-101
src/view/com/util/WelcomeBanner.tsx
··· 1 - import React from 'react' 2 - import {StyleSheet, View} from 'react-native' 3 - import {observer} from 'mobx-react-lite' 4 - import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 5 - import {usePalette} from 'lib/hooks/usePalette' 6 - import {Text} from './text/Text' 7 - import {Button} from './forms/Button' 8 - import {s} from 'lib/styles' 9 - import {useStores} from 'state/index' 10 - import {SUGGESTED_FOLLOWS} from 'lib/constants' 11 - // @ts-ignore no type definition -prf 12 - import ProgressBar from 'react-native-progress/Bar' 13 - import {CenteredView} from './Views' 14 - 15 - export const WelcomeBanner = observer(() => { 16 - const pal = usePalette('default') 17 - const store = useStores() 18 - const [isReady, setIsReady] = React.useState(false) 19 - 20 - const numFollows = Math.min( 21 - SUGGESTED_FOLLOWS(String(store.agent.service)).length, 22 - 5, 23 - ) 24 - const remaining = numFollows - store.me.follows.numFollows 25 - 26 - React.useEffect(() => { 27 - if (remaining <= 0) { 28 - // wait 500ms for the progress bar anim to finish 29 - const ti = setTimeout(() => { 30 - setIsReady(true) 31 - }, 500) 32 - return () => clearTimeout(ti) 33 - } else { 34 - setIsReady(false) 35 - } 36 - }, [remaining]) 37 - 38 - const onPressDone = React.useCallback(() => { 39 - store.shell.setOnboarding(false) 40 - }, [store]) 41 - 42 - return ( 43 - <CenteredView 44 - testID="welcomeBanner" 45 - style={[pal.view, styles.container, pal.border]}> 46 - <Text 47 - type="title-lg" 48 - style={[pal.text, s.textCenter, s.bold, s.pb5]} 49 - lineHeight={1.1}> 50 - Welcome to Bluesky! 51 - </Text> 52 - {isReady ? ( 53 - <View style={styles.controls}> 54 - <Button 55 - type="primary" 56 - style={[s.flexRow, s.alignCenter]} 57 - onPress={onPressDone}> 58 - <Text type="md-bold" style={s.white}> 59 - See my feed! 60 - </Text> 61 - <FontAwesomeIcon icon="angle-right" size={14} style={s.white} /> 62 - </Button> 63 - </View> 64 - ) : ( 65 - <> 66 - <Text type="lg" style={[pal.text, s.textCenter]}> 67 - Follow at least {remaining} {remaining === 1 ? 'person' : 'people'}{' '} 68 - to build your feed. 69 - </Text> 70 - <View style={[styles.controls, styles.progress]}> 71 - <ProgressBar 72 - progress={Math.max( 73 - store.me.follows.numFollows / numFollows, 74 - 0.05, 75 - )} 76 - /> 77 - </View> 78 - </> 79 - )} 80 - </CenteredView> 81 - ) 82 - }) 83 - 84 - const styles = StyleSheet.create({ 85 - container: { 86 - paddingTop: 16, 87 - paddingBottom: 16, 88 - paddingHorizontal: 20, 89 - borderTopWidth: 1, 90 - borderBottomWidth: 1, 91 - }, 92 - controls: { 93 - flexDirection: 'row', 94 - alignItems: 'center', 95 - justifyContent: 'center', 96 - marginTop: 10, 97 - }, 98 - progress: { 99 - marginTop: 12, 100 - }, 101 - })
+87
src/view/com/util/pager/Pager.tsx
··· 1 + import React from 'react' 2 + import {Animated, View} from 'react-native' 3 + import PagerView, {PagerViewOnPageSelectedEvent} from 'react-native-pager-view' 4 + import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' 5 + import {s} from 'lib/styles' 6 + 7 + export type PageSelectedEvent = PagerViewOnPageSelectedEvent 8 + const AnimatedPagerView = Animated.createAnimatedComponent(PagerView) 9 + 10 + export interface RenderTabBarFnProps { 11 + selectedPage: number 12 + position: Animated.Value 13 + offset: Animated.Value 14 + onSelect?: (index: number) => void 15 + } 16 + export type RenderTabBarFn = (props: RenderTabBarFnProps) => JSX.Element 17 + 18 + interface Props { 19 + tabBarPosition?: 'top' | 'bottom' 20 + initialPage?: number 21 + renderTabBar: RenderTabBarFn 22 + onPageSelected?: (index: number) => void 23 + } 24 + export const Pager = ({ 25 + children, 26 + tabBarPosition = 'top', 27 + initialPage = 0, 28 + renderTabBar, 29 + onPageSelected, 30 + }: React.PropsWithChildren<Props>) => { 31 + const [selectedPage, setSelectedPage] = React.useState(0) 32 + const position = useAnimatedValue(0) 33 + const offset = useAnimatedValue(0) 34 + const pagerView = React.useRef<PagerView>() 35 + 36 + const onPageSelectedInner = React.useCallback( 37 + (e: PageSelectedEvent) => { 38 + setSelectedPage(e.nativeEvent.position) 39 + onPageSelected?.(e.nativeEvent.position) 40 + }, 41 + [setSelectedPage, onPageSelected], 42 + ) 43 + 44 + const onTabBarSelect = React.useCallback( 45 + (index: number) => { 46 + pagerView.current?.setPage(index) 47 + }, 48 + [pagerView], 49 + ) 50 + 51 + return ( 52 + <View> 53 + {tabBarPosition === 'top' && 54 + renderTabBar({ 55 + selectedPage, 56 + position, 57 + offset, 58 + onSelect: onTabBarSelect, 59 + })} 60 + <AnimatedPagerView 61 + ref={pagerView} 62 + style={s.h100pct} 63 + initialPage={initialPage} 64 + onPageSelected={onPageSelectedInner} 65 + onPageScroll={Animated.event( 66 + [ 67 + { 68 + nativeEvent: { 69 + position: position, 70 + offset: offset, 71 + }, 72 + }, 73 + ], 74 + {useNativeDriver: true}, 75 + )}> 76 + {children} 77 + </AnimatedPagerView> 78 + {tabBarPosition === 'bottom' && 79 + renderTabBar({ 80 + selectedPage, 81 + position, 82 + offset, 83 + onSelect: onTabBarSelect, 84 + })} 85 + </View> 86 + ) 87 + }
+69
src/view/com/util/pager/Pager.web.tsx
··· 1 + import React from 'react' 2 + import {Animated, View} from 'react-native' 3 + import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' 4 + import {s} from 'lib/styles' 5 + 6 + export interface RenderTabBarFnProps { 7 + selectedPage: number 8 + position: Animated.Value 9 + offset: Animated.Value 10 + onSelect?: (index: number) => void 11 + } 12 + export type RenderTabBarFn = (props: RenderTabBarFnProps) => JSX.Element 13 + 14 + interface Props { 15 + tabBarPosition?: 'top' | 'bottom' 16 + initialPage?: number 17 + renderTabBar: RenderTabBarFn 18 + onPageSelected?: (index: number) => void 19 + } 20 + export const Pager = ({ 21 + children, 22 + tabBarPosition = 'top', 23 + initialPage = 0, 24 + renderTabBar, 25 + onPageSelected, 26 + }: React.PropsWithChildren<Props>) => { 27 + const [selectedPage, setSelectedPage] = React.useState(initialPage) 28 + const position = useAnimatedValue(0) 29 + const offset = useAnimatedValue(0) 30 + 31 + const onTabBarSelect = React.useCallback( 32 + (index: number) => { 33 + setSelectedPage(index) 34 + onPageSelected?.(index) 35 + Animated.timing(position, { 36 + toValue: index, 37 + duration: 200, 38 + useNativeDriver: true, 39 + }).start() 40 + }, 41 + [setSelectedPage, onPageSelected, position], 42 + ) 43 + 44 + return ( 45 + <View> 46 + {tabBarPosition === 'top' && 47 + renderTabBar({ 48 + selectedPage, 49 + position, 50 + offset, 51 + onSelect: onTabBarSelect, 52 + })} 53 + {children.map((child, i) => ( 54 + <View 55 + style={selectedPage === i ? undefined : s.hidden} 56 + key={`page-${i}`}> 57 + {child} 58 + </View> 59 + ))} 60 + {tabBarPosition === 'bottom' && 61 + renderTabBar({ 62 + selectedPage, 63 + position, 64 + offset, 65 + onSelect: onTabBarSelect, 66 + })} 67 + </View> 68 + ) 69 + }
+112 -32
src/view/screens/Home.tsx
··· 1 1 import React from 'react' 2 - import {FlatList, View} from 'react-native' 2 + import {FlatList, View, useWindowDimensions} from 'react-native' 3 3 import {useFocusEffect, useIsFocused} from '@react-navigation/native' 4 4 import {observer} from 'mobx-react-lite' 5 5 import useAppState from 'react-native-appstate-hook' 6 6 import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types' 7 + import {FeedModel} from 'state/models/feed-view' 7 8 import {withAuthRequired} from 'view/com/auth/withAuthRequired' 8 - import {ViewHeader} from '../com/util/ViewHeader' 9 9 import {Feed} from '../com/posts/Feed' 10 + import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState' 10 11 import {LoadLatestBtn} from '../com/util/LoadLatestBtn' 11 - import {WelcomeBanner} from '../com/util/WelcomeBanner' 12 + import {FeedsTabBar} from './home/FeedsTabBar' 13 + import {Pager, RenderTabBarFnProps} from 'view/com/util/pager/Pager' 12 14 import {FAB} from '../com/util/FAB' 13 15 import {useStores} from 'state/index' 14 16 import {s} from 'lib/styles' 15 17 import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' 16 18 import {useAnalytics} from 'lib/analytics' 17 19 import {ComposeIcon2} from 'lib/icons' 20 + import {isDesktopWeb} from 'platform/detection' 18 21 19 - const HEADER_HEIGHT = 42 22 + const TAB_BAR_HEIGHT = 82 20 23 21 24 type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'> 22 - export const HomeScreen = withAuthRequired( 23 - observer(function Home(_opts: Props) { 25 + export const HomeScreen = withAuthRequired((_opts: Props) => { 26 + const store = useStores() 27 + const [selectedPage, setSelectedPage] = React.useState(0) 28 + 29 + const algoFeed = React.useMemo(() => { 30 + const feed = new FeedModel(store, 'goodstuff', {}) 31 + feed.setup() 32 + return feed 33 + }, [store]) 34 + 35 + useFocusEffect( 36 + React.useCallback(() => { 37 + store.shell.setIsDrawerSwipeDisabled(selectedPage > 0) 38 + return () => { 39 + store.shell.setIsDrawerSwipeDisabled(false) 40 + } 41 + }, [store, selectedPage]), 42 + ) 43 + 44 + const onPageSelected = React.useCallback( 45 + (index: number) => { 46 + setSelectedPage(index) 47 + store.shell.setIsDrawerSwipeDisabled(index > 0) 48 + }, 49 + [store], 50 + ) 51 + 52 + const onPressSelected = React.useCallback(() => { 53 + store.emitScreenSoftReset() 54 + }, [store]) 55 + 56 + const renderTabBar = React.useCallback( 57 + (props: RenderTabBarFnProps) => { 58 + return <FeedsTabBar {...props} onPressSelected={onPressSelected} /> 59 + }, 60 + [onPressSelected], 61 + ) 62 + 63 + const renderFollowingEmptyState = React.useCallback(() => { 64 + return <FollowingEmptyState /> 65 + }, []) 66 + 67 + const initialPage = store.me.follows.isEmpty ? 1 : 0 68 + return ( 69 + <Pager 70 + onPageSelected={onPageSelected} 71 + renderTabBar={renderTabBar} 72 + tabBarPosition={isDesktopWeb ? 'top' : 'bottom'} 73 + initialPage={initialPage}> 74 + <FeedPage 75 + key="1" 76 + isPageFocused={selectedPage === 0} 77 + feed={store.me.mainFeed} 78 + renderEmptyState={renderFollowingEmptyState} 79 + /> 80 + <FeedPage key="2" isPageFocused={selectedPage === 1} feed={algoFeed} /> 81 + </Pager> 82 + ) 83 + }) 84 + 85 + const FeedPage = observer( 86 + ({ 87 + isPageFocused, 88 + feed, 89 + renderEmptyState, 90 + }: { 91 + feed: FeedModel 92 + isPageFocused: boolean 93 + renderEmptyState?: () => JSX.Element 94 + }) => { 24 95 const store = useStores() 25 96 const onMainScroll = useOnMainScroll(store) 26 97 const {screen, track} = useAnalytics() ··· 28 99 const {appState} = useAppState({ 29 100 onForeground: () => doPoll(true), 30 101 }) 31 - const isFocused = useIsFocused() 102 + const isScreenFocused = useIsFocused() 103 + const winDim = useWindowDimensions() 104 + const containerStyle = React.useMemo( 105 + () => ({height: winDim.height - (isDesktopWeb ? 0 : TAB_BAR_HEIGHT)}), 106 + [winDim], 107 + ) 32 108 33 109 const doPoll = React.useCallback( 34 110 (knownActive = false) => { 35 - if ((!knownActive && appState !== 'active') || !isFocused) { 111 + if ( 112 + (!knownActive && appState !== 'active') || 113 + !isScreenFocused || 114 + !isPageFocused 115 + ) { 36 116 return 37 117 } 38 - if (store.me.mainFeed.isLoading) { 118 + if (feed.isLoading) { 39 119 return 40 120 } 41 121 store.log.debug('HomeScreen: Polling for new posts') 42 - store.me.mainFeed.checkForLatest() 122 + feed.checkForLatest() 43 123 }, 44 - [appState, isFocused, store], 124 + [appState, isScreenFocused, isPageFocused, store, feed], 45 125 ) 46 126 47 127 const scrollToTop = React.useCallback(() => { 48 - // NOTE: the feed is offset by the height of the collapsing header, 49 - // so we scroll to the negative of that height -prf 50 - scrollElRef.current?.scrollToOffset({offset: -HEADER_HEIGHT}) 128 + scrollElRef.current?.scrollToOffset({offset: 0}) 51 129 }, [scrollElRef]) 52 130 131 + const onSoftReset = React.useCallback(() => { 132 + if (isPageFocused) { 133 + scrollToTop() 134 + } 135 + }, [isPageFocused, scrollToTop]) 136 + 53 137 useFocusEffect( 54 138 React.useCallback(() => { 55 - const softResetSub = store.onScreenSoftReset(scrollToTop) 56 - const feedCleanup = store.me.mainFeed.registerListeners() 139 + const softResetSub = store.onScreenSoftReset(onSoftReset) 140 + const feedCleanup = feed.registerListeners() 57 141 const pollInterval = setInterval(doPoll, 15e3) 58 142 59 143 screen('Feed') 60 144 store.log.debug('HomeScreen: Updating feed') 61 - if (store.me.mainFeed.hasContent) { 62 - store.me.mainFeed.update() 145 + if (feed.hasContent) { 146 + feed.update() 63 147 } 64 148 65 149 return () => { ··· 67 151 softResetSub.remove() 68 152 feedCleanup() 69 153 } 70 - }, [store, doPoll, scrollToTop, screen]), 154 + }, [store, doPoll, onSoftReset, screen, feed]), 71 155 ) 72 156 73 157 const onPressCompose = React.useCallback(() => { ··· 76 160 }, [store, track]) 77 161 78 162 const onPressTryAgain = React.useCallback(() => { 79 - store.me.mainFeed.refresh() 80 - }, [store]) 163 + feed.refresh() 164 + }, [feed]) 81 165 82 166 const onPressLoadLatest = React.useCallback(() => { 83 - store.me.mainFeed.refresh() 167 + feed.refresh() 84 168 scrollToTop() 85 - }, [store, scrollToTop]) 169 + }, [feed, scrollToTop]) 86 170 87 171 return ( 88 - <View style={s.hContentRegion}> 89 - {store.shell.isOnboarding && <WelcomeBanner />} 172 + <View style={containerStyle}> 90 173 <Feed 91 174 testID="homeFeed" 92 175 key="default" 93 - feed={store.me.mainFeed} 176 + feed={feed} 94 177 scrollElRef={scrollElRef} 95 178 style={s.hContentRegion} 96 179 showPostFollowBtn 97 180 onPressTryAgain={onPressTryAgain} 98 181 onScroll={onMainScroll} 99 - headerOffset={store.shell.isOnboarding ? 0 : HEADER_HEIGHT} 182 + renderEmptyState={renderEmptyState} 100 183 /> 101 - {!store.shell.isOnboarding && ( 102 - <ViewHeader title="Bluesky" canGoBack={false} hideOnScroll /> 103 - )} 104 - {store.me.mainFeed.hasNewLatest && !store.me.mainFeed.isRefreshing && ( 184 + {feed.hasNewLatest && !feed.isRefreshing && ( 105 185 <LoadLatestBtn onPress={onPressLoadLatest} /> 106 186 )} 107 187 <FAB ··· 111 191 /> 112 192 </View> 113 193 ) 114 - }), 194 + }, 115 195 )
+75 -18
src/view/screens/Search.tsx
··· 1 1 import React from 'react' 2 2 import { 3 3 Keyboard, 4 + RefreshControl, 4 5 StyleSheet, 5 6 TextInput, 6 7 TouchableOpacity, ··· 13 14 FontAwesomeIconStyle, 14 15 } from '@fortawesome/react-native-fontawesome' 15 16 import {withAuthRequired} from 'view/com/auth/withAuthRequired' 16 - import {ScrollView} from '../com/util/Views' 17 + import {ScrollView} from 'view/com/util/Views' 17 18 import { 18 19 NativeStackScreenProps, 19 20 SearchTabNavigatorParams, 20 21 } from 'lib/routes/types' 21 22 import {observer} from 'mobx-react-lite' 22 - import {UserAvatar} from '../com/util/UserAvatar' 23 - import {Text} from '../com/util/text/Text' 23 + import {UserAvatar} from 'view/com/util/UserAvatar' 24 + import {Text} from 'view/com/util/text/Text' 24 25 import {useStores} from 'state/index' 25 26 import {UserAutocompleteViewModel} from 'state/models/user-autocomplete-view' 27 + import {FoafsModel} from 'state/models/discovery/foafs' 26 28 import {s} from 'lib/styles' 27 29 import {MagnifyingGlassIcon} from 'lib/icons' 28 - import {WhoToFollow} from '../com/discover/WhoToFollow' 29 - import {SuggestedPosts} from '../com/discover/SuggestedPosts' 30 - import {ProfileCard} from '../com/profile/ProfileCard' 30 + import {WhoToFollow} from 'view/com/discover/WhoToFollow' 31 + import {SuggestedFollows} from 'view/com/discover/SuggestedFollows' 32 + import {ProfileCard} from 'view/com/profile/ProfileCard' 33 + import {ProfileCardFeedLoadingPlaceholder} from 'view/com/util/LoadingPlaceholder' 31 34 import {usePalette} from 'lib/hooks/usePalette' 32 35 import {useTheme} from 'lib/ThemeContext' 33 36 import {useOnMainScroll} from 'lib/hooks/useOnMainScroll' ··· 53 56 () => new UserAutocompleteViewModel(store), 54 57 [store], 55 58 ) 59 + const foafsView = React.useMemo<FoafsModel>( 60 + () => new FoafsModel(store), 61 + [store], 62 + ) 63 + const [refreshing, setRefreshing] = React.useState(false) 56 64 57 65 const onSoftReset = () => { 58 66 scrollElRef.current?.scrollTo({x: 0, y: 0}) ··· 71 79 } 72 80 store.shell.setMinimalShellMode(false) 73 81 autocompleteView.setup() 82 + if (!foafsView.hasData) { 83 + foafsView.fetch() 84 + } 74 85 75 86 return cleanup 76 - }, [store, autocompleteView, lastRenderTime, setRenderTime]), 87 + }, [store, autocompleteView, foafsView, lastRenderTime, setRenderTime]), 77 88 ) 78 89 79 90 const onPressMenu = () => { ··· 98 109 autocompleteView.setActive(false) 99 110 textInput.current?.blur() 100 111 } 112 + const onRefresh = React.useCallback(async () => { 113 + setRefreshing(true) 114 + try { 115 + await foafsView.fetch() 116 + } finally { 117 + setRefreshing(false) 118 + } 119 + }, [foafsView, setRefreshing]) 101 120 102 121 return ( 103 122 <TouchableWithoutFeedback onPress={Keyboard.dismiss}> 104 - <ScrollView 105 - ref={scrollElRef} 106 - testID="searchScrollView" 107 - style={[pal.view, styles.container]} 108 - onScroll={onMainScroll} 109 - scrollEventThrottle={100}> 123 + <View style={[pal.view, styles.container]}> 110 124 <View style={[pal.view, pal.border, styles.header]}> 111 125 <TouchableOpacity 112 126 testID="viewHeaderBackOrMenuBtn" ··· 180 194 </Text> 181 195 </View> 182 196 ) : ( 183 - <ScrollView onScroll={Keyboard.dismiss}> 184 - <WhoToFollow key={`wtf-${lastRenderTime}`} /> 185 - <SuggestedPosts key={`sp-${lastRenderTime}`} /> 197 + <ScrollView 198 + ref={scrollElRef} 199 + testID="searchScrollView" 200 + style={pal.view} 201 + onScroll={onMainScroll} 202 + scrollEventThrottle={100} 203 + refreshControl={ 204 + <RefreshControl refreshing={refreshing} onRefresh={onRefresh} /> 205 + }> 206 + {foafsView.isLoading ? ( 207 + <ProfileCardFeedLoadingPlaceholder /> 208 + ) : foafsView.hasContent ? ( 209 + <> 210 + {foafsView.popular.length > 0 && ( 211 + <View style={styles.suggestions}> 212 + <SuggestedFollows 213 + title="In your network" 214 + suggestions={foafsView.popular} 215 + /> 216 + </View> 217 + )} 218 + {foafsView.sources.map((source, i) => { 219 + const item = foafsView.foafs.get(source) 220 + if (!item || item.follows.length === 0) { 221 + return <View key={`sf-${item?.did || i}`} /> 222 + } 223 + return ( 224 + <View key={`sf-${item.did}`} style={styles.suggestions}> 225 + <SuggestedFollows 226 + title={`Followed by ${ 227 + item.displayName || item.handle 228 + }`} 229 + suggestions={item.follows.slice(0, 10)} 230 + /> 231 + </View> 232 + ) 233 + })} 234 + </> 235 + ) : ( 236 + <View style={pal.view}> 237 + <WhoToFollow /> 238 + </View> 239 + )} 186 240 <View style={s.footerSpacer} /> 187 241 </ScrollView> 188 242 )} 189 - <View style={s.footerSpacer} /> 190 - </ScrollView> 243 + </View> 191 244 </TouchableWithoutFeedback> 192 245 ) 193 246 }), ··· 234 287 searchPrompt: { 235 288 textAlign: 'center', 236 289 paddingTop: 10, 290 + }, 291 + 292 + suggestions: { 293 + marginBottom: 8, 237 294 }, 238 295 })
+72
src/view/screens/home/FeedsTabBar.tsx
··· 1 + import React from 'react' 2 + import {Animated, StyleSheet} from 'react-native' 3 + import {observer} from 'mobx-react-lite' 4 + import {TabBar} from 'view/com/util/TabBar' 5 + import {RenderTabBarFnProps} from 'view/com/util/pager/Pager' 6 + import {useStores} from 'state/index' 7 + import {usePalette} from 'lib/hooks/usePalette' 8 + import {useSafeAreaInsets} from 'react-native-safe-area-context' 9 + import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' 10 + import {clamp} from 'lodash' 11 + 12 + const BOTTOM_BAR_HEIGHT = 48 13 + 14 + export const FeedsTabBar = observer( 15 + (props: RenderTabBarFnProps & {onPressSelected: () => void}) => { 16 + const store = useStores() 17 + const safeAreaInsets = useSafeAreaInsets() 18 + const pal = usePalette('default') 19 + const interp = useAnimatedValue(0) 20 + 21 + const pad = React.useMemo( 22 + () => ({ 23 + paddingBottom: clamp(safeAreaInsets.bottom, 15, 20), 24 + }), 25 + [safeAreaInsets], 26 + ) 27 + 28 + React.useEffect(() => { 29 + Animated.timing(interp, { 30 + toValue: store.shell.minimalShellMode ? 0 : 1, 31 + duration: 100, 32 + useNativeDriver: true, 33 + isInteraction: false, 34 + }).start() 35 + }, [interp, store.shell.minimalShellMode]) 36 + const transform = { 37 + transform: [ 38 + {translateY: Animated.multiply(interp, -1 * BOTTOM_BAR_HEIGHT)}, 39 + ], 40 + } 41 + 42 + return ( 43 + <Animated.View 44 + style={[pal.view, pal.border, styles.tabBar, pad, transform]}> 45 + <TabBar 46 + {...props} 47 + items={['Following', "What's hot"]} 48 + indicatorPosition="top" 49 + indicatorColor={pal.colors.link} 50 + /> 51 + </Animated.View> 52 + ) 53 + }, 54 + ) 55 + 56 + const styles = StyleSheet.create({ 57 + tabBar: { 58 + position: 'absolute', 59 + left: 0, 60 + right: 0, 61 + bottom: 0, 62 + flexDirection: 'row', 63 + alignItems: 'center', 64 + paddingHorizontal: 10, 65 + borderTopWidth: 1, 66 + paddingTop: 0, 67 + paddingBottom: 30, 68 + }, 69 + tabBarAvi: { 70 + marginRight: 4, 71 + }, 72 + })
+22
src/view/screens/home/FeedsTabBar.web.tsx
··· 1 + import React from 'react' 2 + import {observer} from 'mobx-react-lite' 3 + import {TabBar} from 'view/com/util/TabBar' 4 + import {CenteredView} from 'view/com/util/Views' 5 + import {RenderTabBarFnProps} from 'view/com/util/pager/Pager' 6 + import {usePalette} from 'lib/hooks/usePalette' 7 + 8 + export const FeedsTabBar = observer( 9 + (props: RenderTabBarFnProps & {onPressSelected: () => void}) => { 10 + const pal = usePalette('default') 11 + return ( 12 + <CenteredView> 13 + <TabBar 14 + {...props} 15 + items={['Following', "What's hot"]} 16 + indicatorPosition="bottom" 17 + indicatorColor={pal.colors.link} 18 + /> 19 + </CenteredView> 20 + ) 21 + }, 22 + )
+17 -5
src/view/shell/BottomBar.tsx
··· 34 34 const minimalShellInterp = useAnimatedValue(0) 35 35 const safeAreaInsets = useSafeAreaInsets() 36 36 const {track} = useAnalytics() 37 - const {isAtHome, isAtSearch, isAtNotifications} = useNavigationState( 38 - state => { 39 - return { 37 + const {isAtHome, isAtSearch, isAtNotifications, noBorder} = 38 + useNavigationState(state => { 39 + const res = { 40 40 isAtHome: getTabState(state, 'Home') !== TabState.Outside, 41 41 isAtSearch: getTabState(state, 'Search') !== TabState.Outside, 42 42 isAtNotifications: 43 43 getTabState(state, 'Notifications') !== TabState.Outside, 44 + noBorder: getTabState(state, 'Home') === TabState.InsideAtRoot, 44 45 } 45 - }, 46 - ) 46 + if (!res.isAtHome && !res.isAtNotifications && !res.isAtSearch) { 47 + // HACK for some reason useNavigationState will give us pre-hydration results 48 + // and not update after, so we force isAtHome if all came back false 49 + // -prf 50 + res.isAtHome = true 51 + res.noBorder = true 52 + } 53 + return res 54 + }) 47 55 48 56 React.useEffect(() => { 49 57 if (store.shell.minimalShellMode) { ··· 99 107 <Animated.View 100 108 style={[ 101 109 styles.bottomBar, 110 + noBorder && styles.noBorder, 102 111 pal.view, 103 112 pal.border, 104 113 {paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)}, ··· 212 221 borderTopWidth: 1, 213 222 paddingLeft: 5, 214 223 paddingRight: 10, 224 + }, 225 + noBorder: { 226 + borderTopWidth: 0, 215 227 }, 216 228 ctrl: { 217 229 flex: 1,
+5 -1
src/view/shell/index.tsx
··· 46 46 onOpen={onOpenDrawer} 47 47 onClose={onCloseDrawer} 48 48 swipeEdgeWidth={winDim.width} 49 - swipeEnabled={!canGoBack && store.session.hasSession}> 49 + swipeEnabled={ 50 + !canGoBack && 51 + store.session.hasSession && 52 + !store.shell.isDrawerSwipeDisabled 53 + }> 50 54 <TabsNavigator /> 51 55 </Drawer> 52 56 </ErrorBoundary>
+408 -300
yarn.lock
··· 208 208 integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== 209 209 210 210 "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.16.0", "@babel/core@^7.20.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0": 211 - version "7.21.0" 212 - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.0.tgz#1341aefdcc14ccc7553fcc688dd8986a2daffc13" 213 - integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA== 211 + version "7.21.3" 212 + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.3.tgz#cf1c877284a469da5d1ce1d1e53665253fae712e" 213 + integrity sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw== 214 214 dependencies: 215 215 "@ampproject/remapping" "^2.2.0" 216 216 "@babel/code-frame" "^7.18.6" 217 - "@babel/generator" "^7.21.0" 217 + "@babel/generator" "^7.21.3" 218 218 "@babel/helper-compilation-targets" "^7.20.7" 219 - "@babel/helper-module-transforms" "^7.21.0" 219 + "@babel/helper-module-transforms" "^7.21.2" 220 220 "@babel/helpers" "^7.21.0" 221 - "@babel/parser" "^7.21.0" 221 + "@babel/parser" "^7.21.3" 222 222 "@babel/template" "^7.20.7" 223 - "@babel/traverse" "^7.21.0" 224 - "@babel/types" "^7.21.0" 223 + "@babel/traverse" "^7.21.3" 224 + "@babel/types" "^7.21.3" 225 225 convert-source-map "^1.7.0" 226 226 debug "^4.1.0" 227 227 gensync "^1.0.0-beta.2" ··· 229 229 semver "^6.3.0" 230 230 231 231 "@babel/eslint-parser@^7.16.3", "@babel/eslint-parser@^7.18.2": 232 - version "7.19.1" 233 - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz#4f68f6b0825489e00a24b41b6a1ae35414ecd2f4" 234 - integrity sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ== 232 + version "7.21.3" 233 + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz#d79e822050f2de65d7f368a076846e7184234af7" 234 + integrity sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg== 235 235 dependencies: 236 236 "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" 237 237 eslint-visitor-keys "^2.1.0" 238 238 semver "^6.3.0" 239 239 240 - "@babel/generator@^7.20.0", "@babel/generator@^7.21.0", "@babel/generator@^7.21.1", "@babel/generator@^7.7.2": 241 - version "7.21.1" 242 - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.1.tgz#951cc626057bc0af2c35cd23e9c64d384dea83dd" 243 - integrity sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA== 240 + "@babel/generator@^7.20.0", "@babel/generator@^7.21.3", "@babel/generator@^7.7.2": 241 + version "7.21.3" 242 + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.3.tgz#232359d0874b392df04045d72ce2fd9bb5045fce" 243 + integrity sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA== 244 244 dependencies: 245 - "@babel/types" "^7.21.0" 245 + "@babel/types" "^7.21.3" 246 246 "@jridgewell/gen-mapping" "^0.3.2" 247 247 "@jridgewell/trace-mapping" "^0.3.17" 248 248 jsesc "^2.5.1" ··· 348 348 dependencies: 349 349 "@babel/types" "^7.18.6" 350 350 351 - "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.0", "@babel/helper-module-transforms@^7.21.2": 351 + "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.20.11", "@babel/helper-module-transforms@^7.21.2": 352 352 version "7.21.2" 353 353 resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" 354 354 integrity sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ== ··· 460 460 chalk "^2.0.0" 461 461 js-tokens "^4.0.0" 462 462 463 - "@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.21.0", "@babel/parser@^7.21.2": 464 - version "7.21.2" 465 - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.2.tgz#dacafadfc6d7654c3051a66d6fe55b6cb2f2a0b3" 466 - integrity sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ== 463 + "@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.21.3": 464 + version "7.21.3" 465 + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.3.tgz#1d285d67a19162ff9daa358d4cb41d50c06220b3" 466 + integrity sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ== 467 467 468 468 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": 469 469 version "7.18.6" ··· 837 837 "@babel/template" "^7.20.7" 838 838 839 839 "@babel/plugin-transform-destructuring@^7.0.0", "@babel/plugin-transform-destructuring@^7.20.2": 840 - version "7.20.7" 841 - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz#8bda578f71620c7de7c93af590154ba331415454" 842 - integrity sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA== 840 + version "7.21.3" 841 + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz#73b46d0fd11cd6ef57dea8a381b1215f4959d401" 842 + integrity sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA== 843 843 dependencies: 844 844 "@babel/helper-plugin-utils" "^7.20.2" 845 845 ··· 970 970 "@babel/helper-replace-supers" "^7.18.6" 971 971 972 972 "@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.20.1", "@babel/plugin-transform-parameters@^7.20.7": 973 - version "7.20.7" 974 - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz#0ee349e9d1bc96e78e3b37a7af423a4078a7083f" 975 - integrity sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA== 973 + version "7.21.3" 974 + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz#18fc4e797cf6d6d972cb8c411dbe8a809fa157db" 975 + integrity sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ== 976 976 dependencies: 977 977 "@babel/helper-plugin-utils" "^7.20.2" 978 978 ··· 984 984 "@babel/helper-plugin-utils" "^7.18.6" 985 985 986 986 "@babel/plugin-transform-react-constant-elements@^7.12.1": 987 - version "7.20.2" 988 - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.20.2.tgz#3f02c784e0b711970d7d8ccc96c4359d64e27ac7" 989 - integrity sha512-KS/G8YI8uwMGKErLFOHS/ekhqdHhpEloxs43NecQHVgo2QuQSyJhGIY1fL8UGl9wy5ItVwwoUL4YxVqsplGq2g== 987 + version "7.21.3" 988 + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz#b32a5556100d424b25e388dd689050d78396884d" 989 + integrity sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ== 990 990 dependencies: 991 991 "@babel/helper-plugin-utils" "^7.20.2" 992 992 ··· 1101 1101 "@babel/helper-plugin-utils" "^7.18.9" 1102 1102 1103 1103 "@babel/plugin-transform-typescript@^7.21.0", "@babel/plugin-transform-typescript@^7.5.0": 1104 - version "7.21.0" 1105 - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.0.tgz#f0956a153679e3b377ae5b7f0143427151e4c848" 1106 - integrity sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg== 1104 + version "7.21.3" 1105 + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz#316c5be579856ea890a57ebc5116c5d064658f2b" 1106 + integrity sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw== 1107 1107 dependencies: 1108 + "@babel/helper-annotate-as-pure" "^7.18.6" 1108 1109 "@babel/helper-create-class-features-plugin" "^7.21.0" 1109 1110 "@babel/helper-plugin-utils" "^7.20.2" 1110 1111 "@babel/plugin-syntax-typescript" "^7.20.0" ··· 1278 1279 "@babel/parser" "^7.20.7" 1279 1280 "@babel/types" "^7.20.7" 1280 1281 1281 - "@babel/traverse@^7.20.0", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.7.2", "@babel/traverse@^7.7.4": 1282 - version "7.21.2" 1283 - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.2.tgz#ac7e1f27658750892e815e60ae90f382a46d8e75" 1284 - integrity sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw== 1282 + "@babel/traverse@^7.20.0", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.3", "@babel/traverse@^7.7.2", "@babel/traverse@^7.7.4": 1283 + version "7.21.3" 1284 + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.3.tgz#4747c5e7903d224be71f90788b06798331896f67" 1285 + integrity sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ== 1285 1286 dependencies: 1286 1287 "@babel/code-frame" "^7.18.6" 1287 - "@babel/generator" "^7.21.1" 1288 + "@babel/generator" "^7.21.3" 1288 1289 "@babel/helper-environment-visitor" "^7.18.9" 1289 1290 "@babel/helper-function-name" "^7.21.0" 1290 1291 "@babel/helper-hoist-variables" "^7.18.6" 1291 1292 "@babel/helper-split-export-declaration" "^7.18.6" 1292 - "@babel/parser" "^7.21.2" 1293 - "@babel/types" "^7.21.2" 1293 + "@babel/parser" "^7.21.3" 1294 + "@babel/types" "^7.21.3" 1294 1295 debug "^4.1.0" 1295 1296 globals "^11.1.0" 1296 1297 1297 - "@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": 1298 - version "7.21.2" 1299 - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.2.tgz#92246f6e00f91755893c2876ad653db70c8310d1" 1300 - integrity sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw== 1298 + "@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.3", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": 1299 + version "7.21.3" 1300 + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.3.tgz#4865a5357ce40f64e3400b0f3b737dc6d4f64d05" 1301 + integrity sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg== 1301 1302 dependencies: 1302 1303 "@babel/helper-string-parser" "^7.19.4" 1303 1304 "@babel/helper-validator-identifier" "^7.19.1" ··· 1436 1437 dependencies: 1437 1438 "@types/hammerjs" "^2.0.36" 1438 1439 1439 - "@eslint/eslintrc@^2.0.0": 1440 - version "2.0.0" 1441 - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.0.tgz#943309d8697c52fc82c076e90c1c74fbbe69dbff" 1442 - integrity sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A== 1440 + "@eslint-community/eslint-utils@^4.2.0": 1441 + version "4.3.0" 1442 + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a" 1443 + integrity sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA== 1444 + dependencies: 1445 + eslint-visitor-keys "^3.3.0" 1446 + 1447 + "@eslint-community/regexpp@^4.4.0": 1448 + version "4.4.0" 1449 + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403" 1450 + integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ== 1451 + 1452 + "@eslint/eslintrc@^2.0.1": 1453 + version "2.0.1" 1454 + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d" 1455 + integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw== 1443 1456 dependencies: 1444 1457 ajv "^6.12.4" 1445 1458 debug "^4.3.2" 1446 - espree "^9.4.0" 1459 + espree "^9.5.0" 1447 1460 globals "^13.19.0" 1448 1461 ignore "^5.2.0" 1449 1462 import-fresh "^3.2.1" ··· 1451 1464 minimatch "^3.1.2" 1452 1465 strip-json-comments "^3.1.1" 1453 1466 1454 - "@eslint/js@8.35.0": 1455 - version "8.35.0" 1456 - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.35.0.tgz#b7569632b0b788a0ca0e438235154e45d42813a7" 1457 - integrity sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw== 1467 + "@eslint/js@8.36.0": 1468 + version "8.36.0" 1469 + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" 1470 + integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== 1458 1471 1459 1472 "@expo/bunyan@4.0.0", "@expo/bunyan@^4.0.0": 1460 1473 version "4.0.0" ··· 1831 1844 cross-spawn "^6.0.5" 1832 1845 1833 1846 "@expo/spawn-async@^1.5.0": 1834 - version "1.7.0" 1835 - resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.0.tgz#3ab6082b24318cccc4e73b13464da91325555500" 1836 - integrity sha512-sqPAjOEFTrjaTybrh9SnPFLInDXcoMC06psEFmH68jLTmoipSQCq8GCEfIoHhxRDALWB+DsiwXJSbXlE/iVIIQ== 1847 + version "1.7.2" 1848 + resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58" 1849 + integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew== 1837 1850 dependencies: 1838 1851 cross-spawn "^7.0.3" 1839 1852 ··· 2502 2515 semver "7.3.8" 2503 2516 2504 2517 "@miblanchard/react-native-slider@^2.2.0": 2505 - version "2.3.0" 2506 - resolved "https://registry.yarnpkg.com/@miblanchard/react-native-slider/-/react-native-slider-2.3.0.tgz#91a3294487a9b91e9ff2f841c7ed855ebadfccc9" 2507 - integrity sha512-KiAESUOP69eft8U43iD6xeX+s9ZetwiY/cXkGq1xL4nywb37cVnrxQeSi3+rAix8aHeJwXXeyPZkxmZQe0Hjbw== 2518 + version "2.3.1" 2519 + resolved "https://registry.yarnpkg.com/@miblanchard/react-native-slider/-/react-native-slider-2.3.1.tgz#79e0f1f9b1ce43ef25ee51ee9256c012e5dfa412" 2520 + integrity sha512-J/hZDBWmXq8fJeOnTVHqIUVDHshqMSpJVxJ4WqwuCBKl5Rke9OBYXIdkSlgi75OgtScAr8FKK5KNkDKHUf6JIg== 2508 2521 2509 2522 "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": 2510 2523 version "5.1.1-v1" ··· 2540 2553 fastq "^1.6.0" 2541 2554 2542 2555 "@notifee/react-native@^7.4.0": 2543 - version "7.5.0" 2544 - resolved "https://registry.yarnpkg.com/@notifee/react-native/-/react-native-7.5.0.tgz#3d846b6a607a6352e798a3440cd3880c005a7d56" 2545 - integrity sha512-FR1xzQI2KpMyLuM7YZyHHjCcOXbjAcBWMeRlarro8peujr6gJZSg4j2Aw4o8O4ifMHDopFrovwyK1uYBaB9MUg== 2556 + version "7.6.1" 2557 + resolved "https://registry.yarnpkg.com/@notifee/react-native/-/react-native-7.6.1.tgz#e215428787396ec57ea424106cc88666f7efe70d" 2558 + integrity sha512-OjhLPODh6FICYZmF9/0UZbcl2JPaPpcrWi1Cvs/OLFbPSJTIEwPZgXFrCHv/cA3wUX4YQCXreSqQGSVQgvNItQ== 2546 2559 2547 2560 "@npmcli/fs@^1.0.0": 2548 2561 version "1.1.1" ··· 2580 2593 resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" 2581 2594 integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== 2582 2595 2583 - "@react-native-async-storage/async-storage@^1.15.15", "@react-native-async-storage/async-storage@^1.15.17", "@react-native-async-storage/async-storage@^1.17.6": 2584 - version "1.17.11" 2585 - resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.17.11.tgz#7ec329c1b9f610e344602e806b04d7c928a2341d" 2586 - integrity sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw== 2596 + "@react-native-async-storage/async-storage@^1.15.15", "@react-native-async-storage/async-storage@^1.17.6": 2597 + version "1.17.12" 2598 + resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.17.12.tgz#a39e4df5b06795ce49b2ca5b7ca9b8faadf8e621" 2599 + integrity sha512-BXg4OxFdjPTRt+8MvN6jz4muq0/2zII3s7HeT/11e4Zeh3WCgk/BleLzUcDfVqF3OzFHUqEkSrb76d6Ndjd/Nw== 2587 2600 dependencies: 2588 2601 merge-options "^3.0.4" 2589 2602 2590 2603 "@react-native-camera-roll/camera-roll@^5.2.2": 2591 - version "5.2.4" 2592 - resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-5.2.4.tgz#216d0ea4656b6538c10b60f057118c6f5e704c0d" 2593 - integrity sha512-pEQDartgO8Nqy6QDm1efvIPpv4q5W+AtTgS05JGK/9x8VzSj8fJ/cvHmMZBlm/4sFpJyvJZ+1KYxKsvFJLbGuQ== 2604 + version "5.3.1" 2605 + resolved "https://registry.yarnpkg.com/@react-native-camera-roll/camera-roll/-/camera-roll-5.3.1.tgz#0b6d363c0f6c83fc93ff033826f8fa96274a01a7" 2606 + integrity sha512-2XKMkb/pLBC6vYkNh+bJ4UEj49V2ZSyWFHmaxsUJU9beLo1QbM3XJnySV6F1uv7aC+I2RBlDuAusCqNiTQiCOw== 2594 2607 2595 2608 "@react-native-clipboard/clipboard@^1.10.0": 2596 2609 version "1.11.2" ··· 2632 2645 serve-static "^1.13.1" 2633 2646 2634 2647 "@react-native-community/cli-doctor@^10.1.1": 2635 - version "10.2.0" 2636 - resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-10.2.0.tgz#6050030eea9200ce3c35de360cf8455e126b4d45" 2637 - integrity sha512-yLxJazUmNSPslHxeeev0gLvsK0nQan8BmGWbtqPz2WwbIbD89vbytC7G96OxiQXr46iWEWAwEJiTTdgA7jlA5Q== 2648 + version "10.2.1" 2649 + resolved "https://registry.yarnpkg.com/@react-native-community/cli-doctor/-/cli-doctor-10.2.1.tgz#b6b7a3f0f9cef1a05f1adc6393eb29c6f8f2972c" 2650 + integrity sha512-IwhdSD+mtgWdxg2eMr0fpkn08XN7r70DC1riGSmqK/DXNyWBzIZlCkDN+/TwlaUEsiFk6LQTjgCiqZSMpmDrsg== 2638 2651 dependencies: 2639 2652 "@react-native-community/cli-config" "^10.1.1" 2640 - "@react-native-community/cli-platform-ios" "^10.2.0" 2653 + "@react-native-community/cli-platform-ios" "^10.2.1" 2641 2654 "@react-native-community/cli-tools" "^10.1.1" 2642 2655 chalk "^4.1.2" 2643 2656 command-exists "^1.2.8" ··· 2697 2710 glob "^7.1.3" 2698 2711 ora "^5.4.1" 2699 2712 2700 - "@react-native-community/cli-platform-ios@^10.2.0": 2701 - version "10.2.0" 2702 - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.2.0.tgz#be21c0e3bbf17358d540cc23e5556bf679f6322e" 2703 - integrity sha512-hIPK3iL/mL+0ChXmQ9uqqzNOKA48H+TAzg+hrxQLll/6dNMxDeK9/wZpktcsh8w+CyhqzKqVernGcQs7tPeKGw== 2713 + "@react-native-community/cli-platform-ios@^10.2.1": 2714 + version "10.2.1" 2715 + resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-10.2.1.tgz#2e6bd2cb6d48cbb8720d7b7265bb1bab80745f72" 2716 + integrity sha512-hz4zu4Y6eyj7D0lnZx8Mf2c2si8y+zh/zUTgCTaPPLzQD8jSZNNBtUUiA1cARm2razpe8marCZ1QbTMAGbf3mg== 2704 2717 dependencies: 2705 2718 "@react-native-community/cli-tools" "^10.1.1" 2706 2719 chalk "^4.1.2" ··· 2963 2976 integrity sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg== 2964 2977 2965 2978 "@segment/analytics-react-native@^2.10.1": 2966 - version "2.13.1" 2967 - resolved "https://registry.yarnpkg.com/@segment/analytics-react-native/-/analytics-react-native-2.13.1.tgz#c093c145cb1a5a87041fbbfc5fa61c3fb370787c" 2968 - integrity sha512-IRg0k8rVTNj2U4jpA0VKGioUKYAbvvYf3FNR8BsHDB3Jutmxdh/SPYAttFU1APJ9mQsqMEIEfocbDtwCAL0kAg== 2979 + version "2.13.4" 2980 + resolved "https://registry.yarnpkg.com/@segment/analytics-react-native/-/analytics-react-native-2.13.4.tgz#52216972bf0a1f8722ddf18088340c9d4d90ca5a" 2981 + integrity sha512-47z2TmODJpeA7Pf1P8kE5dNTiqmxJ7khQ/NgiFR3eoiSy/ir0QOpT49QFrwVMeG35fEl+wDGLXUoYWoAMvBy6w== 2969 2982 dependencies: 2970 - "@react-native-async-storage/async-storage" "^1.15.17" 2971 - "@segment/sovran-react-native" "^0.4.5" 2983 + "@segment/sovran-react-native" "^1" 2972 2984 deepmerge "^4.2.2" 2973 2985 js-base64 "^3.7.2" 2974 - react-native-uuid "^2.0.1" 2986 + uuid "^9.0.0" 2975 2987 2976 2988 "@segment/loosely-validate-event@^2.0.0": 2977 2989 version "2.0.0" ··· 2987 2999 integrity sha512-/dvud4hkszRNgTHdb7p822U+NXTuPxifqQzhcrfdjmFoXMafnzOUAi1KxeGV6Qdb73VAIxcnr/8hkTqdjZ3YLw== 2988 3000 dependencies: 2989 3001 "@react-native-async-storage/async-storage" "^1.15.15" 3002 + ansi-regex "5.0.1" 3003 + deepmerge "^4.2.2" 3004 + shell-quote "1.7.3" 3005 + 3006 + "@segment/sovran-react-native@^1": 3007 + version "1.0.1" 3008 + resolved "https://registry.yarnpkg.com/@segment/sovran-react-native/-/sovran-react-native-1.0.1.tgz#4311f0af2e2b606d2c17e535b293c096c6a3c2e8" 3009 + integrity sha512-7VZrIa7/VP59d4QDvAs0ZOhiadlJ+2YC8K8dKOF0fGwiFC0UmQUZVs4IN9GZfbBavXsagVVMgL2GzjVGLLQdBw== 3010 + dependencies: 2990 3011 ansi-regex "5.0.1" 2991 3012 deepmerge "^4.2.2" 2992 3013 shell-quote "1.7.3" ··· 3370 3391 "@types/estree" "*" 3371 3392 3372 3393 "@types/eslint@*", "@types/eslint@^7.29.0 || ^8.4.1": 3373 - version "8.21.1" 3374 - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.21.1.tgz#110b441a210d53ab47795124dbc3e9bb993d1e7c" 3375 - integrity sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ== 3394 + version "8.21.3" 3395 + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.21.3.tgz#5794b3911f0f19e34e3a272c49cbdf48d6f543f2" 3396 + integrity sha512-fa7GkppZVEByMWGbTtE5MbmXWJTVbrjjaS8K6uQj+XtuuUv1fsuPAxhygfqLmsb/Ufb3CV8deFCpiMfAgi00Sw== 3376 3397 dependencies: 3377 3398 "@types/estree" "*" 3378 3399 "@types/json-schema" "*" ··· 3468 3489 "@types/istanbul-lib-report" "*" 3469 3490 3470 3491 "@types/jest@^29.4.0": 3471 - version "29.4.0" 3472 - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.4.0.tgz#a8444ad1704493e84dbf07bb05990b275b3b9206" 3473 - integrity sha512-VaywcGQ9tPorCX/Jkkni7RWGFfI11whqzs8dvxF41P17Z+z872thvEvlIbznjPJ02kl1HMX3LmLOonsj2n7HeQ== 3492 + version "29.5.0" 3493 + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.0.tgz#337b90bbcfe42158f39c2fb5619ad044bbb518ac" 3494 + integrity sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg== 3474 3495 dependencies: 3475 3496 expect "^29.0.0" 3476 3497 pretty-format "^29.0.0" ··· 3559 3580 integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== 3560 3581 3561 3582 "@types/node@*": 3562 - version "18.14.6" 3563 - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.6.tgz#ae1973dd2b1eeb1825695bb11ebfb746d27e3e93" 3564 - integrity sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA== 3583 + version "18.15.3" 3584 + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" 3585 + integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== 3565 3586 3566 3587 "@types/object.omit@^3.0.0": 3567 3588 version "3.0.0" ··· 3731 3752 "@types/yargs-parser" "*" 3732 3753 3733 3754 "@typescript-eslint/eslint-plugin@^5.30.5", "@typescript-eslint/eslint-plugin@^5.48.2", "@typescript-eslint/eslint-plugin@^5.5.0": 3734 - version "5.54.1" 3735 - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz#0c5091289ce28372e38ab8d28e861d2dbe1ab29e" 3736 - integrity sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew== 3755 + version "5.55.0" 3756 + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz#bc2400c3a23305e8c9a9c04aa40933868aaaeb47" 3757 + integrity sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg== 3737 3758 dependencies: 3738 - "@typescript-eslint/scope-manager" "5.54.1" 3739 - "@typescript-eslint/type-utils" "5.54.1" 3740 - "@typescript-eslint/utils" "5.54.1" 3759 + "@eslint-community/regexpp" "^4.4.0" 3760 + "@typescript-eslint/scope-manager" "5.55.0" 3761 + "@typescript-eslint/type-utils" "5.55.0" 3762 + "@typescript-eslint/utils" "5.55.0" 3741 3763 debug "^4.3.4" 3742 3764 grapheme-splitter "^1.0.4" 3743 3765 ignore "^5.2.0" 3744 3766 natural-compare-lite "^1.4.0" 3745 - regexpp "^3.2.0" 3746 3767 semver "^7.3.7" 3747 3768 tsutils "^3.21.0" 3748 3769 3749 3770 "@typescript-eslint/experimental-utils@^5.0.0": 3750 - version "5.54.1" 3751 - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.54.1.tgz#a45609ce43fc6b24b4c4dde215446eaad7805223" 3752 - integrity sha512-oqSc2Gr4TL/2M0XRJ9abA1o3Wf1cFJTNqWq0kjdStIIvgMQGZ3TSaFFJ2Cvy3Fgqi9UfDZ8u5idbACssIIyHaw== 3771 + version "5.55.0" 3772 + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.55.0.tgz#ea2dd8737834af3a36b6a7be5bee57f57160c942" 3773 + integrity sha512-3ZqXIZhdGyGQAIIGATeMtg7prA6VlyxGtcy5hYIR/3qUqp3t18pWWUYhL9mpsDm7y8F9mr3ISMt83TiqCt7OPQ== 3753 3774 dependencies: 3754 - "@typescript-eslint/utils" "5.54.1" 3775 + "@typescript-eslint/utils" "5.55.0" 3755 3776 3756 3777 "@typescript-eslint/parser@^5.30.5", "@typescript-eslint/parser@^5.48.2", "@typescript-eslint/parser@^5.5.0": 3757 - version "5.54.1" 3758 - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.54.1.tgz#05761d7f777ef1c37c971d3af6631715099b084c" 3759 - integrity sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg== 3778 + version "5.55.0" 3779 + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.55.0.tgz#8c96a0b6529708ace1dcfa60f5e6aec0f5ed2262" 3780 + integrity sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw== 3760 3781 dependencies: 3761 - "@typescript-eslint/scope-manager" "5.54.1" 3762 - "@typescript-eslint/types" "5.54.1" 3763 - "@typescript-eslint/typescript-estree" "5.54.1" 3782 + "@typescript-eslint/scope-manager" "5.55.0" 3783 + "@typescript-eslint/types" "5.55.0" 3784 + "@typescript-eslint/typescript-estree" "5.55.0" 3764 3785 debug "^4.3.4" 3765 3786 3766 - "@typescript-eslint/scope-manager@5.54.1": 3767 - version "5.54.1" 3768 - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz#6d864b4915741c608a58ce9912edf5a02bb58735" 3769 - integrity sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg== 3787 + "@typescript-eslint/scope-manager@5.55.0": 3788 + version "5.55.0" 3789 + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz#e863bab4d4183ddce79967fe10ceb6c829791210" 3790 + integrity sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw== 3770 3791 dependencies: 3771 - "@typescript-eslint/types" "5.54.1" 3772 - "@typescript-eslint/visitor-keys" "5.54.1" 3792 + "@typescript-eslint/types" "5.55.0" 3793 + "@typescript-eslint/visitor-keys" "5.55.0" 3773 3794 3774 - "@typescript-eslint/type-utils@5.54.1": 3775 - version "5.54.1" 3776 - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz#4825918ec27e55da8bb99cd07ec2a8e5f50ab748" 3777 - integrity sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g== 3795 + "@typescript-eslint/type-utils@5.55.0": 3796 + version "5.55.0" 3797 + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz#74bf0233523f874738677bb73cb58094210e01e9" 3798 + integrity sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA== 3778 3799 dependencies: 3779 - "@typescript-eslint/typescript-estree" "5.54.1" 3780 - "@typescript-eslint/utils" "5.54.1" 3800 + "@typescript-eslint/typescript-estree" "5.55.0" 3801 + "@typescript-eslint/utils" "5.55.0" 3781 3802 debug "^4.3.4" 3782 3803 tsutils "^3.21.0" 3783 3804 3784 - "@typescript-eslint/types@5.54.1": 3785 - version "5.54.1" 3786 - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.1.tgz#29fbac29a716d0f08c62fe5de70c9b6735de215c" 3787 - integrity sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw== 3805 + "@typescript-eslint/types@5.55.0": 3806 + version "5.55.0" 3807 + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.55.0.tgz#9830f8d3bcbecf59d12f821e5bc6960baaed41fd" 3808 + integrity sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug== 3788 3809 3789 - "@typescript-eslint/typescript-estree@5.54.1": 3790 - version "5.54.1" 3791 - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz#df7b6ae05fd8fef724a87afa7e2f57fa4a599be1" 3792 - integrity sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg== 3810 + "@typescript-eslint/typescript-estree@5.55.0": 3811 + version "5.55.0" 3812 + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz#8db7c8e47ecc03d49b05362b8db6f1345ee7b575" 3813 + integrity sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ== 3793 3814 dependencies: 3794 - "@typescript-eslint/types" "5.54.1" 3795 - "@typescript-eslint/visitor-keys" "5.54.1" 3815 + "@typescript-eslint/types" "5.55.0" 3816 + "@typescript-eslint/visitor-keys" "5.55.0" 3796 3817 debug "^4.3.4" 3797 3818 globby "^11.1.0" 3798 3819 is-glob "^4.0.3" 3799 3820 semver "^7.3.7" 3800 3821 tsutils "^3.21.0" 3801 3822 3802 - "@typescript-eslint/utils@5.54.1", "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.43.0": 3803 - version "5.54.1" 3804 - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.1.tgz#7a3ee47409285387b9d4609ea7e1020d1797ec34" 3805 - integrity sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ== 3823 + "@typescript-eslint/utils@5.55.0", "@typescript-eslint/utils@^5.10.0", "@typescript-eslint/utils@^5.43.0": 3824 + version "5.55.0" 3825 + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.55.0.tgz#34e97322e7ae5b901e7a870aabb01dad90023341" 3826 + integrity sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw== 3806 3827 dependencies: 3828 + "@eslint-community/eslint-utils" "^4.2.0" 3807 3829 "@types/json-schema" "^7.0.9" 3808 3830 "@types/semver" "^7.3.12" 3809 - "@typescript-eslint/scope-manager" "5.54.1" 3810 - "@typescript-eslint/types" "5.54.1" 3811 - "@typescript-eslint/typescript-estree" "5.54.1" 3831 + "@typescript-eslint/scope-manager" "5.55.0" 3832 + "@typescript-eslint/types" "5.55.0" 3833 + "@typescript-eslint/typescript-estree" "5.55.0" 3812 3834 eslint-scope "^5.1.1" 3813 - eslint-utils "^3.0.0" 3814 3835 semver "^7.3.7" 3815 3836 3816 - "@typescript-eslint/visitor-keys@5.54.1": 3817 - version "5.54.1" 3818 - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz#d7a8a0f7181d6ac748f4d47b2306e0513b98bf8b" 3819 - integrity sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg== 3837 + "@typescript-eslint/visitor-keys@5.55.0": 3838 + version "5.55.0" 3839 + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz#01ad414fca8367706d76cdb94adf788dc5b664a2" 3840 + integrity sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw== 3820 3841 dependencies: 3821 - "@typescript-eslint/types" "5.54.1" 3842 + "@typescript-eslint/types" "5.55.0" 3822 3843 eslint-visitor-keys "^3.3.0" 3823 3844 3824 3845 "@ucans/core@0.11.0": ··· 3837 3858 wonka "^4.0.14" 3838 3859 3839 3860 "@urql/core@>=2.3.1": 3840 - version "3.1.1" 3841 - resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.1.1.tgz#a49cd572360d01f2469a786b294fba2269a65e53" 3842 - integrity sha512-Mnxtq4I4QeFJsgs7Iytw+HyhiGxISR6qtyk66c9tipozLZ6QVxrCiUPF2HY4BxNIabaxcp+rivadvm8NAnXj4Q== 3861 + version "3.2.2" 3862 + resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.2.2.tgz#2a44015b536d72981822f715c96393d8e0ddc576" 3863 + integrity sha512-i046Cz8cZ4xIzGMTyHZrbdgzcFMcKD7+yhCAH5FwWBRjcKrc+RjEOuR9X5AMuBvr8c6IAaE92xAqa4wmlGfWTQ== 3843 3864 dependencies: 3844 3865 wonka "^6.1.2" 3845 3866 ··· 4002 4023 resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" 4003 4024 integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== 4004 4025 4026 + "@yarnpkg/lockfile@^1.1.0": 4027 + version "1.1.0" 4028 + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" 4029 + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== 4030 + 4005 4031 "@zxing/text-encoding@^0.9.0": 4006 4032 version "0.9.0" 4007 4033 resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b" ··· 4172 4198 type-fest "^0.21.3" 4173 4199 4174 4200 ansi-escapes@^6.0.0: 4175 - version "6.0.0" 4176 - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-6.0.0.tgz#68c580e87a489f6df3d761028bb93093fde6bd8a" 4177 - integrity sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw== 4201 + version "6.1.0" 4202 + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-6.1.0.tgz#f2912cdaa10785f3f51f4b562a2497b885aadc5e" 4203 + integrity sha512-bQyg9bzRntwR/8b89DOEhGwctcwCrbWW/TuqTQnpqpy5Fz3aovcOTj5i8NJV6AHc8OGNdMaqdxAWww8pz2kiKg== 4178 4204 dependencies: 4179 4205 type-fest "^3.0.0" 4180 4206 ··· 4292 4318 version "3.1.0" 4293 4319 resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" 4294 4320 integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== 4321 + 4322 + array-buffer-byte-length@^1.0.0: 4323 + version "1.0.0" 4324 + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" 4325 + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== 4326 + dependencies: 4327 + call-bind "^1.0.2" 4328 + is-array-buffer "^3.0.1" 4295 4329 4296 4330 array-flatten@1.1.1: 4297 4331 version "1.1.1" ··· 4448 4482 integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== 4449 4483 4450 4484 autoprefixer@^10.4.13: 4451 - version "10.4.13" 4452 - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8" 4453 - integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg== 4485 + version "10.4.14" 4486 + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.14.tgz#e28d49902f8e759dd25b153264e862df2705f79d" 4487 + integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== 4454 4488 dependencies: 4455 - browserslist "^4.21.4" 4456 - caniuse-lite "^1.0.30001426" 4489 + browserslist "^4.21.5" 4490 + caniuse-lite "^1.0.30001464" 4457 4491 fraction.js "^4.2.0" 4458 4492 normalize-range "^0.1.2" 4459 4493 picocolors "^1.0.0" ··· 5185 5219 lodash.memoize "^4.1.2" 5186 5220 lodash.uniq "^4.5.0" 5187 5221 5188 - caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449: 5189 - version "1.0.30001462" 5190 - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001462.tgz#b2e801e37536d453731286857c8520d3dcee15fe" 5191 - integrity sha512-PDd20WuOBPiasZ7KbFnmQRyuLE7cFXW2PVd7dmALzbkUXEP46upAuCDm9eY9vho8fgNMGmbAX92QBZHzcnWIqw== 5222 + caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: 5223 + version "1.0.30001468" 5224 + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz#0101837c6a4e38e6331104c33dcfb3bdf367a4b7" 5225 + integrity sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A== 5192 5226 5193 5227 case-anything@^2.1.10: 5194 5228 version "2.1.10" ··· 5201 5235 integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== 5202 5236 5203 5237 cborg@^1.6.0: 5204 - version "1.10.0" 5205 - resolved "https://registry.yarnpkg.com/cborg/-/cborg-1.10.0.tgz#0fe157961dd47b537ccb84dc9ba681de8b699013" 5206 - integrity sha512-/eM0JCaL99HDHxjySNQJLaolZFVdl6VA0/hEKIoiQPcQzE5LrG5QHdml0HaBt31brgB9dNe1zMr3f8IVrpotRQ== 5238 + version "1.10.1" 5239 + resolved "https://registry.yarnpkg.com/cborg/-/cborg-1.10.1.tgz#24cfe52c69ec0f66f95e23dc57f2086954c8d718" 5240 + integrity sha512-et6Qm8MOUY2kCWa5GKk2MlBVoPjHv0hQBmlzI/Z7+5V3VJCeIkGehIB3vWknNsm2kOkAIs6wEKJFJo8luWQQ/w== 5207 5241 5208 5242 chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.1, chalk@^2.4.2: 5209 5243 version "2.4.2" ··· 5657 5691 serialize-javascript "^6.0.0" 5658 5692 5659 5693 core-js-compat@^3.25.1: 5660 - version "3.29.0" 5661 - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.0.tgz#1b8d9eb4191ab112022e7f6364b99b65ea52f528" 5662 - integrity sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ== 5694 + version "3.29.1" 5695 + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.29.1.tgz#15c0fb812ea27c973c18d425099afa50b934b41b" 5696 + integrity sha512-QmchCua884D8wWskMX8tW5ydINzd8oSJVx38lx/pVkFGqztxt73GYre3pm/hyYq8bPf+MW5In4I/uRShFDsbrA== 5663 5697 dependencies: 5664 5698 browserslist "^4.21.5" 5665 5699 5666 5700 core-js-pure@^3.23.3: 5667 - version "3.29.0" 5668 - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.0.tgz#0e1ac889214398641ea4bb1c6cf25ff0959ec1d2" 5669 - integrity sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ== 5701 + version "3.29.1" 5702 + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.29.1.tgz#1be6ca2b8772f6b4df7fc4621743286e676c6162" 5703 + integrity sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg== 5670 5704 5671 5705 core-js@^3.19.2: 5672 - version "3.29.0" 5673 - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.0.tgz#0273e142b67761058bcde5615c503c7406b572d6" 5674 - integrity sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg== 5706 + version "3.29.1" 5707 + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.29.1.tgz#40ff3b41588b091aaed19ca1aa5cb111803fa9a6" 5708 + integrity sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw== 5675 5709 5676 5710 core-util-is@~1.0.0: 5677 5711 version "1.0.3" ··· 6124 6158 integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA== 6125 6159 6126 6160 deepmerge@^4.2.2: 6127 - version "4.3.0" 6128 - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.0.tgz#65491893ec47756d44719ae520e0e2609233b59b" 6129 - integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== 6161 + version "4.3.1" 6162 + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" 6163 + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== 6130 6164 6131 6165 default-gateway@^4.2.0: 6132 6166 version "4.2.0" ··· 6548 6582 integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== 6549 6583 6550 6584 ejs@^3.1.6: 6551 - version "3.1.8" 6552 - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b" 6553 - integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ== 6585 + version "3.1.9" 6586 + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" 6587 + integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== 6554 6588 dependencies: 6555 6589 jake "^10.8.5" 6556 6590 6557 6591 electron-to-chromium@^1.4.284: 6558 - version "1.4.325" 6559 - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.325.tgz#7b97238a61192d85d055d97f3149832b3617d37b" 6560 - integrity sha512-K1C03NT4I7BuzsRdCU5RWkgZxtswnKDYM6/eMhkEXqKu4e5T+ck610x3FPzu1y7HVFSiQKZqP16gnJzPpji1TQ== 6592 + version "1.4.333" 6593 + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.333.tgz#ebb21f860f8a29923717b06ec0cb54e77ed34c04" 6594 + integrity sha512-YyE8+GKyGtPEP1/kpvqsdhD6rA/TP1DUFDN4uiU/YI52NzDxmwHkEb3qjId8hLBa5siJvG0sfC3O66501jMruQ== 6561 6595 6562 6596 email-validator@^2.0.4: 6563 6597 version "2.0.4" ··· 6667 6701 escape-html "~1.0.3" 6668 6702 6669 6703 es-abstract@^1.17.2, es-abstract@^1.19.0, es-abstract@^1.20.4: 6670 - version "1.21.1" 6671 - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" 6672 - integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg== 6704 + version "1.21.2" 6705 + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" 6706 + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== 6673 6707 dependencies: 6708 + array-buffer-byte-length "^1.0.0" 6674 6709 available-typed-arrays "^1.0.5" 6675 6710 call-bind "^1.0.2" 6676 6711 es-set-tostringtag "^2.0.1" 6677 6712 es-to-primitive "^1.2.1" 6678 - function-bind "^1.1.1" 6679 6713 function.prototype.name "^1.1.5" 6680 - get-intrinsic "^1.1.3" 6714 + get-intrinsic "^1.2.0" 6681 6715 get-symbol-description "^1.0.0" 6682 6716 globalthis "^1.0.3" 6683 6717 gopd "^1.0.1" ··· 6685 6719 has-property-descriptors "^1.0.0" 6686 6720 has-proto "^1.0.1" 6687 6721 has-symbols "^1.0.3" 6688 - internal-slot "^1.0.4" 6689 - is-array-buffer "^3.0.1" 6722 + internal-slot "^1.0.5" 6723 + is-array-buffer "^3.0.2" 6690 6724 is-callable "^1.2.7" 6691 6725 is-negative-zero "^2.0.2" 6692 6726 is-regex "^1.1.4" ··· 6694 6728 is-string "^1.0.7" 6695 6729 is-typed-array "^1.1.10" 6696 6730 is-weakref "^1.0.2" 6697 - object-inspect "^1.12.2" 6731 + object-inspect "^1.12.3" 6698 6732 object-keys "^1.1.1" 6699 6733 object.assign "^4.1.4" 6700 6734 regexp.prototype.flags "^1.4.3" 6701 6735 safe-regex-test "^1.0.0" 6736 + string.prototype.trim "^1.2.7" 6702 6737 string.prototype.trimend "^1.0.6" 6703 6738 string.prototype.trimstart "^1.0.6" 6704 6739 typed-array-length "^1.0.4" ··· 6990 7025 esrecurse "^4.3.0" 6991 7026 estraverse "^5.2.0" 6992 7027 6993 - eslint-utils@^3.0.0: 6994 - version "3.0.0" 6995 - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" 6996 - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== 6997 - dependencies: 6998 - eslint-visitor-keys "^2.0.0" 6999 - 7000 - eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: 7028 + eslint-visitor-keys@^2.1.0: 7001 7029 version "2.1.0" 7002 7030 resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" 7003 7031 integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== ··· 7019 7047 schema-utils "^4.0.0" 7020 7048 7021 7049 eslint@^8.19.0, eslint@^8.3.0: 7022 - version "8.35.0" 7023 - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.35.0.tgz#fffad7c7e326bae606f0e8f436a6158566d42323" 7024 - integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw== 7050 + version "8.36.0" 7051 + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf" 7052 + integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw== 7025 7053 dependencies: 7026 - "@eslint/eslintrc" "^2.0.0" 7027 - "@eslint/js" "8.35.0" 7054 + "@eslint-community/eslint-utils" "^4.2.0" 7055 + "@eslint-community/regexpp" "^4.4.0" 7056 + "@eslint/eslintrc" "^2.0.1" 7057 + "@eslint/js" "8.36.0" 7028 7058 "@humanwhocodes/config-array" "^0.11.8" 7029 7059 "@humanwhocodes/module-importer" "^1.0.1" 7030 7060 "@nodelib/fs.walk" "^1.2.8" ··· 7035 7065 doctrine "^3.0.0" 7036 7066 escape-string-regexp "^4.0.0" 7037 7067 eslint-scope "^7.1.1" 7038 - eslint-utils "^3.0.0" 7039 7068 eslint-visitor-keys "^3.3.0" 7040 - espree "^9.4.0" 7069 + espree "^9.5.0" 7041 7070 esquery "^1.4.2" 7042 7071 esutils "^2.0.2" 7043 7072 fast-deep-equal "^3.1.3" ··· 7059 7088 minimatch "^3.1.2" 7060 7089 natural-compare "^1.4.0" 7061 7090 optionator "^0.9.1" 7062 - regexpp "^3.2.0" 7063 7091 strip-ansi "^6.0.1" 7064 7092 strip-json-comments "^3.1.0" 7065 7093 text-table "^0.2.0" 7066 7094 7067 - espree@^9.4.0: 7068 - version "9.4.1" 7069 - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" 7070 - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== 7095 + espree@^9.5.0: 7096 + version "9.5.0" 7097 + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113" 7098 + integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw== 7071 7099 dependencies: 7072 7100 acorn "^8.8.0" 7073 7101 acorn-jsx "^5.3.2" ··· 7324 7352 dependencies: 7325 7353 expo-json-utils "~0.5.0" 7326 7354 7327 - expo-media-library@~15.2.1: 7328 - version "15.2.2" 7329 - resolved "https://registry.yarnpkg.com/expo-media-library/-/expo-media-library-15.2.2.tgz#71ece905e425f606422cd16019d78b135040e003" 7330 - integrity sha512-GebBavV9H+m0Qzoy4G7++BWmwUcddLnCee1qGYkCyHT6CvuLNhXUgC3FV9NINEwlii3HGAuCzk1auaEY60SGDA== 7355 + expo-media-library@~15.2.3: 7356 + version "15.2.3" 7357 + resolved "https://registry.yarnpkg.com/expo-media-library/-/expo-media-library-15.2.3.tgz#188f3c77f58b354f0ea6250f6756ac1e1a226291" 7358 + integrity sha512-Oz8b8Xsvfj7YcutUBtI84NUIqSnt7iCM5HZ5DyKoWKKiDK/+aUuj3RXNQELG8jUw6pQPgEwgbZ1+J8SdH/y9jw== 7331 7359 7332 7360 expo-modules-autolinking@1.1.2: 7333 7361 version "1.1.2" ··· 7340 7368 find-up "^5.0.0" 7341 7369 fs-extra "^9.1.0" 7342 7370 7343 - expo-modules-core@1.2.4: 7344 - version "1.2.4" 7345 - resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.2.4.tgz#06c0e92b952ae2d3b3329dbeadb6da4f01965d63" 7346 - integrity sha512-AV0NCTy9O8xQqpKgX6gvsDzV1ogpCzYpGxqM85Vw1xHsOF51s7Avu7NdNjBPUZOVuDderUXAvd97dWrtefSKcA== 7371 + expo-modules-core@1.2.5: 7372 + version "1.2.5" 7373 + resolved "https://registry.yarnpkg.com/expo-modules-core/-/expo-modules-core-1.2.5.tgz#3f9166f4c32c68ab8ef3e120c70ce9890b711650" 7374 + integrity sha512-5pXNlLHNKLayOusAFMbqr27gjgymHuKuWl/Dtbw2MjoyJY1MZCGD2nIJxd1TTcfnyxNxLg6OQmgkyqoBUFqBuw== 7347 7375 dependencies: 7348 7376 compare-versions "^3.4.0" 7349 7377 invariant "^2.2.4" ··· 7377 7405 integrity sha512-wk88LLhseQ7LJvxdN7BTKiryyqALxnrvr+lyHK3/prg76Yy0EGi2Q/oE/rtFyyZ1JmQDRbO/5pdX0EE6QqVQXQ== 7378 7406 7379 7407 expo@~48.0.0-beta.2: 7380 - version "48.0.6" 7381 - resolved "https://registry.yarnpkg.com/expo/-/expo-48.0.6.tgz#374e51a6791bc15e998cd66c335d304ea9c4472a" 7382 - integrity sha512-ylm91v/xYjBBEqFHH+mpNyGijJgFXx4NwgKgHCIEfcAQyTZLXpGCL6teOVzAmHCCVF7EdalLl3If/+n09jOi4g== 7408 + version "48.0.7" 7409 + resolved "https://registry.yarnpkg.com/expo/-/expo-48.0.7.tgz#7900bfda316d25127ed9c412daa31db66dc4a869" 7410 + integrity sha512-4sPW+HWm03z72FKIG9IddwEhF9+RlAUsTh8pnsoZjZbXALVikmV3QjD4zp/Dkt9YuiCAnJN1VBaT2AlhbYk2Rg== 7383 7411 dependencies: 7384 7412 "@babel/runtime" "^7.20.0" 7385 7413 "@expo/cli" "0.6.2" ··· 7395 7423 expo-font "~11.1.1" 7396 7424 expo-keep-awake "~12.0.1" 7397 7425 expo-modules-autolinking "1.1.2" 7398 - expo-modules-core "1.2.4" 7426 + expo-modules-core "1.2.5" 7399 7427 fbemitter "^3.0.0" 7400 7428 getenv "^1.0.0" 7401 7429 invariant "^2.2.4" ··· 7742 7770 locate-path "^6.0.0" 7743 7771 path-exists "^4.0.0" 7744 7772 7745 - find-yarn-workspace-root@~2.0.0: 7773 + find-yarn-workspace-root@^2.0.0, find-yarn-workspace-root@~2.0.0: 7746 7774 version "2.0.0" 7747 7775 resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" 7748 7776 integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== ··· 7768 7796 integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== 7769 7797 7770 7798 flow-parser@0.*: 7771 - version "0.201.0" 7772 - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.201.0.tgz#d2005d4dae6fddf60d30f9ae0fb49a13c9c51cfe" 7773 - integrity sha512-G4oeDNpNGyIrweF9EnoHatncAihMT0tQgV6NMdyM5I7fhrz9Pr13PJ2KLQ673O4wj9KooTdBpeeYHdDNAQoyyw== 7799 + version "0.202.0" 7800 + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.202.0.tgz#534178266d3ceec5368415e59990db97eece5bd0" 7801 + integrity sha512-ZiXxSIXK3zPmY3zrzCofFonM2T+/3Jz5QZKJyPVtUERQEJUnYkXBQ+0H3FzyqiyJs+VXqb/UNU6/K6sziVYdxw== 7774 7802 7775 7803 flow-parser@^0.185.0: 7776 7804 version "0.185.2" ··· 8186 8214 get-intrinsic "^1.1.3" 8187 8215 8188 8216 graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: 8189 - version "4.2.10" 8190 - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" 8191 - integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== 8217 + version "4.2.11" 8218 + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 8219 + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 8192 8220 8193 8221 grapheme-splitter@^1.0.4: 8194 8222 version "1.0.4" ··· 8672 8700 default-gateway "^4.2.0" 8673 8701 ipaddr.js "^1.9.0" 8674 8702 8675 - internal-slot@^1.0.3, internal-slot@^1.0.4: 8703 + internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: 8676 8704 version "1.0.5" 8677 8705 resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" 8678 8706 integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== ··· 8735 8763 call-bind "^1.0.2" 8736 8764 has-tostringtag "^1.0.0" 8737 8765 8738 - is-array-buffer@^3.0.1: 8766 + is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: 8739 8767 version "3.0.2" 8740 8768 resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" 8741 8769 integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== ··· 8786 8814 resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" 8787 8815 integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== 8788 8816 8817 + is-ci@^2.0.0: 8818 + version "2.0.0" 8819 + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" 8820 + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== 8821 + dependencies: 8822 + ci-info "^2.0.0" 8823 + 8789 8824 is-core-module@^2.11.0, is-core-module@^2.9.0: 8790 8825 version "2.11.0" 8791 8826 resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" ··· 10116 10151 integrity sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww== 10117 10152 10118 10153 joi@^17.2.1: 10119 - version "17.8.3" 10120 - resolved "https://registry.yarnpkg.com/joi/-/joi-17.8.3.tgz#d772fe27a87a5cda21aace5cf11eee8671ca7e6f" 10121 - integrity sha512-q5Fn6Tj/jR8PfrLrx4fpGH4v9qM6o+vDUfD4/3vxxyg34OmKcNqYZ1qn2mpLza96S8tL0p0rIw2gOZX+/cTg9w== 10154 + version "17.8.4" 10155 + resolved "https://registry.yarnpkg.com/joi/-/joi-17.8.4.tgz#f2d91ab8acd3cca4079ba70669c65891739234aa" 10156 + integrity sha512-jjdRHb5WtL+KgSHvOULQEPPv4kcl+ixd1ybOFQq3rWLgEEqc03QMmilodL0GVJE14U/SQDXkUhQUSZANGDH/AA== 10122 10157 dependencies: 10123 10158 "@hapi/hoek" "^9.0.0" 10124 10159 "@hapi/topo" "^5.0.0" ··· 10435 10470 resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" 10436 10471 integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== 10437 10472 10473 + klaw-sync@^6.0.0: 10474 + version "6.0.0" 10475 + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" 10476 + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== 10477 + dependencies: 10478 + graceful-fs "^4.1.11" 10479 + 10438 10480 kleur@^3.0.3: 10439 10481 version "3.0.3" 10440 10482 resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" ··· 10450 10492 resolved "https://registry.yarnpkg.com/kysely/-/kysely-0.22.0.tgz#8aac53942da3cadc604d7d154a746d983fe8f7b9" 10451 10493 integrity sha512-ZE3qWtnqLOalodzfK5QUEcm7AEulhxsPNuKaGFsC3XiqO92vMLm+mAHk/NnbSIOtC4RmGm0nsv700i8KDp1gfQ== 10452 10494 10495 + lande@^1.0.10: 10496 + version "1.0.10" 10497 + resolved "https://registry.yarnpkg.com/lande/-/lande-1.0.10.tgz#1f6c6542e628338eb18def22edd1038f5fce9e7a" 10498 + integrity sha512-yT52DQh+UV2pEp08jOYrA4drDv0DbjpiRyZYgl25ak9G2cVR2AimzrqkYQWrD9a7Ud+qkAcaiDDoNH9DXfHPmw== 10499 + dependencies: 10500 + toygrad "^2.6.0" 10501 + 10453 10502 language-subtag-registry@~0.3.2: 10454 10503 version "0.3.22" 10455 10504 resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz#2e1500861b2e457eba7e7ae86877cbd08fa1fd1d" ··· 10461 10510 integrity sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ== 10462 10511 dependencies: 10463 10512 language-subtag-registry "~0.3.2" 10513 + 10514 + launch-editor@^2.6.0: 10515 + version "2.6.0" 10516 + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" 10517 + integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== 10518 + dependencies: 10519 + picocolors "^1.0.0" 10520 + shell-quote "^1.7.3" 10464 10521 10465 10522 leven@^3.1.0: 10466 10523 version "3.1.0" ··· 11310 11367 integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== 11311 11368 11312 11369 mini-css-extract-plugin@^2.4.5, mini-css-extract-plugin@^2.5.2: 11313 - version "2.7.3" 11314 - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.3.tgz#794aa4d598bf178a66b2a35fe287c3df3eac394e" 11315 - integrity sha512-CD9cXeKeXLcnMw8FZdtfrRrLaM7gwCl4nKuKn2YkY2Bw5wdlB8zU2cCzw+w2zS9RFvbrufTBkMCJACNPwqQA0w== 11370 + version "2.7.5" 11371 + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz#afbb344977659ec0f1f6e050c7aea456b121cfc5" 11372 + integrity sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ== 11316 11373 dependencies: 11317 11374 schema-utils "^4.0.0" 11318 11375 ··· 11376 11433 yallist "^4.0.0" 11377 11434 11378 11435 minipass@^4.0.0: 11379 - version "4.2.4" 11380 - resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.4.tgz#7d0d97434b6a19f59c5c3221698b48bbf3b2cd06" 11381 - integrity sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ== 11436 + version "4.2.5" 11437 + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.5.tgz#9e0e5256f1e3513f8c34691dd68549e85b2c8ceb" 11438 + integrity sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q== 11382 11439 11383 11440 minizlib@^2.1.1: 11384 11441 version "2.1.2" ··· 11756 11813 resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" 11757 11814 integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== 11758 11815 11759 - object-inspect@^1.12.2, object-inspect@^1.9.0: 11816 + object-inspect@^1.12.3, object-inspect@^1.9.0: 11760 11817 version "1.12.3" 11761 11818 resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" 11762 11819 integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== ··· 11911 11968 integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== 11912 11969 dependencies: 11913 11970 is-wsl "^1.1.0" 11971 + 11972 + open@^7.4.2: 11973 + version "7.4.2" 11974 + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" 11975 + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== 11976 + dependencies: 11977 + is-docker "^2.0.0" 11978 + is-wsl "^2.1.1" 11914 11979 11915 11980 open@^8.0.4, open@^8.0.9, open@^8.3.0, open@^8.4.0: 11916 11981 version "8.4.2" ··· 12170 12235 ansi-escapes "^3.1.0" 12171 12236 cross-spawn "^6.0.5" 12172 12237 12238 + patch-package@^6.5.1: 12239 + version "6.5.1" 12240 + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621" 12241 + integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA== 12242 + dependencies: 12243 + "@yarnpkg/lockfile" "^1.1.0" 12244 + chalk "^4.1.2" 12245 + cross-spawn "^6.0.5" 12246 + find-yarn-workspace-root "^2.0.0" 12247 + fs-extra "^9.0.0" 12248 + is-ci "^2.0.0" 12249 + klaw-sync "^6.0.0" 12250 + minimist "^1.2.6" 12251 + open "^7.4.2" 12252 + rimraf "^2.6.3" 12253 + semver "^5.6.0" 12254 + slash "^2.0.0" 12255 + tmp "^0.0.33" 12256 + yaml "^1.10.2" 12257 + 12173 12258 path-browserify@^1.0.0: 12174 12259 version "1.0.1" 12175 12260 resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" ··· 12981 13066 dependencies: 12982 13067 xtend "^4.0.0" 12983 13068 13069 + postinstall-postinstall@^2.1.0: 13070 + version "2.1.0" 13071 + resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" 13072 + integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== 13073 + 12984 13074 prebuild-install@^7.1.0, prebuild-install@^7.1.1: 12985 13075 version "7.1.1" 12986 13076 resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" ··· 13288 13378 prosemirror-model "^1.0.0" 13289 13379 13290 13380 prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.28.2: 13291 - version "1.30.1" 13292 - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.30.1.tgz#7cf0ae8dc8553a02c32961e82eca25079c4d8fc9" 13293 - integrity sha512-pZUfr7lICJkEY7XwzldAKrkflZDeIvnbfuu2RIS01N5NwJmR/dfZzDzJRzhb3SM2QtT/bM8b4Nnib8X3MGpAhA== 13381 + version "1.30.2" 13382 + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.30.2.tgz#57a9d15c5baa454f0d0f4a3028ddbd9be1e8ed9b" 13383 + integrity sha512-nTNzZvalQf9kHeEyO407LiV6DoOs/pXsid88UqW9Vvybo4ozJW2PJhkfZUxCUF1hR/9vJLdhxX84wuw9P9HsXA== 13294 13384 dependencies: 13295 13385 prosemirror-model "^1.16.0" 13296 13386 prosemirror-state "^1.0.0" ··· 13328 13418 integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== 13329 13419 13330 13420 pure-rand@^6.0.0: 13331 - version "6.0.0" 13332 - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.0.tgz#701996ceefa253507923a0e864c17ab421c04a7c" 13333 - integrity sha512-rLSBxJjP+4DQOgcJAx6RZHT2he2pkhQdSnofG5VWyVl6GRq/K02ISOuOLcsMOrtKDIJb8JN2zm3FFzWNbezdPw== 13421 + version "6.0.1" 13422 + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.1.tgz#31207dddd15d43f299fdcdb2f572df65030c19af" 13423 + integrity sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg== 13334 13424 13335 13425 q@^1.1.2: 13336 13426 version "1.5.1" ··· 13538 13628 integrity sha512-0hPVyf5yLxCSVrrNEuGqN1ZnSSj3Ye2gZex0NtcK/AHYwMc0rXWFNZjBKOoZSouspqu3hXBbQ6NOUSTzrME1AQ== 13539 13629 13540 13630 react-native-background-fetch@^4.1.8: 13541 - version "4.1.8" 13542 - resolved "https://registry.yarnpkg.com/react-native-background-fetch/-/react-native-background-fetch-4.1.8.tgz#a21858e5d876de8d9d15a37f40714b244f73713c" 13543 - integrity sha512-/qe86laa0n4AbD6mrLL8SCGR+K5693URX95e02/bTJh3UkdS3+sU1Jyc/XTlz4MQwlquI929/lm5EZh8AOUqzQ== 13631 + version "4.1.9" 13632 + resolved "https://registry.yarnpkg.com/react-native-background-fetch/-/react-native-background-fetch-4.1.9.tgz#10ebff9ca45a8868f1a72b2aa6cea40d499ece6e" 13633 + integrity sha512-sk4MCXRhGghBXu9ReabuT8U0WRzjsMt2i/nqCwR9eHi0hux+4kUh5ubpLKLByw5G8WifUv1sp6qsA7uvQERrrQ== 13544 13634 13545 13635 react-native-codegen@^0.71.5: 13546 13636 version "0.71.5" ··· 13618 13708 resolved "https://registry.yarnpkg.com/react-native-linear-gradient/-/react-native-linear-gradient-2.6.2.tgz#56598a76832724b2afa7889747635b5c80948f38" 13619 13709 integrity sha512-Z8Xxvupsex+9BBFoSYS87bilNPWcRfRsGC0cpJk72Nxb5p2nEkGSBv73xZbEHnW2mUFvP+huYxrVvjZkr/gRjQ== 13620 13710 13711 + react-native-pager-view@6.1.2: 13712 + version "6.1.2" 13713 + resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-6.1.2.tgz#3522079b9a9d6634ca5e8d153bc0b4d660254552" 13714 + integrity sha512-qs2KSFc+7N7B+UZ6SG2sTvCkppagm5fVyRclv1KFKc7lDtrhXLzN59tXJw575LDP/dRJoXsNwqUAhZJdws6ABQ== 13715 + 13621 13716 react-native-progress@bluesky-social/react-native-progress: 13622 13717 version "5.0.0" 13623 13718 resolved "https://codeload.github.com/bluesky-social/react-native-progress/tar.gz/5a372f4f2ce5feb26f4f47b6a4d187ab9b923ab4" ··· 13660 13755 resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.3.0.tgz#3af71ed17afe50fee69590a45aec399d071ead02" 13661 13756 integrity sha512-rGjt6HkoSXxMqH4SQUJ1gnPQlPJV8+J47+4yhgTIan4bVvAwJhEeJH7wWt9hXSdH4+VfwTS0GTaflj1Tw83IhA== 13662 13757 13663 - react-native-svg@^13.4.0: 13664 - version "13.8.0" 13665 - resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-13.8.0.tgz#b6a22cf77f8098f910490a13aeb160a37e182f97" 13666 - integrity sha512-G8Mx6W86da+vFimZBJvA93POw8yz0fgDS5biy6oIjMWVJVQSDzCyzwO/zY0yuZmCDhKSZzogl5m0wXXvW2OcTA== 13758 + react-native-svg@13.4.0: 13759 + version "13.4.0" 13760 + resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-13.4.0.tgz#82399ba0956c454144618aa581e2d748dd3f010a" 13761 + integrity sha512-B3TwK+H0+JuRhYPzF21AgqMt4fjhCwDZ9QUtwNstT5XcslJBXC0FoTkdZo8IEb1Sv4suSqhZwlAY6lwOv3tHag== 13667 13762 dependencies: 13668 13763 css-select "^5.1.0" 13669 13764 css-tree "^1.1.3" 13670 - 13671 - react-native-tab-view@^3.3.0: 13672 - version "3.5.1" 13673 - resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.5.1.tgz#2ad454afc0e186b43ea8b89053f39180d480d48b" 13674 - integrity sha512-qdrS5t+AEhfuKQyuCXkwHu4IVppkuTvzWWlkSZKrPaSkjjIa32xrsGxt1UW9YDdro2w4AMw5hKn1hFmg/5mvzA== 13675 - dependencies: 13676 - use-latest-callback "^0.1.5" 13677 13765 13678 13766 react-native-url-polyfill@^1.3.0: 13679 13767 version "1.3.0" ··· 13717 13805 postcss-value-parser "^4.2.0" 13718 13806 styleq "^0.1.2" 13719 13807 13720 - react-native-webview@^11.26.1: 13721 - version "11.26.1" 13722 - resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.26.1.tgz#658c09ed5162dc170b361e48c2dd26c9712879da" 13723 - integrity sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw== 13808 + react-native-webview@11.26.0: 13809 + version "11.26.0" 13810 + resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.26.0.tgz#e524992876fe4a79e69905f0fab8949b470e9f16" 13811 + integrity sha512-4T4CKRm8xlaQDz9h/bCMPGAvtkesrhkRWqCX9FDJEzBToaVUIsV0ZOqtC4w/JSnCtFKKYiaC1ReJtCGv+4mFeQ== 13724 13812 dependencies: 13725 13813 escape-string-regexp "2.0.0" 13726 13814 invariant "2.2.4" ··· 13882 13970 util-deprecate "~1.0.1" 13883 13971 13884 13972 readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: 13885 - version "3.6.1" 13886 - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62" 13887 - integrity sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ== 13973 + version "3.6.2" 13974 + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" 13975 + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== 13888 13976 dependencies: 13889 13977 inherits "^2.0.3" 13890 13978 string_decoder "^1.1.1" ··· 14002 14090 define-properties "^1.1.3" 14003 14091 functions-have-names "^1.2.2" 14004 14092 14005 - regexpp@^3.2.0: 14006 - version "3.2.0" 14007 - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" 14008 - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== 14009 - 14010 14093 regexpu-core@^5.3.1: 14011 - version "5.3.1" 14012 - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.1.tgz#66900860f88def39a5cb79ebd9490e84f17bcdfb" 14013 - integrity sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ== 14094 + version "5.3.2" 14095 + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" 14096 + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== 14014 14097 dependencies: 14015 14098 "@babel/regjsgen" "^0.8.0" 14016 14099 regenerate "^1.4.2" ··· 14346 14429 ret "~0.1.10" 14347 14430 14348 14431 safe-stable-stringify@^2.3.1, safe-stable-stringify@^2.4.1: 14349 - version "2.4.2" 14350 - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz#ec7b037768098bf65310d1d64370de0dc02353aa" 14351 - integrity sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA== 14432 + version "2.4.3" 14433 + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" 14434 + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== 14352 14435 14353 14436 "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": 14354 14437 version "2.1.2" ··· 14685 14768 version "1.0.5" 14686 14769 resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" 14687 14770 integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== 14771 + 14772 + slash@^2.0.0: 14773 + version "2.0.0" 14774 + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" 14775 + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== 14688 14776 14689 14777 slash@^3.0.0: 14690 14778 version "3.0.0" ··· 15023 15111 regexp.prototype.flags "^1.4.3" 15024 15112 side-channel "^1.0.4" 15025 15113 15114 + string.prototype.trim@^1.2.7: 15115 + version "1.2.7" 15116 + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" 15117 + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== 15118 + dependencies: 15119 + call-bind "^1.0.2" 15120 + define-properties "^1.1.4" 15121 + es-abstract "^1.20.4" 15122 + 15026 15123 string.prototype.trimend@^1.0.6: 15027 15124 version "1.0.6" 15028 15125 resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" ··· 15146 15243 integrity sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg== 15147 15244 15148 15245 style-loader@^3.3.1: 15149 - version "3.3.1" 15150 - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575" 15151 - integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ== 15246 + version "3.3.2" 15247 + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.2.tgz#eaebca714d9e462c19aa1e3599057bc363924899" 15248 + integrity sha512-RHs/vcrKdQK8wZliteNK4NKzxvLBzpuHMqYmUVWeKa6MkaIQ97ZTOS0b+zapZhy6GcrgWnvWYCMHRirC3FsUmw== 15152 15249 15153 15250 stylehacks@^5.1.1: 15154 15251 version "5.1.1" ··· 15428 15525 terser "^5.16.5" 15429 15526 15430 15527 terser@^5.0.0, terser@^5.10.0, terser@^5.15.0, terser@^5.16.5: 15431 - version "5.16.5" 15432 - resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.5.tgz#1c285ca0655f467f92af1bbab46ab72d1cb08e5a" 15433 - integrity sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg== 15528 + version "5.16.6" 15529 + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.6.tgz#f6c7a14a378ee0630fbe3ac8d1f41b4681109533" 15530 + integrity sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg== 15434 15531 dependencies: 15435 15532 "@jridgewell/source-map" "^0.3.2" 15436 15533 acorn "^8.5.0" ··· 15513 15610 "@popperjs/core" "^2.9.0" 15514 15611 15515 15612 tlds@^1.234.0: 15516 - version "1.237.0" 15517 - resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.237.0.tgz#71e5ca558878a046bc9e253db7a1f2b602ce1a2d" 15518 - integrity sha512-4IA6zR7jQop4pEdziQaptOgkIwnnZ537fXM3MKAzOXjXLjiHm77SA3/E0nXWJGSVRnKcn/JxDJmwTqyPgQ+ozg== 15613 + version "1.238.0" 15614 + resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.238.0.tgz#ffe7c19c8940c35b497cda187a6927f9450325a4" 15615 + integrity sha512-lFPF9pZFhLrPodaJ0wt9QIN0l8jOxqmUezGZnm7BfkDSVd9q667oVIJukLVzhF+4oW7uDlrLlfJrL5yu9RWwew== 15519 15616 15520 15617 tmp@^0.0.33: 15521 15618 version "0.0.33" ··· 15588 15685 punycode "^2.1.1" 15589 15686 universalify "^0.2.0" 15590 15687 url-parse "^1.5.3" 15688 + 15689 + toygrad@^2.6.0: 15690 + version "2.6.0" 15691 + resolved "https://registry.yarnpkg.com/toygrad/-/toygrad-2.6.0.tgz#e814bb7da026db8e08dc7da14c7155f49cdb4d54" 15692 + integrity sha512-g4zBmlSbvzOE5FOILxYkAybTSxijKLkj1WoNqVGnbMcWDyj4wWQ+eYSr3ik7XOpIgMq/7eBcPRTJX3DM2E0YMg== 15591 15693 15592 15694 tr46@^1.0.1: 15593 15695 version "1.0.1" ··· 16033 16135 resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" 16034 16136 integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== 16035 16137 16138 + uuid@^9.0.0: 16139 + version "9.0.0" 16140 + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" 16141 + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== 16142 + 16036 16143 v8-to-istanbul@^8.1.0: 16037 16144 version "8.1.1" 16038 16145 resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" ··· 16194 16301 schema-utils "^4.0.0" 16195 16302 16196 16303 webpack-dev-server@^4.11.1, webpack-dev-server@^4.6.0: 16197 - version "4.11.1" 16198 - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz#ae07f0d71ca0438cf88446f09029b92ce81380b5" 16199 - integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw== 16304 + version "4.13.1" 16305 + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.13.1.tgz#6417a9b5d2f528e7644b68d6ed335e392dccffe8" 16306 + integrity sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA== 16200 16307 dependencies: 16201 16308 "@types/bonjour" "^3.5.9" 16202 16309 "@types/connect-history-api-fallback" "^1.3.5" ··· 16217 16324 html-entities "^2.3.2" 16218 16325 http-proxy-middleware "^2.0.3" 16219 16326 ipaddr.js "^2.0.1" 16327 + launch-editor "^2.6.0" 16220 16328 open "^8.0.9" 16221 16329 p-retry "^4.5.0" 16222 16330 rimraf "^3.0.2" ··· 16226 16334 sockjs "^0.3.24" 16227 16335 spdy "^4.0.2" 16228 16336 webpack-dev-middleware "^5.3.1" 16229 - ws "^8.4.2" 16337 + ws "^8.13.0" 16230 16338 16231 16339 webpack-manifest-plugin@^4.0.2, webpack-manifest-plugin@^4.1.1: 16232 16340 version "4.1.1" ··· 16266 16374 integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== 16267 16375 16268 16376 webpack@^5.64.4, webpack@^5.75.0: 16269 - version "5.76.0" 16270 - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.0.tgz#f9fb9fb8c4a7dbdcd0d56a98e56b8a942ee2692c" 16271 - integrity sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA== 16377 + version "5.76.2" 16378 + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.76.2.tgz#6f80d1c1d1e3bf704db571b2504a0461fac80230" 16379 + integrity sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w== 16272 16380 dependencies: 16273 16381 "@types/eslint-scope" "^3.7.3" 16274 16382 "@types/estree" "^0.0.51" ··· 16444 16552 integrity sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg== 16445 16553 16446 16554 wonka@^6.1.2: 16447 - version "6.2.3" 16448 - resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.2.3.tgz#88f7852a23a3d53bca7411c70d66e9ce8f93a366" 16449 - integrity sha512-EFOYiqDeYLXSzGYt2X3aVe9Hq1XJG+Hz/HjTRRT4dZE9q95khHl5+7pzUSXI19dbMO1/2UMrTf7JT7/7JrSQSQ== 16555 + version "6.2.5" 16556 + resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.2.5.tgz#26e54a6827b96a6164b845106f4d925ede4089bb" 16557 + integrity sha512-adhGYKm5xWIZYXRkzEqHbRbRl2gXHqOudjQJMXpRgSyboFmaKOjGm3RIThBk4tZdiZx1DXuKK0H9wKBgXHhzZg== 16450 16558 16451 16559 word-wrap@^1.2.3, word-wrap@~1.2.3: 16452 16560 version "1.2.3" ··· 16689 16797 resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" 16690 16798 integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== 16691 16799 16692 - ws@^8.11.0, ws@^8.4.2: 16693 - version "8.12.1" 16694 - resolved "https://registry.yarnpkg.com/ws/-/ws-8.12.1.tgz#c51e583d79140b5e42e39be48c934131942d4a8f" 16695 - integrity sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew== 16800 + ws@^8.11.0, ws@^8.13.0: 16801 + version "8.13.0" 16802 + resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" 16803 + integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== 16696 16804 16697 16805 xcode@^3.0.0, xcode@^3.0.1: 16698 16806 version "3.0.1"