mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Launch automatically the search in the asset store when typing (#4725)
This commit is contained in:
@@ -115,8 +115,7 @@ export const AssetStoreContext = React.createContext<AssetStoreState>({
|
||||
backToPreviousPage: () => {},
|
||||
openHome: () => {},
|
||||
clearHistory: () => {},
|
||||
openSearchIfNeeded: () => {},
|
||||
activateTextualSearch: () => {},
|
||||
openSearchResultPage: () => {},
|
||||
openTagPage: tag => {},
|
||||
openPackPage: assetPack => {},
|
||||
openDetailPage: assetShortHeader => {},
|
||||
@@ -392,7 +391,7 @@ export const AssetStoreStateProvider = ({
|
||||
const searchResults: ?Array<AssetShortHeader> = useSearchItem(
|
||||
assetShortHeadersById,
|
||||
getAssetShortHeaderSearchTerms,
|
||||
currentPage.ignoreTextualSearch ? '' : searchText,
|
||||
searchText,
|
||||
chosenCategory,
|
||||
chosenFilters,
|
||||
searchFilters
|
||||
|
@@ -9,12 +9,10 @@ import {
|
||||
import { type PrivateAssetPackListingData } from '../Utils/GDevelopServices/Shop';
|
||||
|
||||
export type AssetStorePageState = {|
|
||||
isOnHomePage: boolean,
|
||||
openedAssetPack: PublicAssetPack | PrivateAssetPack | null,
|
||||
openedAssetShortHeader: ?AssetShortHeader,
|
||||
openedPrivateAssetPackListingData: ?PrivateAssetPackListingData,
|
||||
filtersState: FiltersState,
|
||||
ignoreTextualSearch: boolean,
|
||||
scrollPosition?: ?number,
|
||||
|};
|
||||
|
||||
@@ -23,8 +21,7 @@ export type NavigationState = {|
|
||||
backToPreviousPage: () => void,
|
||||
openHome: () => void,
|
||||
clearHistory: () => void,
|
||||
openSearchIfNeeded: () => void,
|
||||
activateTextualSearch: () => void,
|
||||
openSearchResultPage: () => void,
|
||||
openTagPage: string => void,
|
||||
openPackPage: (PublicAssetPack | PrivateAssetPack) => void,
|
||||
openPrivateAssetPackInformationPage: PrivateAssetPackListingData => void,
|
||||
@@ -40,21 +37,29 @@ const noFilter: FiltersState = {
|
||||
};
|
||||
|
||||
export const assetStoreHomePageState: AssetStorePageState = {
|
||||
isOnHomePage: true,
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: noFilter,
|
||||
ignoreTextualSearch: false,
|
||||
};
|
||||
|
||||
const searchPageState: AssetStorePageState = {
|
||||
isOnHomePage: false,
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: noFilter,
|
||||
ignoreTextualSearch: false,
|
||||
};
|
||||
|
||||
export const isHomePage = (pageState: AssetStorePageState) => {
|
||||
return pageState === assetStoreHomePageState;
|
||||
};
|
||||
|
||||
export const isSearchResultPage = (pageState: AssetStorePageState) => {
|
||||
return (
|
||||
!isHomePage(pageState) &&
|
||||
!pageState.openedAssetShortHeader &&
|
||||
!pageState.openedPrivateAssetPackListingData
|
||||
);
|
||||
};
|
||||
|
||||
type AssetStorePageHistory = {|
|
||||
@@ -82,6 +87,8 @@ export const useNavigation = (): NavigationState => {
|
||||
},
|
||||
clearHistory: () => {
|
||||
setHistory(previousHistory => {
|
||||
if (previousHistory.previousPages.length <= 1) return previousHistory;
|
||||
|
||||
const currentPage =
|
||||
previousHistory.previousPages[
|
||||
previousHistory.previousPages.length - 1
|
||||
@@ -89,28 +96,20 @@ export const useNavigation = (): NavigationState => {
|
||||
return { previousPages: [assetStoreHomePageState, currentPage] };
|
||||
});
|
||||
},
|
||||
openSearchIfNeeded: () => {
|
||||
const currentPage = previousPages[previousPages.length - 1];
|
||||
if (currentPage.isOnHomePage || currentPage.openedAssetShortHeader) {
|
||||
setHistory({ previousPages: [...previousPages, searchPageState] });
|
||||
}
|
||||
},
|
||||
activateTextualSearch: () => {
|
||||
openSearchResultPage: () => {
|
||||
setHistory(previousHistory => {
|
||||
const currentPage =
|
||||
previousHistory.previousPages[
|
||||
previousHistory.previousPages.length - 1
|
||||
];
|
||||
if (currentPage.isOnHomePage || currentPage.openedAssetShortHeader) {
|
||||
if (!isSearchResultPage(currentPage)) {
|
||||
return {
|
||||
...previousHistory,
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
searchPageState,
|
||||
],
|
||||
};
|
||||
} else if (currentPage.ignoreTextualSearch) {
|
||||
currentPage.ignoreTextualSearch = false;
|
||||
return { previousPages: [...previousHistory.previousPages] };
|
||||
}
|
||||
|
||||
return previousHistory;
|
||||
@@ -122,7 +121,6 @@ export const useNavigation = (): NavigationState => {
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
isOnHomePage: false,
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
@@ -136,7 +134,6 @@ export const useNavigation = (): NavigationState => {
|
||||
removeFilter: () => {},
|
||||
setChosenCategory: () => {},
|
||||
},
|
||||
ignoreTextualSearch: true,
|
||||
},
|
||||
],
|
||||
}));
|
||||
@@ -147,7 +144,6 @@ export const useNavigation = (): NavigationState => {
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
isOnHomePage: false,
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetPack: assetPack,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
@@ -165,7 +161,6 @@ export const useNavigation = (): NavigationState => {
|
||||
removeFilter: () => {},
|
||||
setChosenCategory: () => {},
|
||||
},
|
||||
ignoreTextualSearch: true,
|
||||
},
|
||||
],
|
||||
}));
|
||||
@@ -178,12 +173,10 @@ export const useNavigation = (): NavigationState => {
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
isOnHomePage: false,
|
||||
openedAssetShortHeader: null,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: assetPack,
|
||||
filtersState: noFilter,
|
||||
ignoreTextualSearch: true,
|
||||
},
|
||||
],
|
||||
}));
|
||||
@@ -194,12 +187,10 @@ export const useNavigation = (): NavigationState => {
|
||||
previousPages: [
|
||||
...previousHistory.previousPages,
|
||||
{
|
||||
isOnHomePage: false,
|
||||
openedAssetShortHeader: assetShortHeader,
|
||||
openedAssetPack: null,
|
||||
openedPrivateAssetPackListingData: null,
|
||||
filtersState: noFilter,
|
||||
ignoreTextualSearch: true,
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
@@ -48,6 +48,7 @@ import AuthenticatedUserContext from '../Profile/AuthenticatedUserContext';
|
||||
import PrivateAssetPackPurchaseDialog from './PrivateAssets/PrivateAssetPackPurchaseDialog';
|
||||
import { LineStackLayout } from '../UI/Layout';
|
||||
import Paper from '../UI/Paper';
|
||||
import { isHomePage, isSearchResultPage } from './AssetStoreNavigator';
|
||||
|
||||
type Props = {||};
|
||||
|
||||
@@ -95,12 +96,15 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
assetPackRandomOrdering,
|
||||
} = React.useContext(AssetStoreContext);
|
||||
const {
|
||||
isOnHomePage,
|
||||
openedAssetPack,
|
||||
openedAssetShortHeader,
|
||||
openedPrivateAssetPackListingData,
|
||||
filtersState,
|
||||
} = navigationState.getCurrentPage();
|
||||
const isOnHomePage = isHomePage(navigationState.getCurrentPage());
|
||||
const isOnSearchResultPage = isSearchResultPage(
|
||||
navigationState.getCurrentPage()
|
||||
);
|
||||
const searchBar = React.useRef<?SearchBarInterface>(null);
|
||||
|
||||
const shouldAutofocusSearchbar = useShouldAutofocusSearchbar();
|
||||
@@ -224,11 +228,12 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
Window.openExternalURL(assetPack.externalWebLink);
|
||||
} else {
|
||||
saveScrollPosition();
|
||||
setSearchText('');
|
||||
navigationState.openPackPage(assetPack);
|
||||
setIsFiltersPanelOpen(true);
|
||||
}
|
||||
},
|
||||
[navigationState, saveScrollPosition]
|
||||
[navigationState, saveScrollPosition, setSearchText]
|
||||
);
|
||||
|
||||
// When a private pack is selected from the home page,
|
||||
@@ -248,6 +253,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
assetPackKind: 'private',
|
||||
});
|
||||
|
||||
setSearchText('');
|
||||
navigationState.openPrivateAssetPackInformationPage(
|
||||
assetPackListingData
|
||||
);
|
||||
@@ -255,6 +261,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
}
|
||||
|
||||
// The user has received the pack, open it.
|
||||
setSearchText('');
|
||||
sendAssetPackOpened({
|
||||
assetPackName: assetPackListingData.name,
|
||||
assetPackId: assetPackListingData.id,
|
||||
@@ -265,7 +272,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
navigationState.openPackPage(receivedAssetPack);
|
||||
setIsFiltersPanelOpen(true);
|
||||
},
|
||||
[receivedAssetPacks, saveScrollPosition, navigationState]
|
||||
[receivedAssetPacks, saveScrollPosition, navigationState, setSearchText]
|
||||
);
|
||||
|
||||
// If the user has received the pack they are currently viewing,
|
||||
@@ -286,6 +293,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
);
|
||||
if (receivedAssetPack) {
|
||||
// The user has received the pack, close the pack information dialog, and open the pack in the search.
|
||||
setSearchText('');
|
||||
setIsFiltersPanelOpen(true);
|
||||
saveScrollPosition();
|
||||
navigationState.openPackPage(receivedAssetPack);
|
||||
@@ -297,6 +305,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
purchasingPrivateAssetPackListingData,
|
||||
navigationState,
|
||||
saveScrollPosition,
|
||||
setSearchText,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -312,6 +321,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
publicAssetPacks &&
|
||||
publicAssetPacks.starterPacks.find(pack => pack.tag === tag);
|
||||
saveScrollPosition();
|
||||
setSearchText('');
|
||||
if (privateAssetPack) {
|
||||
navigationState.openPackPage(privateAssetPack);
|
||||
} else if (publicAssetPack) {
|
||||
@@ -323,6 +333,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
setIsFiltersPanelOpen(true);
|
||||
},
|
||||
[
|
||||
setSearchText,
|
||||
receivedAssetPacks,
|
||||
publicAssetPacks,
|
||||
saveScrollPosition,
|
||||
@@ -344,6 +355,18 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
[shouldAutofocusSearchbar]
|
||||
);
|
||||
|
||||
React.useLayoutEffect(
|
||||
() => {
|
||||
if (isOnHomePage) {
|
||||
clearAllFilters(assetFiltersState);
|
||||
setIsFiltersPanelOpen(false);
|
||||
}
|
||||
},
|
||||
// assetFiltersState is not stable, so don't list it.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[isOnHomePage]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResponsiveWindowMeasurer>
|
||||
@@ -361,6 +384,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
key="back-discover"
|
||||
tooltip={t`Back to discover`}
|
||||
onClick={() => {
|
||||
setSearchText('');
|
||||
navigationState.openHome();
|
||||
setScrollUpdateIsNeeded();
|
||||
clearAllFilters(assetFiltersState);
|
||||
@@ -374,13 +398,24 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
<SearchBar
|
||||
placeholder={t`Search assets`}
|
||||
value={searchText}
|
||||
onChange={setSearchText}
|
||||
onRequestSearch={() => {
|
||||
// Clear the history
|
||||
navigationState.activateTextualSearch();
|
||||
navigationState.clearHistory();
|
||||
setIsFiltersPanelOpen(true);
|
||||
}}
|
||||
onChange={
|
||||
isOnSearchResultPage
|
||||
? // An existing search is already being done: just update the
|
||||
// search text and the asset store will update the search results.
|
||||
setSearchText
|
||||
: (newValue: string) => {
|
||||
setSearchText(newValue);
|
||||
|
||||
// A new search is being initiated: navigate to the search page,
|
||||
// and clear the history as a new search was launched.
|
||||
if (!!newValue) {
|
||||
navigationState.clearHistory();
|
||||
navigationState.openSearchResultPage();
|
||||
setIsFiltersPanelOpen(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
onRequestSearch={() => {}}
|
||||
ref={searchBar}
|
||||
id="asset-store-search-bar"
|
||||
/>
|
||||
@@ -407,12 +442,6 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
onClick={() => {
|
||||
navigationState.backToPreviousPage();
|
||||
setScrollUpdateIsNeeded();
|
||||
if (
|
||||
navigationState.getCurrentPage().isOnHomePage
|
||||
) {
|
||||
clearAllFilters(assetFiltersState);
|
||||
setIsFiltersPanelOpen(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
@@ -497,7 +526,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
<AssetStoreFilterPanel
|
||||
assetFiltersState={assetFiltersState}
|
||||
onChoiceChange={() => {
|
||||
navigationState.openSearchIfNeeded();
|
||||
navigationState.openSearchResultPage();
|
||||
}}
|
||||
/>
|
||||
</Line>
|
||||
@@ -507,13 +536,19 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
</ScrollView>
|
||||
</Column>
|
||||
)}
|
||||
{isOnHomePage &&
|
||||
!(publicAssetPacks && privateAssetPacks) &&
|
||||
!error && <PlaceholderLoader />}
|
||||
{isOnHomePage &&
|
||||
publicAssetPacks &&
|
||||
privateAssetPacks &&
|
||||
assetPackRandomOrdering && (
|
||||
{isOnHomePage ? (
|
||||
error ? (
|
||||
<PlaceholderError onRetry={fetchAssetsAndFilters}>
|
||||
<AlertMessage kind="error">
|
||||
<Trans>
|
||||
An error occurred when fetching the asset store
|
||||
content. Please try again later.
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
</PlaceholderError>
|
||||
) : publicAssetPacks &&
|
||||
privateAssetPacks &&
|
||||
assetPackRandomOrdering ? (
|
||||
<AssetsHome
|
||||
ref={assetsHome}
|
||||
publicAssetPacks={publicAssetPacks}
|
||||
@@ -522,43 +557,30 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
onPublicAssetPackSelection={selectPublicAssetPack}
|
||||
onPrivateAssetPackSelection={selectPrivateAssetPack}
|
||||
/>
|
||||
)}
|
||||
{!isOnHomePage &&
|
||||
!openedAssetShortHeader &&
|
||||
!openedPrivateAssetPackListingData && (
|
||||
<BoxSearchResults
|
||||
ref={boxSearchResults}
|
||||
baseSize={128}
|
||||
onRetry={fetchAssetsAndFilters}
|
||||
error={error}
|
||||
searchItems={searchResults}
|
||||
renderSearchItem={(assetShortHeader, size) => (
|
||||
<AssetCard
|
||||
size={size}
|
||||
onOpenDetails={() =>
|
||||
onOpenDetails(assetShortHeader)
|
||||
}
|
||||
assetShortHeader={assetShortHeader}
|
||||
/>
|
||||
)}
|
||||
noResultPlaceholder={
|
||||
<NoResultPlaceholder
|
||||
onClear={() => clearAllFilters(assetFiltersState)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isOnHomePage && error && (
|
||||
<PlaceholderError onRetry={fetchAssetsAndFilters}>
|
||||
<AlertMessage kind="error">
|
||||
<Trans>
|
||||
An error occurred when fetching the asset store
|
||||
content. Please try again later.
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
</PlaceholderError>
|
||||
)}
|
||||
{openedAssetShortHeader && (
|
||||
) : (
|
||||
<PlaceholderLoader />
|
||||
)
|
||||
) : isOnSearchResultPage ? (
|
||||
<BoxSearchResults
|
||||
ref={boxSearchResults}
|
||||
baseSize={128}
|
||||
onRetry={fetchAssetsAndFilters}
|
||||
error={error}
|
||||
searchItems={searchResults}
|
||||
renderSearchItem={(assetShortHeader, size) => (
|
||||
<AssetCard
|
||||
size={size}
|
||||
onOpenDetails={() => onOpenDetails(assetShortHeader)}
|
||||
assetShortHeader={assetShortHeader}
|
||||
/>
|
||||
)}
|
||||
noResultPlaceholder={
|
||||
<NoResultPlaceholder
|
||||
onClear={() => clearAllFilters(assetFiltersState)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : openedAssetShortHeader ? (
|
||||
<AssetDetails
|
||||
ref={assetDetails}
|
||||
onTagSelection={selectTag}
|
||||
@@ -566,8 +588,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
onOpenDetails={onOpenDetails}
|
||||
onAssetLoaded={applyBackScrollPosition}
|
||||
/>
|
||||
)}
|
||||
{!!openedPrivateAssetPackListingData && (
|
||||
) : !!openedPrivateAssetPackListingData ? (
|
||||
<PrivateAssetPackInformationPage
|
||||
privateAssetPackListingData={
|
||||
openedPrivateAssetPackListingData
|
||||
@@ -581,7 +602,7 @@ export const AssetStore = React.forwardRef<Props, AssetStoreInterface>(
|
||||
!!purchasingPrivateAssetPackListingData
|
||||
}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
{!!purchasingPrivateAssetPackListingData && (
|
||||
<PrivateAssetPackPurchaseDialog
|
||||
privateAssetPackListingData={
|
||||
|
@@ -23,6 +23,7 @@ import Search from './CustomSvgIcons/Search';
|
||||
import Cross from './CustomSvgIcons/Cross';
|
||||
import GDevelopThemeContext from './Theme/ThemeContext';
|
||||
import { type GDevelopTheme } from './Theme';
|
||||
import { useDebounce } from '../Utils/UseDebounce';
|
||||
|
||||
type TagsHandler = {|
|
||||
remove: string => void,
|
||||
@@ -161,6 +162,8 @@ export type SearchBarInterface = {|
|
||||
blur: () => void,
|
||||
|};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
/**
|
||||
* Material design search bar,
|
||||
* inspired from https://github.com/TeamWertarbyte/material-ui-search-bar
|
||||
@@ -230,10 +233,20 @@ const SearchBar = React.forwardRef<Props, SearchBarInterface>(
|
||||
focused: isInputFocused,
|
||||
});
|
||||
|
||||
const changeValue = React.useCallback(
|
||||
newValue => {
|
||||
setValue(newValue || '');
|
||||
onChange && onChange(newValue || '');
|
||||
const debouncedOnChange = useDebounce(onChange ? onChange : noop, 250);
|
||||
|
||||
const changeValueDebounced = React.useCallback(
|
||||
(newValue: string) => {
|
||||
setValue(newValue);
|
||||
debouncedOnChange(newValue);
|
||||
},
|
||||
[debouncedOnChange, setValue]
|
||||
);
|
||||
|
||||
const changeValueImmediately = React.useCallback(
|
||||
(newValue: string) => {
|
||||
setValue(newValue);
|
||||
onChange && onChange(newValue);
|
||||
},
|
||||
[onChange, setValue]
|
||||
);
|
||||
@@ -270,7 +283,7 @@ const SearchBar = React.forwardRef<Props, SearchBarInterface>(
|
||||
const handleBlur = () => {
|
||||
setIsInputFocused(false);
|
||||
if (!value || value.trim() === '') {
|
||||
changeValue('');
|
||||
changeValueImmediately('');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -279,11 +292,11 @@ const SearchBar = React.forwardRef<Props, SearchBarInterface>(
|
||||
};
|
||||
|
||||
const handleInput = (e: {| target: {| value: string |} |}) => {
|
||||
changeValue(e.target.value);
|
||||
changeValueDebounced(e.target.value);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
changeValue('');
|
||||
changeValueImmediately('');
|
||||
focus();
|
||||
};
|
||||
|
||||
@@ -297,7 +310,7 @@ const SearchBar = React.forwardRef<Props, SearchBarInterface>(
|
||||
|
||||
const handleAutocompleteInput = (
|
||||
event: any,
|
||||
newValue: string,
|
||||
newValue: ?string,
|
||||
reason:
|
||||
| 'create-option'
|
||||
| 'select-option'
|
||||
@@ -307,26 +320,35 @@ const SearchBar = React.forwardRef<Props, SearchBarInterface>(
|
||||
) => {
|
||||
// Called when the value of the autocomplete changes.
|
||||
if (reason === 'select-option') {
|
||||
tagsHandler && tagsHandler.add(newValue);
|
||||
tagsHandler && tagsHandler.add(newValue || '');
|
||||
|
||||
// Clear the value that was entered as an option was selected.
|
||||
changeValueImmediately('');
|
||||
|
||||
// Clear this value to make sure the autocomplete doesn't keep the
|
||||
// last typed value in memory.
|
||||
setAutocompleteValue('');
|
||||
} else {
|
||||
changeValue(newValue);
|
||||
changeValueImmediately(newValue || '');
|
||||
}
|
||||
};
|
||||
|
||||
const handleAutocompleteInputChange = (
|
||||
event: any,
|
||||
newValue: string,
|
||||
newValue: ?string,
|
||||
reason: 'reset' | 'input' | 'clear'
|
||||
) => {
|
||||
// Called when the value of the input within the autocomplete changes.
|
||||
if (reason === 'reset') {
|
||||
// Happens when user selects an option
|
||||
setValue('');
|
||||
// Happens when user selects an option. Do as for 'select-option':
|
||||
// Clear the value that was entered as an option was selected.
|
||||
changeValueImmediately('');
|
||||
|
||||
// Clear this value to make sure the autocomplete doesn't keep the
|
||||
// last typed value in memory.
|
||||
setAutocompleteValue('');
|
||||
} else {
|
||||
setValue(newValue);
|
||||
changeValueDebounced(newValue || '');
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -7,33 +7,40 @@ import paperDecorator from '../PaperDecorator';
|
||||
import SearchBar from '../../UI/SearchBar';
|
||||
import { useFilters } from '../../UI/Search/FiltersChooser';
|
||||
import { ColumnStackLayout } from '../../UI/Layout';
|
||||
import Text from '../../UI/Text';
|
||||
|
||||
export default {
|
||||
title: 'UI Building Blocks/SearchBar',
|
||||
component: SearchBar,
|
||||
decorators: [muiDecorator, paperDecorator],
|
||||
decorators: [paperDecorator, muiDecorator],
|
||||
};
|
||||
|
||||
const Vanilla = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const WithPlaceholder = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with placeholder"
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with placeholder"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -42,70 +49,82 @@ const Disabled = () => {
|
||||
'something typed in disabled field'
|
||||
);
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
disabled
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
disabled
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Integrated = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
aspect="integrated-search-bar"
|
||||
placeholder="Search integrated"
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
aspect="integrated-search-bar"
|
||||
placeholder="Search integrated"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const WithHelpIcon = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
helpPagePath="https://gdevelop.io"
|
||||
placeholder="Search with help icon"
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
helpPagePath="https://gdevelop.io"
|
||||
placeholder="Search with help icon"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const WithMenu = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with menu"
|
||||
buildMenuTemplate={() => [
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Tag 1',
|
||||
checked: false,
|
||||
click: action('Clicked Tag 1'),
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Tag 2 (checked)',
|
||||
checked: true,
|
||||
click: action('Clicked Tag 2 (checked)'),
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Tag 3',
|
||||
checked: false,
|
||||
click: action('Clicked Tag 3'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with menu"
|
||||
buildMenuTemplate={() => [
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Tag 1',
|
||||
checked: false,
|
||||
click: action('Clicked Tag 1'),
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Tag 2 (checked)',
|
||||
checked: true,
|
||||
click: action('Clicked Tag 2 (checked)'),
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Tag 3',
|
||||
checked: false,
|
||||
click: action('Clicked Tag 3'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -113,18 +132,21 @@ const WithTags = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
const filtersState = useFilters();
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with tags"
|
||||
tagsHandler={{
|
||||
add: filtersState.addFilter,
|
||||
remove: filtersState.removeFilter,
|
||||
chosenTags: filtersState.chosenFilters,
|
||||
}}
|
||||
tags={['Platformer', 'RPG', 'Beat them all', 'Top down']}
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with tags"
|
||||
tagsHandler={{
|
||||
add: filtersState.addFilter,
|
||||
remove: filtersState.removeFilter,
|
||||
chosenTags: filtersState.chosenFilters,
|
||||
}}
|
||||
tags={['Platformer', 'RPG', 'Beat them all', 'Top down']}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -132,19 +154,22 @@ const WithTagsAndHelp = () => {
|
||||
const [value, setValue] = React.useState<string>('');
|
||||
const filtersState = useFilters();
|
||||
return (
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with tags and help"
|
||||
tagsHandler={{
|
||||
add: filtersState.addFilter,
|
||||
remove: filtersState.removeFilter,
|
||||
chosenTags: filtersState.chosenFilters,
|
||||
}}
|
||||
tags={['Platformer', 'RPG', 'Beat them all', 'Top down']}
|
||||
helpPagePath="https://gdevelop.io"
|
||||
/>
|
||||
<>
|
||||
<Text>Value in state is: "{value}".</Text>
|
||||
<SearchBar
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
onRequestSearch={action('request search')}
|
||||
placeholder="Search with tags and help"
|
||||
tagsHandler={{
|
||||
add: filtersState.addFilter,
|
||||
remove: filtersState.removeFilter,
|
||||
chosenTags: filtersState.chosenFilters,
|
||||
}}
|
||||
tags={['Platformer', 'RPG', 'Beat them all', 'Top down']}
|
||||
helpPagePath="https://gdevelop.io"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user