Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a06b58e831 | |||
| 48c53603d8 | |||
| 0bd1053798 | |||
| ce1f5a1f58 | |||
| 7bafcf1cc2 | |||
| 290b52fb04 |
@@ -127,6 +127,7 @@
|
||||
"bcp-47-match": "^2.0.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"deprecated-react-native-prop-types": "^5.0.0",
|
||||
"downshift": "^9.0.10",
|
||||
"email-validator": "^2.0.4",
|
||||
"emoji-mart": "^5.5.2",
|
||||
"emoji-regex": "^10.4.0",
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import React from 'react'
|
||||
import {TextInput, View} from 'react-native'
|
||||
import {
|
||||
type NativeSyntheticEvent,
|
||||
type TextInput,
|
||||
type TextInputKeyPressEventData,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
@@ -12,72 +16,91 @@ import {MagnifyingGlass2_Stroke2_Corner0_Rounded as MagnifyingGlassIcon} from '#
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times'
|
||||
|
||||
type SearchInputProps = Omit<TextField.InputProps, 'label'> & {
|
||||
ref?: React.Ref<TextInput>
|
||||
label?: TextField.InputProps['label']
|
||||
/**
|
||||
* Called when the user presses the (X) button
|
||||
*/
|
||||
onClearText?: () => void
|
||||
/**
|
||||
* Called when the user presses the Escape key
|
||||
*/
|
||||
onEscape?: () => void
|
||||
}
|
||||
|
||||
export const SearchInput = React.forwardRef<TextInput, SearchInputProps>(
|
||||
function SearchInput({value, label, onClearText, ...rest}, ref) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const showClear = value && value.length > 0
|
||||
export function SearchInput({
|
||||
ref,
|
||||
value,
|
||||
label,
|
||||
onClearText,
|
||||
onEscape,
|
||||
...rest
|
||||
}: SearchInputProps) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const showClear = value && value.length > 0
|
||||
|
||||
return (
|
||||
<View style={[a.w_full, a.relative]}>
|
||||
<TextField.Root>
|
||||
<TextField.Icon icon={MagnifyingGlassIcon} />
|
||||
<TextField.Input
|
||||
inputRef={ref}
|
||||
label={label || _(msg`Search`)}
|
||||
value={value}
|
||||
placeholder={_(msg`Search`)}
|
||||
returnKeyType="search"
|
||||
keyboardAppearance={t.scheme}
|
||||
selectTextOnFocus={isNative}
|
||||
autoFocus={false}
|
||||
accessibilityRole="search"
|
||||
autoCorrect={false}
|
||||
autoComplete="off"
|
||||
autoCapitalize="none"
|
||||
style={[
|
||||
showClear
|
||||
? {
|
||||
paddingRight: 24,
|
||||
}
|
||||
: {},
|
||||
]}
|
||||
{...rest}
|
||||
/>
|
||||
</TextField.Root>
|
||||
const onKeyPress = (
|
||||
evt: NativeSyntheticEvent<TextInputKeyPressEventData>,
|
||||
) => {
|
||||
if (evt.nativeEvent.key === 'Escape') {
|
||||
onEscape?.()
|
||||
}
|
||||
}
|
||||
|
||||
{showClear && (
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.z_20,
|
||||
a.my_auto,
|
||||
a.inset_0,
|
||||
a.justify_center,
|
||||
a.pr_sm,
|
||||
{left: 'auto'},
|
||||
]}>
|
||||
<Button
|
||||
testID="searchTextInputClearBtn"
|
||||
onPress={onClearText}
|
||||
label={_(msg`Clear search query`)}
|
||||
hitSlop={HITSLOP_10}
|
||||
size="tiny"
|
||||
shape="round"
|
||||
variant="ghost"
|
||||
color="secondary">
|
||||
<ButtonIcon icon={X} size="xs" />
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
},
|
||||
)
|
||||
return (
|
||||
<View style={[a.w_full, a.relative]}>
|
||||
<TextField.Root>
|
||||
<TextField.Icon icon={MagnifyingGlassIcon} />
|
||||
<TextField.Input
|
||||
inputRef={ref}
|
||||
label={label || _(msg`Search`)}
|
||||
value={value}
|
||||
placeholder={_(msg`Search`)}
|
||||
returnKeyType="search"
|
||||
keyboardAppearance={t.scheme}
|
||||
selectTextOnFocus={isNative}
|
||||
autoFocus={false}
|
||||
accessibilityRole="search"
|
||||
autoCorrect={false}
|
||||
autoComplete="off"
|
||||
autoCapitalize="none"
|
||||
onKeyPress={onKeyPress}
|
||||
style={[
|
||||
showClear
|
||||
? {
|
||||
paddingRight: 24,
|
||||
}
|
||||
: {},
|
||||
]}
|
||||
{...rest}
|
||||
/>
|
||||
</TextField.Root>
|
||||
|
||||
{showClear && (
|
||||
<View
|
||||
style={[
|
||||
a.absolute,
|
||||
a.z_20,
|
||||
a.my_auto,
|
||||
a.inset_0,
|
||||
a.justify_center,
|
||||
a.pr_sm,
|
||||
{left: 'auto'},
|
||||
]}>
|
||||
<Button
|
||||
testID="searchTextInputClearBtn"
|
||||
onPress={onClearText}
|
||||
label={_(msg`Clear search query`)}
|
||||
hitSlop={HITSLOP_10}
|
||||
size="tiny"
|
||||
shape="round"
|
||||
variant="ghost"
|
||||
color="secondary">
|
||||
<ButtonIcon icon={X} size="xs" />
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
memo,
|
||||
useCallback,
|
||||
useDeferredValue,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
@@ -75,9 +76,10 @@ export function SearchScreenShell({
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
// Query terms
|
||||
const [searchText, setSearchText] = useState<string>(queryParam)
|
||||
const [searchText, setSearchText] = useState(queryParam)
|
||||
const deferredSearchText = useDeferredValue(searchText)
|
||||
const {data: autocompleteData, isFetching: isAutocompleteFetching} =
|
||||
useActorAutocompleteQuery(searchText, true)
|
||||
useActorAutocompleteQuery(deferredSearchText, true)
|
||||
|
||||
const [showAutocomplete, setShowAutocomplete] = useState(false)
|
||||
|
||||
@@ -203,8 +205,8 @@ export function SearchScreenShell({
|
||||
}, [setShowAutocomplete, setSearchText, navigation, route.params, route.name])
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
navigateToItem(searchText)
|
||||
}, [navigateToItem, searchText])
|
||||
navigateToItem(deferredSearchText)
|
||||
}, [navigateToItem, deferredSearchText])
|
||||
|
||||
const onAutocompleteResultPress = useCallback(() => {
|
||||
if (isWeb) {
|
||||
@@ -376,11 +378,11 @@ export function SearchScreenShell({
|
||||
display: showAutocomplete && !fixedParams ? 'flex' : 'none',
|
||||
flex: 1,
|
||||
}}>
|
||||
{searchText.length > 0 ? (
|
||||
{deferredSearchText.length > 0 ? (
|
||||
<AutocompleteResults
|
||||
isAutocompleteFetching={isAutocompleteFetching}
|
||||
autocompleteData={autocompleteData}
|
||||
searchText={searchText}
|
||||
searchText={deferredSearchText}
|
||||
onSubmit={onSubmit}
|
||||
onResultPress={onAutocompleteResultPress}
|
||||
onProfileClick={handleProfileClick}
|
||||
@@ -428,7 +430,6 @@ let SearchScreenInner = ({
|
||||
const {hasSession} = useSession()
|
||||
const {gtTablet} = useBreakpoints()
|
||||
const [activeTab, setActiveTab] = useState(0)
|
||||
const {_} = useLingui()
|
||||
|
||||
const onPageSelected = useCallback(
|
||||
(index: number) => {
|
||||
|
||||
@@ -4,12 +4,11 @@ import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {SearchLinkCard} from '#/view/shell/desktop/Search'
|
||||
import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard'
|
||||
import {atoms as a, native} from '#/alf'
|
||||
import {atoms as a} from '#/alf'
|
||||
import * as Layout from '#/components/Layout'
|
||||
import {SearchLinkCard} from './SearchLinkCard'
|
||||
|
||||
let AutocompleteResults = ({
|
||||
isAutocompleteFetching,
|
||||
@@ -43,12 +42,8 @@ let AutocompleteResults = ({
|
||||
keyboardDismissMode="on-drag">
|
||||
<SearchLinkCard
|
||||
label={_(msg`Search for "${searchText}"`)}
|
||||
onPress={native(onSubmit)}
|
||||
to={
|
||||
isNative
|
||||
? undefined
|
||||
: `/search?q=${encodeURIComponent(searchText)}`
|
||||
}
|
||||
onPress={onSubmit}
|
||||
to={{screen: 'Search', params: {q: searchText}}}
|
||||
style={a.border_b}
|
||||
/>
|
||||
{autocompleteData?.map(item => (
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button} from '#/components/Button'
|
||||
import {type LinkProps} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function SearchLinkCard({
|
||||
label,
|
||||
onPress,
|
||||
style,
|
||||
}: {
|
||||
label: string
|
||||
/**
|
||||
* @platform web
|
||||
*/
|
||||
to: LinkProps['to']
|
||||
/**
|
||||
* @platform native
|
||||
*/
|
||||
onPress: () => void
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<Button label={label} onPress={onPress}>
|
||||
{({focused, hovered, pressed}) => (
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
t.atoms.border_contrast_low,
|
||||
a.p_lg,
|
||||
(focused || hovered || pressed) && t.atoms.bg_contrast_25,
|
||||
style,
|
||||
]}>
|
||||
<Text style={[a.text_sm, a.leading_snug]}>{label}</Text>
|
||||
</View>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {type StyleProp, View, type ViewStyle} from 'react-native'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Link, type LinkProps} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function SearchLinkCard({
|
||||
label,
|
||||
to,
|
||||
style,
|
||||
}: {
|
||||
label: string
|
||||
/**
|
||||
* @platform web
|
||||
*/
|
||||
to: LinkProps['to']
|
||||
/**
|
||||
* @platform native
|
||||
*/
|
||||
onPress: () => void
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<Link to={to} label={label}>
|
||||
{({focused, hovered, pressed}) => (
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
t.atoms.border_contrast_low,
|
||||
a.py_lg,
|
||||
a.px_md,
|
||||
(focused || hovered || pressed) && t.atoms.bg_contrast_25,
|
||||
style,
|
||||
]}>
|
||||
<Text style={[a.text_sm, a.leading_snug]}>{label}</Text>
|
||||
</View>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
+114
-118
@@ -1,167 +1,163 @@
|
||||
import React from 'react'
|
||||
import {useDeferredValue, useMemo, useRef, useState} from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
type StyleProp,
|
||||
type TextInput,
|
||||
View,
|
||||
type ViewStyle,
|
||||
} from 'react-native'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||
import {useCombobox} from 'downshift'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||
import {Link} from '#/view/com/util/Link'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {SearchProfileCard} from '#/screens/Search/components/SearchProfileCard'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {SearchInput} from '#/components/forms/SearchInput'
|
||||
import {MagnifyingGlass2_Stroke2_Corner0_Rounded as SearchIcon} from '#/components/icons/MagnifyingGlass2'
|
||||
import {Link, type LinkProps} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
let SearchLinkCard = ({
|
||||
function SearchLinkCard({
|
||||
label,
|
||||
to,
|
||||
onPress,
|
||||
style,
|
||||
}: {
|
||||
label: string
|
||||
to?: string
|
||||
onPress?: () => void
|
||||
style?: ViewStyle
|
||||
}): React.ReactNode => {
|
||||
const pal = usePalette('default')
|
||||
|
||||
const inner = (
|
||||
<View
|
||||
style={[pal.border, {paddingVertical: 16, paddingHorizontal: 12}, style]}>
|
||||
<Text type="md" style={[pal.text]}>
|
||||
{label}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
|
||||
if (onPress) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
accessibilityLabel={label}
|
||||
accessibilityHint="">
|
||||
{inner}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
to: LinkProps['to']
|
||||
style?: StyleProp<ViewStyle>
|
||||
}) {
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<Link href={to} asAnchor anchorNoUnderline>
|
||||
<View
|
||||
style={[
|
||||
pal.border,
|
||||
{paddingVertical: 16, paddingHorizontal: 12},
|
||||
style,
|
||||
]}>
|
||||
<Text type="md" style={[pal.text]}>
|
||||
{label}
|
||||
</Text>
|
||||
</View>
|
||||
<Link to={to} label={label}>
|
||||
{({focused, hovered, pressed}) => (
|
||||
<View
|
||||
style={[
|
||||
a.w_full,
|
||||
t.atoms.border_contrast_low,
|
||||
a.py_lg,
|
||||
a.px_md,
|
||||
(focused || hovered || pressed) && t.atoms.bg_contrast_25,
|
||||
style,
|
||||
]}>
|
||||
<Text style={[a.text_sm, a.leading_snug]}>{label}</Text>
|
||||
</View>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
SearchLinkCard = React.memo(SearchLinkCard)
|
||||
export {SearchLinkCard}
|
||||
|
||||
export function DesktopSearch() {
|
||||
const {_} = useLingui()
|
||||
const pal = usePalette('default')
|
||||
const t = useTheme()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const [isActive, setIsActive] = React.useState<boolean>(false)
|
||||
const [query, setQuery] = React.useState<string>('')
|
||||
const searchInputRef = useRef<TextInput>(null)
|
||||
const [query, setQuery] = useState('')
|
||||
const deferredQuery = useDeferredValue(query)
|
||||
const {data: autocompleteData, isFetching} = useActorAutocompleteQuery(
|
||||
query,
|
||||
deferredQuery,
|
||||
true,
|
||||
)
|
||||
|
||||
const items = useMemo(() => {
|
||||
if (deferredQuery.length === 0) return []
|
||||
return ['__TEXT__', ...(autocompleteData || [])]
|
||||
}, [deferredQuery, autocompleteData])
|
||||
|
||||
const {getInputProps, isOpen} = useCombobox({
|
||||
items,
|
||||
getItemId: index =>
|
||||
typeof items[index] === 'string' ? items[index] : items[index].did,
|
||||
})
|
||||
|
||||
const moderationOpts = useModerationOpts()
|
||||
|
||||
const onChangeText = React.useCallback((text: string) => {
|
||||
setQuery(text)
|
||||
setIsActive(text.length > 0)
|
||||
}, [])
|
||||
|
||||
const onPressCancelSearch = React.useCallback(() => {
|
||||
const onPressCancelSearch = () => {
|
||||
setQuery('')
|
||||
setIsActive(false)
|
||||
}, [setQuery])
|
||||
}
|
||||
|
||||
const onSubmit = React.useCallback(() => {
|
||||
setIsActive(false)
|
||||
if (!query.length) return
|
||||
navigation.dispatch(StackActions.push('Search', {q: query}))
|
||||
}, [query, navigation])
|
||||
|
||||
const onSearchProfileCardPress = React.useCallback(() => {
|
||||
const onEscape = () => {
|
||||
setQuery('')
|
||||
setIsActive(false)
|
||||
}, [])
|
||||
searchInputRef.current?.blur()
|
||||
}
|
||||
|
||||
const onSubmit = () => {
|
||||
if (!deferredQuery.length) return
|
||||
navigation.dispatch(StackActions.push('Search', {q: deferredQuery}))
|
||||
setQuery('')
|
||||
}
|
||||
|
||||
const onSearchProfileCardPress = () => {
|
||||
setQuery('')
|
||||
}
|
||||
|
||||
console.log(getInputProps())
|
||||
|
||||
return (
|
||||
<View style={[styles.container, pal.view]}>
|
||||
<View style={[a.w_full, a.z_10]}>
|
||||
<SearchInput
|
||||
value={query}
|
||||
onChangeText={onChangeText}
|
||||
ref={searchInputRef}
|
||||
onClearText={onPressCancelSearch}
|
||||
onEscape={onEscape}
|
||||
onSubmitEditing={onSubmit}
|
||||
{...getInputProps()}
|
||||
/>
|
||||
{query !== '' && isActive && moderationOpts && (
|
||||
<View
|
||||
style={[
|
||||
pal.view,
|
||||
pal.borderDark,
|
||||
styles.resultsContainer,
|
||||
a.overflow_hidden,
|
||||
]}>
|
||||
{isFetching && !autocompleteData?.length ? (
|
||||
<View style={{padding: 8}}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
<SearchLinkCard
|
||||
label={_(msg`Search for "${query}"`)}
|
||||
to={`/search?q=${encodeURIComponent(query)}`}
|
||||
style={
|
||||
(autocompleteData?.length ?? 0) > 0
|
||||
? {borderBottomWidth: 1}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
{autocompleteData?.map(item => (
|
||||
<SearchProfileCard
|
||||
key={item.did}
|
||||
profile={item}
|
||||
moderationOpts={moderationOpts}
|
||||
onPress={onSearchProfileCardPress}
|
||||
{isOpen && moderationOpts && (
|
||||
<View style={[a.w_full]}>
|
||||
<View
|
||||
style={[
|
||||
t.atoms.bg,
|
||||
t.atoms.border_contrast_low,
|
||||
a.w_full,
|
||||
a.border,
|
||||
a.mt_sm,
|
||||
a.rounded_sm,
|
||||
a.overflow_hidden,
|
||||
a.absolute,
|
||||
a.shadow_lg,
|
||||
a.zoom_fade_in,
|
||||
]}>
|
||||
{deferredQuery.length === 0 ? (
|
||||
<View style={[a.py_xl, a.gap_sm, a.align_center]}>
|
||||
<SearchIcon size="2xl" style={[t.atoms.text_contrast_low]} />
|
||||
<Text
|
||||
style={[a.text_sm, t.atoms.text_contrast_low, a.text_center]}>
|
||||
<Trans>Start typing to search</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<>
|
||||
<SearchLinkCard
|
||||
label={_(msg`Search for "${deferredQuery}"`)}
|
||||
to={{screen: 'Search', params: {q: deferredQuery}}}
|
||||
style={[
|
||||
((autocompleteData?.length ?? 0) > 0 || isFetching) &&
|
||||
a.border_b,
|
||||
]}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{isFetching && !autocompleteData?.length ? (
|
||||
<View style={[a.p_md]}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
) : (
|
||||
autocompleteData?.map(item => (
|
||||
<SearchProfileCard
|
||||
key={item.did}
|
||||
profile={item}
|
||||
moderationOpts={moderationOpts}
|
||||
onPress={onSearchProfileCardPress}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
},
|
||||
resultsContainer: {
|
||||
marginTop: 10,
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
borderWidth: 1,
|
||||
borderRadius: 6,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -3252,6 +3252,11 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/runtime@^7.24.5":
|
||||
version "7.28.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.2.tgz#2ae5a9d51cc583bd1f5673b3bb70d6d819682473"
|
||||
integrity sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==
|
||||
|
||||
"@babel/runtime@^7.25.0", "@babel/runtime@^7.26.0":
|
||||
version "7.26.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
|
||||
@@ -9523,6 +9528,11 @@ compression@^1.7.4:
|
||||
safe-buffer "5.1.2"
|
||||
vary "~1.1.2"
|
||||
|
||||
compute-scroll-into-view@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz#02c3386ec531fb6a9881967388e53e8564f3e9aa"
|
||||
integrity sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -10334,6 +10344,17 @@ dotenv@^16.4.4, dotenv@^16.4.5, dotenv@~16.4.5:
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
|
||||
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
|
||||
|
||||
downshift@^9.0.10:
|
||||
version "9.0.10"
|
||||
resolved "https://registry.yarnpkg.com/downshift/-/downshift-9.0.10.tgz#44e4d34bba63c1b7cd5a41ea4bead1b569ae061c"
|
||||
integrity sha512-TP/iqV6bBok6eGD5tZ8boM8Xt7/+DZvnVNr8cNIhbAm2oUBd79Tudiccs2hbcV9p7xAgS/ozE7Hxy3a9QqS6Mw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.24.5"
|
||||
compute-scroll-into-view "^3.1.0"
|
||||
prop-types "^15.8.1"
|
||||
react-is "18.2.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
dunder-proto@^1.0.0, dunder-proto@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
|
||||
@@ -16757,6 +16778,11 @@ react-image-crop@^11.0.7:
|
||||
resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-11.0.7.tgz#25f3d37ccbb65a05d19d23b4740a5912835c741e"
|
||||
integrity sha512-ZciKWHDYzmm366JDL18CbrVyjnjH0ojufGDmScfS4ZUqLHg4nm6ATY+K62C75W4ZRNt4Ii+tX0bSjNk9LQ2xzQ==
|
||||
|
||||
react-is@18.2.0, react-is@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-is@19, react-is@^19.0.0, react-is@^19.1.0:
|
||||
version "19.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.1.0.tgz#805bce321546b7e14c084989c77022351bbdd11b"
|
||||
@@ -16767,11 +16793,6 @@ react-is@^16.13.1, react-is@^16.7.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-is@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-keyed-flatten-children@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-keyed-flatten-children/-/react-keyed-flatten-children-5.0.0.tgz#3024fc8819f7b60fc5039b527f133d9ac3a02a82"
|
||||
@@ -19004,7 +19025,7 @@ tsconfig-paths@^3.15.0:
|
||||
minimist "^1.2.6"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
tslib@2:
|
||||
tslib@2, tslib@^2.6.2:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
Reference in New Issue
Block a user