[Contacts] NUXes (#9515)
* add a bunch of number parsing logic with libphonenumber * add banner nux * add announcement nux * native only nux * rm shitty animation * move isNative check
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
+1
-1
@@ -75,7 +75,7 @@
|
|||||||
"@atproto/api": "^0.18.6",
|
"@atproto/api": "^0.18.6",
|
||||||
"@bitdrift/react-native": "^0.6.8",
|
"@bitdrift/react-native": "^0.6.8",
|
||||||
"@braintree/sanitize-url": "^6.0.2",
|
"@braintree/sanitize-url": "^6.0.2",
|
||||||
"@bsky.app/alf": "^0.1.5",
|
"@bsky.app/alf": "^0.1.6",
|
||||||
"@bsky.app/react-native-mmkv": "2.12.5",
|
"@bsky.app/react-native-mmkv": "2.12.5",
|
||||||
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
||||||
"@emoji-mart/react": "^1.1.1",
|
"@emoji-mart/react": "^1.1.1",
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export function Outer({
|
|||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
noBottomBorder?: boolean
|
noBottomBorder?: boolean
|
||||||
headerRef?: React.MutableRefObject<View | null>
|
headerRef?: React.RefObject<View | null>
|
||||||
sticky?: boolean
|
sticky?: boolean
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
@@ -183,7 +183,7 @@ export function TitleText({
|
|||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
a.text_lg,
|
a.text_lg,
|
||||||
a.font_bold,
|
a.font_semi_bold,
|
||||||
a.leading_tight,
|
a.leading_tight,
|
||||||
isIOS && align === 'platform' && a.text_center,
|
isIOS && align === 'platform' && a.text_center,
|
||||||
gtMobile && a.text_xl,
|
gtMobile && a.text_xl,
|
||||||
|
|||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import {useMemo} from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {Image} from 'expo-image'
|
||||||
|
import {LinearGradient} from 'expo-linear-gradient'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {HITSLOP_10} from '#/lib/constants'
|
||||||
|
import {isWeb} from '#/platform/detection'
|
||||||
|
import {Nux, useNux, useSaveNux} from '#/state/queries/nuxs'
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
|
import {Button} from '#/components/Button'
|
||||||
|
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import {Link} from '../Link'
|
||||||
|
|
||||||
|
export function FindContactsBannerNUX() {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const {visible, close} = useInternalState()
|
||||||
|
|
||||||
|
if (!visible) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[a.w_full, a.p_lg, a.border_b, t.atoms.border_contrast_low]}>
|
||||||
|
<View style={a.w_full}>
|
||||||
|
<Link
|
||||||
|
to={{screen: 'FindContactsFlow'}}
|
||||||
|
label={_(msg`Import contacts to find your friends`)}
|
||||||
|
style={[
|
||||||
|
a.w_full,
|
||||||
|
a.rounded_xl,
|
||||||
|
a.curve_continuous,
|
||||||
|
a.overflow_hidden,
|
||||||
|
]}>
|
||||||
|
<LinearGradient
|
||||||
|
colors={[t.palette.primary_200, t.palette.primary_50]}
|
||||||
|
start={{x: 0, y: 0.5}}
|
||||||
|
end={{x: 1, y: 0.5}}
|
||||||
|
style={[
|
||||||
|
a.w_full,
|
||||||
|
a.h_full,
|
||||||
|
a.flex_row,
|
||||||
|
a.align_center,
|
||||||
|
a.gap_lg,
|
||||||
|
a.pl_lg,
|
||||||
|
]}>
|
||||||
|
<Image
|
||||||
|
source={require('../../../assets/images/find_friends_illustration_small.webp')}
|
||||||
|
accessibilityIgnoresInvertColors
|
||||||
|
style={[
|
||||||
|
{height: 70, aspectRatio: 573 / 286},
|
||||||
|
a.self_end,
|
||||||
|
a.mt_sm,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<View style={[a.flex_1, a.justify_center, a.py_xl, a.pr_5xl]}>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_md,
|
||||||
|
a.font_bold,
|
||||||
|
{color: t.palette.primary_900},
|
||||||
|
]}>
|
||||||
|
<Trans>Import contacts to find your friends</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</LinearGradient>
|
||||||
|
</Link>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Dismiss banner`)}
|
||||||
|
hitSlop={HITSLOP_10}
|
||||||
|
onPress={close}
|
||||||
|
style={[a.absolute, {top: 14, right: 14}]}
|
||||||
|
hoverStyle={[a.bg_transparent, {opacity: 0.5}]}>
|
||||||
|
<XIcon size="xs" style={[t.atoms.text_contrast_low]} />
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
function useInternalState() {
|
||||||
|
const {nux} = useNux(Nux.FindContactsDismissibleBanner)
|
||||||
|
const {mutate: save, variables} = useSaveNux()
|
||||||
|
const hidden = !!variables
|
||||||
|
|
||||||
|
const visible = useMemo(() => {
|
||||||
|
if (isWeb) return false
|
||||||
|
if (hidden) return false
|
||||||
|
if (nux && nux.completed) return false
|
||||||
|
return true
|
||||||
|
}, [hidden, nux])
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
save({
|
||||||
|
id: Nux.FindContactsDismissibleBanner,
|
||||||
|
completed: true,
|
||||||
|
data: undefined,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {visible, close}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export function SyncContactsFlow() {
|
||||||
|
throw new Error('SyncContactsFlow is not available on web')
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import {useCallback} from 'react'
|
||||||
|
import {View} from 'react-native'
|
||||||
|
import {Image} from 'expo-image'
|
||||||
|
import {LinearGradient} from 'expo-linear-gradient'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {isWeb} from '#/platform/detection'
|
||||||
|
import {atoms as a, useTheme, web} from '#/alf'
|
||||||
|
import {Button, ButtonText} from '#/components/Button'
|
||||||
|
import * as Dialog from '#/components/Dialog'
|
||||||
|
import {useNuxDialogContext} from '#/components/dialogs/nuxs'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
import {navigate} from '#/Navigation'
|
||||||
|
|
||||||
|
export function FindContactsAnnouncement() {
|
||||||
|
const t = useTheme()
|
||||||
|
const {_} = useLingui()
|
||||||
|
const nuxDialogs = useNuxDialogContext()
|
||||||
|
const control = Dialog.useDialogControl()
|
||||||
|
|
||||||
|
Dialog.useAutoOpen(control)
|
||||||
|
|
||||||
|
const onClose = useCallback(() => {
|
||||||
|
nuxDialogs.dismissActiveNux()
|
||||||
|
}, [nuxDialogs])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog.Outer
|
||||||
|
control={control}
|
||||||
|
onClose={onClose}
|
||||||
|
nativeOptions={{preventExpansion: true}}>
|
||||||
|
<Dialog.Handle />
|
||||||
|
|
||||||
|
<Dialog.ScrollableInner
|
||||||
|
label={_(msg`Introducing finding friends via contacts`)}
|
||||||
|
style={[web({maxWidth: 440})]}
|
||||||
|
contentContainerStyle={[
|
||||||
|
{
|
||||||
|
paddingTop: 0,
|
||||||
|
paddingLeft: 0,
|
||||||
|
paddingRight: 0,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<View style={[a.align_center, a.pt_3xl]}>
|
||||||
|
<LinearGradient
|
||||||
|
colors={[t.palette.primary_200, t.atoms.bg.backgroundColor]}
|
||||||
|
locations={[0, 1]}
|
||||||
|
start={{x: 0, y: 0}}
|
||||||
|
end={{x: 0, y: 1}}
|
||||||
|
style={[a.absolute, a.inset_0]}
|
||||||
|
/>
|
||||||
|
<View style={[a.w_full, a.pt_sm, a.px_5xl, a.pb_4xl]}>
|
||||||
|
<Image
|
||||||
|
accessibilityIgnoresInvertColors
|
||||||
|
source={require('../../../../assets/images/find_friends_illustration.webp')}
|
||||||
|
style={[a.w_full, {aspectRatio: 1278 / 661}]}
|
||||||
|
alt={_(
|
||||||
|
msg`An illustration depicting user avatars flowing from a contact book into the Bluesky app`,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={[a.align_center, a.px_xl, a.gap_5xl]}>
|
||||||
|
<View style={[a.gap_sm, a.align_center]}>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_4xl,
|
||||||
|
a.leading_tight,
|
||||||
|
a.font_bold,
|
||||||
|
a.text_center,
|
||||||
|
{
|
||||||
|
fontSize: isWeb ? 28 : 32,
|
||||||
|
maxWidth: 300,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Trans>Find your friends</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.text_md,
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
a.leading_snug,
|
||||||
|
a.text_center,
|
||||||
|
{maxWidth: 340},
|
||||||
|
]}>
|
||||||
|
<Trans>
|
||||||
|
Bluesky is more fun with friends! Import your contacts to see
|
||||||
|
who’s already here.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
label={_(msg`Import Contacts`)}
|
||||||
|
size="large"
|
||||||
|
color="primary"
|
||||||
|
onPress={() => {
|
||||||
|
control.close(() => {
|
||||||
|
navigate('FindContactsFlow')
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
style={[a.w_full]}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Import Contacts</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Dialog.Close />
|
||||||
|
</Dialog.ScrollableInner>
|
||||||
|
</Dialog.Outer>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,8 +1,16 @@
|
|||||||
import React from 'react'
|
import {
|
||||||
|
createContext,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
import {type AppBskyActorDefs} from '@atproto/api'
|
import {type AppBskyActorDefs} from '@atproto/api'
|
||||||
|
|
||||||
import {useGate} from '#/lib/statsig/statsig'
|
import {useGate} from '#/lib/statsig/statsig'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
import {isNative} from '#/platform/detection'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs'
|
import {Nux, useNuxs, useResetNuxs, useSaveNux} from '#/state/queries/nuxs'
|
||||||
import {
|
import {
|
||||||
@@ -12,11 +20,11 @@ import {
|
|||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {type SessionAccount, useSession} from '#/state/session'
|
import {type SessionAccount, useSession} from '#/state/session'
|
||||||
import {useOnboardingState} from '#/state/shell'
|
import {useOnboardingState} from '#/state/shell'
|
||||||
import {BookmarksAnnouncement} from '#/components/dialogs/nuxs/BookmarksAnnouncement'
|
import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
|
||||||
/*
|
/*
|
||||||
* NUXs
|
* NUXs
|
||||||
*/
|
*/
|
||||||
import {isSnoozed, snooze, unsnooze} from '#/components/dialogs/nuxs/snoozing'
|
import {FindContactsAnnouncement} from './FindContactsAnnouncement'
|
||||||
import {isExistingUserAsOf} from './utils'
|
import {isExistingUserAsOf} from './utils'
|
||||||
|
|
||||||
type Context = {
|
type Context = {
|
||||||
@@ -34,24 +42,24 @@ const queuedNuxs: {
|
|||||||
}) => boolean
|
}) => boolean
|
||||||
}[] = [
|
}[] = [
|
||||||
{
|
{
|
||||||
id: Nux.BookmarksAnnouncement,
|
id: Nux.FindContactsAnnouncement,
|
||||||
enabled: ({currentProfile}) => {
|
enabled: ({currentProfile}) => {
|
||||||
return isExistingUserAsOf(
|
return (
|
||||||
'2025-09-08T00:00:00.000Z',
|
isNative &&
|
||||||
currentProfile.createdAt,
|
isExistingUserAsOf('2025-12-16T00:00:00.000Z', currentProfile.createdAt)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const Context = React.createContext<Context>({
|
const Context = createContext<Context>({
|
||||||
activeNux: undefined,
|
activeNux: undefined,
|
||||||
dismissActiveNux: () => {},
|
dismissActiveNux: () => {},
|
||||||
})
|
})
|
||||||
Context.displayName = 'NuxDialogContext'
|
Context.displayName = 'NuxDialogContext'
|
||||||
|
|
||||||
export function useNuxDialogContext() {
|
export function useNuxDialogContext() {
|
||||||
return React.useContext(Context)
|
return useContext(Context)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NuxDialogs() {
|
export function NuxDialogs() {
|
||||||
@@ -92,19 +100,19 @@ function Inner({
|
|||||||
}) {
|
}) {
|
||||||
const gate = useGate()
|
const gate = useGate()
|
||||||
const {nuxs} = useNuxs()
|
const {nuxs} = useNuxs()
|
||||||
const [snoozed, setSnoozed] = React.useState(() => {
|
const [snoozed, setSnoozed] = useState(() => {
|
||||||
return isSnoozed()
|
return isSnoozed()
|
||||||
})
|
})
|
||||||
const [activeNux, setActiveNux] = React.useState<Nux | undefined>()
|
const [activeNux, setActiveNux] = useState<Nux | undefined>()
|
||||||
const {mutateAsync: saveNux} = useSaveNux()
|
const {mutateAsync: saveNux} = useSaveNux()
|
||||||
const {mutate: resetNuxs} = useResetNuxs()
|
const {mutate: resetNuxs} = useResetNuxs()
|
||||||
|
|
||||||
const snoozeNuxDialog = React.useCallback(() => {
|
const snoozeNuxDialog = useCallback(() => {
|
||||||
snooze()
|
snooze()
|
||||||
setSnoozed(true)
|
setSnoozed(true)
|
||||||
}, [setSnoozed])
|
}, [setSnoozed])
|
||||||
|
|
||||||
const dismissActiveNux = React.useCallback(() => {
|
const dismissActiveNux = useCallback(() => {
|
||||||
if (!activeNux) return
|
if (!activeNux) return
|
||||||
setActiveNux(undefined)
|
setActiveNux(undefined)
|
||||||
}, [activeNux, setActiveNux])
|
}, [activeNux, setActiveNux])
|
||||||
@@ -118,7 +126,7 @@ function Inner({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
useEffect(() => {
|
||||||
if (snoozed) return // comment this out to test
|
if (snoozed) return // comment this out to test
|
||||||
if (!nuxs) return
|
if (!nuxs) return
|
||||||
|
|
||||||
@@ -170,7 +178,7 @@ function Inner({
|
|||||||
preferences,
|
preferences,
|
||||||
])
|
])
|
||||||
|
|
||||||
const ctx = React.useMemo(() => {
|
const ctx = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
activeNux,
|
activeNux,
|
||||||
dismissActiveNux,
|
dismissActiveNux,
|
||||||
@@ -180,7 +188,9 @@ function Inner({
|
|||||||
return (
|
return (
|
||||||
<Context.Provider value={ctx}>
|
<Context.Provider value={ctx}>
|
||||||
{/*For example, activeNux === Nux.NeueTypography && <NeueTypography />*/}
|
{/*For example, activeNux === Nux.NeueTypography && <NeueTypography />*/}
|
||||||
{activeNux === Nux.BookmarksAnnouncement && <BookmarksAnnouncement />}
|
{activeNux === Nux.FindContactsAnnouncement && (
|
||||||
|
<FindContactsAnnouncement />
|
||||||
|
)}
|
||||||
</Context.Provider>
|
</Context.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export enum Nux {
|
|||||||
AgeAssuranceDismissibleNotice = 'AgeAssuranceDismissibleNotice',
|
AgeAssuranceDismissibleNotice = 'AgeAssuranceDismissibleNotice',
|
||||||
AgeAssuranceDismissibleFeedBanner = 'AgeAssuranceDismissibleFeedBanner',
|
AgeAssuranceDismissibleFeedBanner = 'AgeAssuranceDismissibleFeedBanner',
|
||||||
BookmarksAnnouncement = 'BookmarksAnnouncement',
|
BookmarksAnnouncement = 'BookmarksAnnouncement',
|
||||||
|
FindContactsAnnouncement = 'FindContactsAnnouncement',
|
||||||
|
FindContactsDismissibleBanner = 'FindContactsDismissibleBanner',
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Blocking announcements. New IDs are required for each new announcement.
|
* Blocking announcements. New IDs are required for each new announcement.
|
||||||
@@ -52,6 +54,14 @@ export type AppNux = BaseNux<
|
|||||||
id: Nux.BookmarksAnnouncement
|
id: Nux.BookmarksAnnouncement
|
||||||
data: undefined
|
data: undefined
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
id: Nux.FindContactsAnnouncement
|
||||||
|
data: undefined
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id: Nux.FindContactsDismissibleBanner
|
||||||
|
data: undefined
|
||||||
|
}
|
||||||
>
|
>
|
||||||
|
|
||||||
export const NuxSchemas: Record<Nux, zod.ZodObject<any> | undefined> = {
|
export const NuxSchemas: Record<Nux, zod.ZodObject<any> | undefined> = {
|
||||||
@@ -63,4 +73,6 @@ export const NuxSchemas: Record<Nux, zod.ZodObject<any> | undefined> = {
|
|||||||
[Nux.AgeAssuranceDismissibleFeedBanner]: undefined,
|
[Nux.AgeAssuranceDismissibleFeedBanner]: undefined,
|
||||||
[Nux.PolicyUpdate202508]: undefined,
|
[Nux.PolicyUpdate202508]: undefined,
|
||||||
[Nux.BookmarksAnnouncement]: undefined,
|
[Nux.BookmarksAnnouncement]: undefined,
|
||||||
|
[Nux.FindContactsAnnouncement]: undefined,
|
||||||
|
[Nux.FindContactsDismissibleBanner]: undefined,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {isWeb} from '#/platform/detection'
|
|||||||
import {useProfileFollowsQuery} from '#/state/queries/profile-follows'
|
import {useProfileFollowsQuery} from '#/state/queries/profile-follows'
|
||||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
import {FindContactsBannerNUX} from '#/components/contacts/FindContactsBannerNUX'
|
||||||
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
|
import {PeopleRemove2_Stroke1_Corner0_Rounded as PeopleRemoveIcon} from '#/components/icons/PeopleRemove2'
|
||||||
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
|
||||||
import {List} from '../util/List'
|
import {List} from '../util/List'
|
||||||
@@ -208,6 +209,7 @@ export function ProfileFollows({name}: {name: string}) {
|
|||||||
onEndReached={onEndReached}
|
onEndReached={onEndReached}
|
||||||
onEndReachedThreshold={4}
|
onEndReachedThreshold={4}
|
||||||
onItemSeen={onItemSeen}
|
onItemSeen={onItemSeen}
|
||||||
|
ListHeaderComponent={<FindContactsBannerNUX />}
|
||||||
ListFooterComponent={
|
ListFooterComponent={
|
||||||
<ListFooter
|
<ListFooter
|
||||||
isFetchingNextPage={isFetchingNextPage}
|
isFetchingNextPage={isFetchingNextPage}
|
||||||
|
|||||||
@@ -3800,10 +3800,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783"
|
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz#923ca57e173c6b232bbbb07347b1be982f03e783"
|
||||||
integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==
|
integrity sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==
|
||||||
|
|
||||||
"@bsky.app/alf@^0.1.5":
|
"@bsky.app/alf@^0.1.6":
|
||||||
version "0.1.5"
|
version "0.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/@bsky.app/alf/-/alf-0.1.5.tgz#8de3e128a3a490625fa24dae89f8febfe4a668b2"
|
resolved "https://registry.yarnpkg.com/@bsky.app/alf/-/alf-0.1.6.tgz#256dac988702f076b98f1963c9d594141bc74a10"
|
||||||
integrity sha512-1FGsLTUxv4UpbO3tW/oXIEzR8If/FPkFwWkTOBvpcA9cfR73QZiXXitUojCZbiXEIl0WiL+8j3zHjpNaaxiOAA==
|
integrity sha512-8DdAOP+qRVgme+5WwqhxU20qzHXvEkEzr60SIBvDEVblCkyEiPZ36YznbpbmpT23qXbfbUFf9mb5IXYJqd8ELQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
react-responsive "^10.0.1"
|
react-responsive "^10.0.1"
|
||||||
|
|
||||||
@@ -14292,9 +14292,9 @@ levn@^0.4.1:
|
|||||||
type-check "~0.4.0"
|
type-check "~0.4.0"
|
||||||
|
|
||||||
libphonenumber-js@^1.12.30:
|
libphonenumber-js@^1.12.30:
|
||||||
version "1.12.31"
|
version "1.12.30"
|
||||||
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.12.31.tgz#3cdb45641c6b77228dd1238f3d810c3bb5d91199"
|
resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.12.30.tgz#8f37c6d0546e89a399085d329214a583642e611a"
|
||||||
integrity sha512-Z3IhgVgrqO1S5xPYM3K5XwbkDasU67/Vys4heW+lfSBALcUZjeIIzI8zCLifY+OCzSq+fpDdywMDa7z+4srJPQ==
|
integrity sha512-KxH7uIJFD6+cR6nhdh+wY6prFiH26A3W/W1gTMXnng2PXSwVfi5MhYkdq3Z2Y7vhBVa1/5VJgpNtI76UM2njGA==
|
||||||
|
|
||||||
lighthouse-logger@^1.0.0:
|
lighthouse-logger@^1.0.0:
|
||||||
version "1.4.2"
|
version "1.4.2"
|
||||||
|
|||||||
Reference in New Issue
Block a user