Skip to content

Commit

Permalink
Merge pull request #26807 from storybookjs/jeppe/fix-halt-on-search
Browse files Browse the repository at this point in the history
UI: Fix sidebar search hanging when selecting a story in touch mode
  • Loading branch information
JReinhold authored Apr 15, 2024
2 parents ea87f40 + e3f6b12 commit e967840
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 54 deletions.
2 changes: 1 addition & 1 deletion code/ui/manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
"@types/semver": "^7.3.4",
"browser-dtector": "^3.4.0",
"copy-to-clipboard": "^3.3.1",
"downshift": "^6.0.15",
"downshift": "^9.0.4",
"fs-extra": "^11.1.0",
"fuse.js": "^3.6.1",
"lodash": "^4.17.21",
Expand Down
63 changes: 35 additions & 28 deletions code/ui/manager/src/components/sidebar/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,6 @@ export const Search = React.memo<{
const [allComponents, showAllComponents] = useState(false);
const searchShortcut = api ? shortcutToHumanString(api.getShortcutKeys().search) : '/';

const selectStory = useCallback(
(id: string, refId: string) => {
if (api) {
api.selectStory(id, undefined, { ref: refId !== DEFAULT_REF_ID && refId });
}
inputRef.current.blur();
showAllComponents(false);
},
[api, inputRef, showAllComponents, DEFAULT_REF_ID]
);

const makeFuse = useCallback(() => {
const list = dataset.entries.reduce<SearchItem[]>((acc, [refId, { index, status }]) => {
const groupStatus = getGroupStatus(index || {}, status);
Expand Down Expand Up @@ -232,6 +221,26 @@ export const Search = React.memo<{
[allComponents, makeFuse]
);

const onSelect = useCallback(
(selectedItem: DownshiftItem) => {
if (isSearchResult(selectedItem)) {
const { id, refId } = selectedItem.item;
api?.selectStory(id, undefined, { ref: refId !== DEFAULT_REF_ID && refId });
inputRef.current.blur();
showAllComponents(false);
return;
}
if (isExpandType(selectedItem)) {
selectedItem.showAll();
}
},
[api]
);

const onInputValueChange = useCallback((inputValue: string, stateAndHelpers: any) => {
showAllComponents(false);
}, []);

const stateReducer = useCallback(
(state: DownshiftState<DownshiftItem>, changes: StateChangeOptions<DownshiftItem>) => {
switch (changes.type) {
Expand All @@ -242,52 +251,42 @@ export const Search = React.memo<{
inputValue: state.inputValue,
// Return to the tree view after selecting an item
isOpen: state.inputValue && !state.selectedItem,
selectedItem: null,
};
}

case Downshift.stateChangeTypes.mouseUp: {
// Prevent clearing the input on refocus
return {};
return state;
}

case Downshift.stateChangeTypes.keyDownEscape: {
if (state.inputValue) {
// Clear the inputValue, but don't return to the tree view
return { ...changes, inputValue: '', isOpen: true, selectedItem: null };
}
// When pressing escape a second time, blur the input and return to the tree view
inputRef.current.blur();
// When pressing escape a second time return to the tree view
// The onKeyDown handler will also blur the input in this case
return { ...changes, isOpen: false, selectedItem: null };
}

case Downshift.stateChangeTypes.clickItem:
case Downshift.stateChangeTypes.keyDownEnter: {
if (isSearchResult(changes.selectedItem)) {
const { id, refId } = changes.selectedItem.item;
selectStory(id, refId);
// Return to the tree view, but keep the input value
return { ...changes, inputValue: state.inputValue, isOpen: false };
return { ...changes, inputValue: state.inputValue };
}
if (isExpandType(changes.selectedItem)) {
changes.selectedItem.showAll();
// Downshift should completely ignore this
return {};
return state;
}
return changes;
}

case Downshift.stateChangeTypes.changeInput: {
// Reset the "show more" state whenever the input changes
showAllComponents(false);
return changes;
}

default:
return changes;
}
},
[inputRef, selectStory, showAllComponents]
[]
);
const { isMobile } = useLayout();

Expand All @@ -298,6 +297,8 @@ export const Search = React.memo<{
// @ts-expect-error (Converted from ts-ignore)
itemToString={(result) => result?.item?.name || ''}
scrollIntoView={(e) => scrollIntoView(e)}
onSelect={onSelect}
onInputValueChange={onInputValueChange}
>
{({
isOpen,
Expand Down Expand Up @@ -343,6 +344,13 @@ export const Search = React.memo<{
setPlaceholder('Type to find...');
},
onBlur: () => setPlaceholder('Find components'),
onKeyDown: (e) => {
if (e.key === 'Escape' && inputValue.length === 0) {
// When pressing escape while the input is empty, blur the input
// The stateReducer will handle returning to the tree view
inputRef.current.blur();
}
},
});

const labelProps = getLabelProps({
Expand All @@ -359,7 +367,6 @@ export const Search = React.memo<{
<SearchIconWrapper>
<SearchIcon />
</SearchIconWrapper>
{/* @ts-expect-error (TODO) */}
<Input {...inputProps} />
{!isMobile && enableShortcuts && !isOpen && (
<FocusKey>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const recents = stories
.map((story) => ({ item: story, matches: [], score: 0 }));

// We need this to prevent react key warnings
const passKey = (props: any = {}) => ({ key: props.key });
const passKey: any = (props = { key: '' }) => ({ key: props.key });

export const searching = {
query: 'query',
Expand Down
12 changes: 5 additions & 7 deletions code/ui/manager/src/components/sidebar/SearchResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,13 @@ const Path = styled.div(({ theme }) => ({

const Result: FC<
SearchResult & {
icon: string;
isHighlighted: boolean;
onClick: MouseEventHandler;
}
> = React.memo(function Result({ item, matches, icon, onClick, ...props }) {
const click: MouseEventHandler = useCallback(
} & React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>
> = React.memo(function Result({ item, matches, onClick, ...props }) {
const click: MouseEventHandler<HTMLLIElement> = useCallback(
(event) => {
event.preventDefault();
onClick(event);
onClick?.(event);
},
[onClick]
);
Expand Down Expand Up @@ -260,7 +258,7 @@ export const SearchResults: FC<{
return () => document.removeEventListener('keydown', handleEscape);
}, [closeMenu, enableShortcuts, isLoading]);

const mouseOverHandler = useCallback((event: MouseEvent) => {
const mouseOverHandler: MouseEventHandler = useCallback((event) => {
if (!api) {
return;
}
Expand Down
43 changes: 26 additions & 17 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1996,7 +1996,7 @@ __metadata:
languageName: node
linkType: hard

"@babel/runtime@npm:7.24.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.14.8, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
"@babel/runtime@npm:7.24.0, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2":
version: 7.24.0
resolution: "@babel/runtime@npm:7.24.0"
dependencies:
Expand All @@ -2014,6 +2014,15 @@ __metadata:
languageName: node
linkType: hard

"@babel/runtime@npm:^7.22.15":
version: 7.24.4
resolution: "@babel/runtime@npm:7.24.4"
dependencies:
regenerator-runtime: "npm:^0.14.0"
checksum: 10c0/785aff96a3aa8ff97f90958e1e8a7b1d47f793b204b47c6455eaadc3f694f48c97cd5c0a921fe3596d818e71f18106610a164fb0f1c71fd68c622a58269d537c
languageName: node
linkType: hard

"@babel/runtime@npm:~7.5.4":
version: 7.5.5
resolution: "@babel/runtime@npm:7.5.5"
Expand Down Expand Up @@ -6093,7 +6102,7 @@ __metadata:
"@types/semver": "npm:^7.3.4"
browser-dtector: "npm:^3.4.0"
copy-to-clipboard: "npm:^3.3.1"
downshift: "npm:^6.0.15"
downshift: "npm:^9.0.4"
fs-extra: "npm:^11.1.0"
fuse.js: "npm:^3.6.1"
lodash: "npm:^4.17.21"
Expand Down Expand Up @@ -11964,10 +11973,10 @@ __metadata:
languageName: node
linkType: hard

"compute-scroll-into-view@npm:^1.0.17":
version: 1.0.20
resolution: "compute-scroll-into-view@npm:1.0.20"
checksum: 10c0/19034322590bfce59cb6939b3603e7aaf6f0d4128b8627bbc136e71c8714905e2f8bf2ba0cb7f153c6e8cdb8ad907ffd6d0188ccc7625dc05790a59ae6a81f01
"compute-scroll-into-view@npm:^3.0.3":
version: 3.1.0
resolution: "compute-scroll-into-view@npm:3.1.0"
checksum: 10c0/bf305c4ece8e5c59ed3f7ed82b6dab5b7487ce26f56a693d903869964712870fccb08fe31d40edcbd600b03c99198f54d443acb315d674bd64fd344410c8672e
languageName: node
linkType: hard

Expand Down Expand Up @@ -13235,18 +13244,18 @@ __metadata:
languageName: node
linkType: hard

"downshift@npm:^6.0.15":
version: 6.1.12
resolution: "downshift@npm:6.1.12"
"downshift@npm:^9.0.4":
version: 9.0.4
resolution: "downshift@npm:9.0.4"
dependencies:
"@babel/runtime": "npm:^7.14.8"
compute-scroll-into-view: "npm:^1.0.17"
prop-types: "npm:^15.7.2"
react-is: "npm:^17.0.2"
tslib: "npm:^2.3.0"
"@babel/runtime": "npm:^7.22.15"
compute-scroll-into-view: "npm:^3.0.3"
prop-types: "npm:^15.8.1"
react-is: "npm:^18.2.0"
tslib: "npm:^2.6.2"
peerDependencies:
react: ">=16.12.0"
checksum: 10c0/fa29bfcb9db520c9e45735a49e00d85bb47fb3ad0d4b754dbf2e75ef5cb9264c0950be3186422f14a8acb0e753a7fc0564e4312906de641989c349ea70424558
checksum: 10c0/8474a42d7fdbe9e5fb748c79b0f824610375921a5300426312d8b8e13d72aa29a6a5d45dba42b599878855d127ba7fa4b26862a8a12d12fd576e8d955b6670c4
languageName: node
linkType: hard

Expand Down Expand Up @@ -23801,14 +23810,14 @@ __metadata:
languageName: node
linkType: hard

"react-is@npm:^17.0.1, react-is@npm:^17.0.2":
"react-is@npm:^17.0.1":
version: 17.0.2
resolution: "react-is@npm:17.0.2"
checksum: 10c0/2bdb6b93fbb1820b024b496042cce405c57e2f85e777c9aabd55f9b26d145408f9f74f5934676ffdc46f3dcff656d78413a6e43968e7b3f92eea35b3052e9053
languageName: node
linkType: hard

"react-is@npm:^18.0.0":
"react-is@npm:^18.0.0, react-is@npm:^18.2.0":
version: 18.2.0
resolution: "react-is@npm:18.2.0"
checksum: 10c0/6eb5e4b28028c23e2bfcf73371e72cd4162e4ac7ab445ddae2afe24e347a37d6dc22fae6e1748632cd43c6d4f9b8f86dcf26bf9275e1874f436d129952528ae0
Expand Down

0 comments on commit e967840

Please sign in to comment.