fix(SW-1446): handle empty history and performance better

This commit is contained in:
Michael Zetterberg
2025-04-08 04:03:07 +02:00
parent b2ff5124ec
commit 2953b3571d
6 changed files with 134 additions and 105 deletions

View File

@@ -89,7 +89,7 @@
border-radius: var(--Corner-radius-Large);
padding: var(--Space-x2);
width: 360px;
max-height: 430px;
max-height: 400px;
box-sizing: content-box;
box-shadow: var(--BoxShadow-Level-4);
position: absolute;

View File

@@ -13,7 +13,7 @@ import { useIntl } from "react-intl"
import { useIsMounted } from "usehooks-ts"
import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { Results } from "../Results"
@@ -35,7 +35,8 @@ export function ClientInline({
const isMounted = useIsMounted()
const showResults = !!results
const showHistory = isMounted() && (!results || results.length === 0)
const showHistory =
latest.length > 0 && isMounted() && (!results || results.length === 0)
return (
<Autocomplete>
@@ -101,6 +102,7 @@ export function ClientInline({
</form>
)}
</SearchField>
{showResults || showHistory ? (
<div className={styles.results}>
<div
className={cx({
@@ -127,6 +129,7 @@ export function ClientInline({
) : null}
</div>
</div>
) : null}
</div>
</Autocomplete>
)

View File

@@ -16,7 +16,7 @@ import {
} from "react-aria-components"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { Results } from "../Results"

View File

@@ -23,51 +23,51 @@ export function ResultsSkeleton() {
<div>
<div className={styles.item}>
<Typography variant="Body/Paragraph/mdBold">
<SkeletonShimmer width="50%" />
<SkeletonShimmer width="50%" display="inline-block" />
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<div className={styles.itemDescription}>
<SkeletonShimmer width="38%" />
<SkeletonShimmer width="38%" display="inline-block" />
</div>
</Typography>
</div>
<div className={styles.item}>
<Typography variant="Body/Paragraph/mdBold">
<SkeletonShimmer width="40%" />
<SkeletonShimmer width="40%" display="inline-block" />
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<div className={styles.itemDescription}>
<SkeletonShimmer width="23%" />
<SkeletonShimmer width="23%" display="inline-block" />
</div>
</Typography>
</div>
<div className={styles.item}>
<Typography variant="Body/Paragraph/mdBold">
<SkeletonShimmer width="55%" />
<SkeletonShimmer width="55%" display="inline-block" />
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<div className={styles.itemDescription}>
<SkeletonShimmer width="40%" />
<SkeletonShimmer width="40%" display="inline-block" />
</div>
</Typography>
</div>
<div className={styles.item}>
<Typography variant="Body/Paragraph/mdBold">
<SkeletonShimmer width="27%" />
<SkeletonShimmer width="27%" display="inline-block" />
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<div className={styles.itemDescription}>
<SkeletonShimmer width="33%" />
<SkeletonShimmer width="33%" display="inline-block" />
</div>
</Typography>
</div>
<div className={styles.item}>
<Typography variant="Body/Paragraph/mdBold">
<SkeletonShimmer width="45%" />
<SkeletonShimmer width="45%" display="inline-block" />
</Typography>
<Typography variant="Body/Paragraph/mdRegular">
<div className={styles.itemDescription}>
<SkeletonShimmer width="37%" />
<SkeletonShimmer width="37%" display="inline-block" />
</div>
</Typography>
</div>

View File

@@ -3,14 +3,16 @@
import {
Collection,
Header,
ListLayout,
Menu,
MenuItem,
MenuSection,
Text,
Virtualizer,
} from "react-aria-components"
import { useIntl } from "react-intl"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import styles from "./results.module.css"
@@ -25,6 +27,13 @@ export function Results({
const intl = useIntl()
return (
<Virtualizer
layout={ListLayout}
layoutOptions={{
estimatedRowHeight: 64,
estimatedHeadingHeight: 41,
}}
>
<Menu
aria-label={ariaLabel}
onAction={onAction}
@@ -38,7 +47,9 @@ export function Results({
if (section.id === "actions") {
return (
<MenuSection key={section.id} className={styles.actionsSection}>
<Header className="sr-only">{section.name}</Header>
<Header className={styles.menuDivider}>
<span className="sr-only">{section.name}</span>
</Header>
<Collection items={section.children}>
{(item) => (
<MenuItem
@@ -101,5 +112,6 @@ export function Results({
)
}}
</Menu>
</Virtualizer>
)
}

View File

@@ -1,13 +1,20 @@
.menu {
display: flex;
flex-direction: column;
gap: var(--Space-x2);
height: 100%;
overflow-y: auto;
}
.sectionHeader {
color: var(--UI-Text-Placeholder);
padding-left: var(--Space-x1);
padding-bottom: var(--Space-x05);
/* Due to Virtualizer we cannot use gap in .menu,
instead we use padding-top on each section header */
padding-top: var(--Space-x2);
/* Except for the first section header */
.menu > div > div:first-child & {
padding-top: 0;
}
}
.item {
@@ -45,9 +52,16 @@
color: var(--Text-Tertiary);
}
.actionsSection {
border-top: solid 1px var(--Border-Divider-Subtle);
padding-top: var(--Space-x2); /* match gap of .menu */
.menuDivider {
padding-top: var(--Space-x2);
padding-bottom: var(--Space-x2);
}
.menuDivider:before {
display: block;
content: "";
height: 1px;
background: var(--Border-Divider-Subtle);
}
.actionsSection .item {