Skip to content

Commit 00f9060

Browse files
authored
docs: fix search menu styles (adobe#9575)
* fix tags overflowing and enable horizontal scrolling * start-align the info messages * fix import * lint * share info message styles * trim icon/illustration search inputs * fix padding on color items * use consistent styles between icon search and color search
1 parent bdec15c commit 00f9060

File tree

7 files changed

+77
-90
lines changed

7 files changed

+77
-90
lines changed

packages/dev/s2-docs/src/ColorSearchView.tsx

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import CheckmarkCircle from '@react-spectrum/s2/icons/CheckmarkCircle';
66
import {colorSwatch, getColorScale} from './color.macro' with {type: 'macro'};
77
import {focusRing, iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
88
import {Header, ListBox, ListBoxItem, ListBoxSection} from 'react-aria-components';
9-
import InfoCircle from '@react-spectrum/s2/icons/InfoCircle';
9+
import {InfoMessage} from './colorSearchData';
1010
// eslint-disable-next-line monorepo/no-internal-import
1111
import NoSearchResults from '@react-spectrum/s2/illustrations/linear/NoSearchResults';
1212
import React, {useCallback, useEffect, useRef, useState} from 'react';
@@ -19,7 +19,7 @@ const itemStyle = style({
1919
justifyContent: 'center',
2020
alignItems: 'center',
2121
gap: 8,
22-
padding: 8,
22+
paddingY: 8,
2323
backgroundColor: {
2424
default: 'gray-50',
2525
isHovered: 'gray-100',
@@ -47,13 +47,6 @@ const swatchStyle = style({
4747
forcedColorAdjust: 'none'
4848
});
4949

50-
const listBoxStyle = style({
51-
width: 'full',
52-
display: 'flex',
53-
flexDirection: 'column',
54-
gap: 24
55-
});
56-
5750
const sectionStyle = style({
5851
display: 'grid',
5952
gridTemplateColumns: 'repeat(auto-fill, minmax(100px, 1fr))',
@@ -199,20 +192,6 @@ const scaleSwatches: Record<string, string> = {
199192
};
200193

201194

202-
export function CopyInfoMessage() {
203-
return (
204-
<div className={style({display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 4, padding: 8})}>
205-
<div className={style({display: 'flex', alignItems: 'center', gap: 4})}>
206-
<InfoCircle styles={iconStyle({size: 'XS'})} />
207-
<span className={style({font: 'ui'})}>Press a color to copy its name.</span>
208-
</div>
209-
<span>
210-
See <Link href="styling">styling</Link> for more information.
211-
</span>
212-
</div>
213-
);
214-
}
215-
216195
interface ColorSearchViewProps {
217196
filteredItems: Array<{
218197
id: string,
@@ -268,8 +247,8 @@ export function ColorSearchView({filteredItems, exactMatches = new Set(), closes
268247
}
269248

270249
return (
271-
<div className={style({display: 'flex', flexDirection: 'column', gap: 8})}>
272-
<CopyInfoMessage />
250+
<>
251+
<InfoMessage>Press a color to copy its name. See <Link href="styling">styling</Link> for more information.</InfoMessage>
273252
<ListBox
274253
aria-label="Colors"
275254
onAction={(key) => {
@@ -282,7 +261,15 @@ export function ColorSearchView({filteredItems, exactMatches = new Set(), closes
282261
}
283262
}}
284263
layout="grid"
285-
className={listBoxStyle}
264+
className={style({
265+
width: 'full',
266+
display: 'flex',
267+
flexDirection: 'column',
268+
gap: 24,
269+
flexGrow: 1,
270+
overflow: 'auto',
271+
scrollPaddingY: 4
272+
})}
286273
dependencies={[copiedId, exactMatches, closestMatches]}
287274
items={sections}>
288275
{section => (
@@ -300,7 +287,7 @@ export function ColorSearchView({filteredItems, exactMatches = new Set(), closes
300287
</ListBoxSection>
301288
)}
302289
</ListBox>
303-
</div>
290+
</>
304291
);
305292
}
306293

packages/dev/s2-docs/src/IconSearchView.tsx

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import {Autocomplete, GridLayout, ListBox, ListBoxItem, Size, useFilter, Virtualizer} from 'react-aria-components';
55
import CheckmarkCircle from '@react-spectrum/s2/icons/CheckmarkCircle';
66
import Close from '@react-spectrum/s2/icons/Close';
7-
import {Content, Heading, IllustratedMessage, pressScale, SearchField, Skeleton, Text, ToastQueue} from '@react-spectrum/s2';
7+
import {Content, Heading, IllustratedMessage, Link, pressScale, SearchField, Skeleton, Text, ToastQueue} from '@react-spectrum/s2';
88
import {focusRing, iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
99
import {iconAliases} from './iconAliases.js';
1010
// @ts-ignore
1111
import icons from '/packages/@react-spectrum/s2/s2wf-icons/*.svg';
12-
import InfoCircle from '@react-spectrum/s2/icons/InfoCircle';
12+
import {InfoMessage} from './colorSearchData';
1313
// eslint-disable-next-line monorepo/no-internal-import
1414
import NoSearchResults from '@react-spectrum/s2/illustrations/linear/NoSearchResults';
1515
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
@@ -19,14 +19,19 @@ export const iconList = Object.keys(icons).map(name => ({id: name.replace(/^S2_I
1919
export function useIconFilter() {
2020
let {contains} = useFilter({sensitivity: 'base'});
2121
return useCallback((textValue: string, inputValue: string) => {
22+
const trimmedInput = inputValue.trim();
23+
// If input is empty after trimming, show all items
24+
if (!trimmedInput) {
25+
return true;
26+
}
2227
// Check for alias matches
2328
for (const alias of Object.keys(iconAliases)) {
24-
if (contains(alias, inputValue) && iconAliases[alias].includes(textValue)) {
29+
if (contains(alias, trimmedInput) && iconAliases[alias].includes(textValue)) {
2530
return true;
2631
}
2732
}
2833
// Also compare for substrings in the icon's actual name
29-
return textValue != null && contains(textValue, inputValue);
34+
return textValue != null && contains(textValue, trimmedInput);
3035
}, [contains]);
3136
}
3237

@@ -57,15 +62,6 @@ export function useCopyImport() {
5762
return {copiedId, handleCopyImport};
5863
}
5964

60-
function CopyInfoMessage() {
61-
return (
62-
<div className={style({display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4})}>
63-
<InfoCircle styles={iconStyle({size: 'XS'})} />
64-
<span className={style({font: 'ui'})}>Press an item to copy its import statement</span>
65-
</div>
66-
);
67-
}
68-
6965
interface IconListBoxProps {
7066
items: typeof iconList,
7167
copiedId: string | null,
@@ -133,7 +129,7 @@ export function IconSearchView({filteredItems, listBoxClassName}: IconSearchView
133129

134130
return (
135131
<>
136-
<CopyInfoMessage />
132+
<InfoMessage>Press an item to copy its import statement. See <Link href="icons">Icons</Link> for more information.</InfoMessage>
137133
<IconListBox items={filteredItems} copiedId={copiedId} onAction={handleCopyImport} listBoxClassName={listBoxClassName} />
138134
</>
139135
);
@@ -236,7 +232,7 @@ export function IconsPageSearch() {
236232
<Autocomplete filter={filter}>
237233
<div className={style({display: 'flex', flexDirection: 'column', gap: 8})}>
238234
<SearchField size="L" aria-label="Search icons" placeholder="Search icons" />
239-
<CopyInfoMessage />
235+
<InfoMessage>Press an item to copy its import statement. See <Link href="icons">Icons</Link> for more information.</InfoMessage>
240236
<IconListBox
241237
items={iconList}
242238
copiedId={copiedId}

packages/dev/s2-docs/src/IllustrationCards.tsx

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
import {Autocomplete, GridLayout, ListBox, ListBoxItem, Size, useFilter, Virtualizer} from 'react-aria-components';
44
// eslint-disable-next-line monorepo/no-internal-import
55
import Checkmark from '@react-spectrum/s2/illustrations/gradient/generic1/Checkmark';
6-
import {Content, Heading, IllustratedMessage, pressScale, ProgressCircle, Radio, RadioGroup, SearchField, SegmentedControl, SegmentedControlItem, Text, ToastQueue} from '@react-spectrum/s2';
7-
import {focusRing, iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
6+
import {Content, Heading, IllustratedMessage, Link, pressScale, ProgressCircle, Radio, RadioGroup, SearchField, SegmentedControl, SegmentedControlItem, Text, ToastQueue} from '@react-spectrum/s2';
7+
import {focusRing, style} from '@react-spectrum/s2/style' with {type: 'macro'};
88
// @ts-ignore
99
import Gradient from '@react-spectrum/s2/icons/Gradient';
10-
import {illustrationAliases} from './illustrationAliases.js';
11-
import InfoCircle from '@react-spectrum/s2/icons/InfoCircle';
10+
import {illustrationAliases} from './illustrationAliases.js';
11+
import {InfoMessage} from './colorSearchData';
1212
// eslint-disable-next-line monorepo/no-internal-import
1313
import NoSearchResults from '@react-spectrum/s2/illustrations/linear/NoSearchResults';
1414
import Polygon4 from '@react-spectrum/s2/icons/Polygon4';
@@ -44,14 +44,19 @@ export function IllustrationCards() {
4444

4545
let {contains} = useFilter({sensitivity: 'base'});
4646
let filter = useCallback((textValue: string, inputValue: string) => {
47+
const trimmedInput = inputValue.trim();
48+
// If input is empty after trimming, show all items
49+
if (!trimmedInput) {
50+
return true;
51+
}
4752
// Check if input matches an alias that maps to this illustration name
4853
for (const alias of Object.keys(illustrationAliases)) {
49-
if (contains(alias, inputValue) && illustrationAliases[alias].includes(textValue)) {
54+
if (contains(alias, trimmedInput) && illustrationAliases[alias].includes(textValue)) {
5055
return true;
5156
}
5257
}
5358
// Also compare for substrings in the illustration's actual name
54-
return textValue != null && contains(textValue, inputValue);
59+
return textValue != null && contains(textValue, trimmedInput);
5560
}, [contains]);
5661

5762
return (
@@ -80,7 +85,7 @@ export function IllustrationCards() {
8085
<Radio value="generic2">Generic 2</Radio>
8186
</RadioGroup>
8287
)}
83-
<CopyInfoMessage />
88+
<InfoMessage>Press an item to copy its import statement. See <Link href="illustrations">Illustrations</Link> for more information.</InfoMessage>
8489
<Suspense fallback={<Loading />}>
8590
<IllustrationList variant={variant} gradientStyle={gradientStyle} />
8691
</Suspense>
@@ -97,14 +102,6 @@ function Loading() {
97102
);
98103
}
99104

100-
function CopyInfoMessage() {
101-
return (
102-
<div className={style({display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4})}>
103-
<InfoCircle styles={iconStyle({size: 'XS'})} />
104-
<span className={style({font: 'ui'})}>Press an item to copy its import statement</span>
105-
</div>
106-
);
107-
}
108105

109106
function useCopyImport(variant: string, gradientStyle: string) {
110107
let [copiedId, setCopiedId] = useState<string | null>(null);

packages/dev/s2-docs/src/MobileSearchMenu.tsx

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ function MobileNav({initialTag}: {initialTag?: string}) {
328328
selectedTagId={selectedSection}
329329
onSectionSelectionChange={handleTagSelectionChange}
330330
onResourceSelectionChange={handleTagSelectionChange}
331-
isMobile
332331
wrapperClassName={style({paddingTop: 0})}
333332
contentClassName={style({display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 8, marginX: 0})} />
334333
</div>
@@ -356,19 +355,12 @@ function MobileNav({initialTag}: {initialTag?: string}) {
356355
</Suspense>
357356
)}
358357
{!showIcons && isColorsSelected && library.id === 'react-spectrum' && (
359-
<div
360-
className={style({
361-
flexGrow: 1,
362-
overflow: 'auto',
363-
paddingBottom: 16
364-
})}>
365-
<Suspense fallback={<ColorSearchSkeleton />}>
366-
<LazyColorSearchView
367-
filteredItems={filteredColors.sections}
368-
exactMatches={filteredColors.exactMatches}
369-
closestMatches={filteredColors.closestMatches} />
370-
</Suspense>
371-
</div>
358+
<Suspense fallback={<ColorSearchSkeleton />}>
359+
<LazyColorSearchView
360+
filteredItems={filteredColors.sections}
361+
exactMatches={filteredColors.exactMatches}
362+
closestMatches={filteredColors.closestMatches} />
363+
</Suspense>
372364
)}
373365
{!showIcons && (!isColorsSelected || library.id !== 'react-spectrum') && (
374366
<ComponentCardView

packages/dev/s2-docs/src/SearchMenu.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,16 +175,17 @@ export function SearchMenu(props: SearchMenuProps) {
175175
</div>
176176

177177
<CloseButton onClose={onClose} />
178-
179-
<SearchTagGroups
180-
sectionTags={sectionTagsForDisplay}
181-
resourceTags={tabResourceTags}
182-
selectedTagId={selectedTagId}
183-
onSectionSelectionChange={handleTagSelectionChange}
184-
onResourceSelectionChange={handleTagSelectionChange}
185-
onHover={tag => {
186-
preloadComponentImages(sections.find(s => s.id === tag)?.children?.map(c => c.name) || []);
187-
}} />
178+
<div className={style({overflow: 'auto', flexShrink: 0, paddingBottom: 8})}>
179+
<SearchTagGroups
180+
sectionTags={sectionTagsForDisplay}
181+
resourceTags={tabResourceTags}
182+
selectedTagId={selectedTagId}
183+
onSectionSelectionChange={handleTagSelectionChange}
184+
onResourceSelectionChange={handleTagSelectionChange}
185+
onHover={tag => {
186+
preloadComponentImages(sections.find(s => s.id === tag)?.children?.map(c => c.name) || []);
187+
}} />
188+
</div>
188189
{isIconsSelected ? (
189190
<div className={style({flexGrow: 1, overflow: 'auto', display: 'flex', flexDirection: 'column'})}>
190191
<Suspense fallback={<IconSearchSkeleton />}>
@@ -195,7 +196,7 @@ export function SearchMenu(props: SearchMenuProps) {
195196
</div>
196197
) : null}
197198
{selectedTagId === 'colors' && (
198-
<div className={style({flexGrow: 1, overflow: 'auto', paddingX: 16, paddingBottom: 16})}>
199+
<div className={style({flexGrow: 1, overflow: 'auto', display: 'flex', flexDirection: 'column'})}>
199200
<Suspense fallback={<ColorSearchSkeleton />}>
200201
<LazyColorSearchView filteredItems={filteredColors.sections} exactMatches={filteredColors.exactMatches} closestMatches={filteredColors.closestMatches} />
201202
</Suspense>

packages/dev/s2-docs/src/SearchTagGroups.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ interface SearchTagGroupsProps {
1818
selectedTagId: string | undefined,
1919
onSectionSelectionChange: (keys: Iterable<Key>) => void,
2020
onResourceSelectionChange?: (keys: Iterable<Key>) => void,
21-
isMobile?: boolean,
2221
wrapperClassName?: string,
2322
contentClassName?: string,
2423
onHover?: (id: Key) => void
@@ -30,7 +29,6 @@ export function SearchTagGroups({
3029
selectedTagId,
3130
onSectionSelectionChange,
3231
onResourceSelectionChange,
33-
isMobile = false,
3432
wrapperClassName,
3533
contentClassName,
3634
onHover
@@ -58,7 +56,7 @@ export function SearchTagGroups({
5856
onSelectionChange={onSectionSelectionChange}
5957
aria-label="Sections"
6058
items={sectionTags}
61-
UNSAFE_style={isMobile ? {whiteSpace: 'nowrap'} : undefined}>
59+
UNSAFE_style={{whiteSpace: 'nowrap'}}>
6260
{(tag) => (
6361
<Tag key={tag.id} id={tag.id} onHoverStart={() => onHover?.(tag.id)} onPressStart={() => onHover?.(tag.id)}>
6462
{tag.name}
@@ -79,7 +77,7 @@ export function SearchTagGroups({
7977
onSelectionChange={onResourceSelectionChange}
8078
aria-label="Resources"
8179
items={resourceTags}
82-
UNSAFE_style={isMobile ? {whiteSpace: 'nowrap'} : undefined}>
80+
UNSAFE_style={{whiteSpace: 'nowrap'}}>
8381
{(tag) => (
8482
<Tag key={tag.id} id={tag.id} href={tag.href} target="_blank">
8583
{tag.name}

packages/dev/s2-docs/src/colorSearchData.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use client';
22

3-
import {CopyInfoMessage} from './ColorSearchView';
43
import {getColorHexMap} from './color.macro' with {type: 'macro'};
54
import {Header, ListBox, ListBoxItem, ListBoxSection} from 'react-aria-components';
5+
import {iconStyle, style} from '@react-spectrum/s2/style' with {type: 'macro'};
6+
import InfoCircle from '@react-spectrum/s2/icons/InfoCircle';
7+
import {Link, Skeleton, Text} from '@react-spectrum/s2';
68
import React, {useMemo, useRef} from 'react';
7-
import {Skeleton, Text} from '@react-spectrum/s2';
8-
import {style} from '@react-spectrum/s2/style' with {type: 'macro'};
99

1010
export const colorHexMaps = getColorHexMap();
1111

@@ -148,6 +148,22 @@ const headerStyle = style({
148148
marginBottom: 4
149149
});
150150

151+
interface InfoMessageProps {
152+
/** The content to display in the message. */
153+
children: React.ReactNode
154+
}
155+
156+
export function InfoMessage({children}: InfoMessageProps) {
157+
return (
158+
<div className={style({display: 'flex', gap: 4, padding: 8, alignItems: 'center'})}>
159+
<InfoCircle styles={iconStyle({size: 'XS'})} />
160+
<span className={style({font: 'ui'})}>
161+
{children}
162+
</span>
163+
</div>
164+
);
165+
}
166+
151167
function SkeletonColorItem({item}: {item: {id: string}}) {
152168
const ref = useRef(null);
153169
return (
@@ -204,7 +220,7 @@ export function ColorSearchSkeleton() {
204220

205221
return (
206222
<div className={style({display: 'flex', flexDirection: 'column', gap: 8})}>
207-
<CopyInfoMessage />
223+
<InfoMessage>Press a color to copy its name. See <Link href="styling">styling</Link> for more information.</InfoMessage>
208224
<Skeleton isLoading>
209225
<ListBox
210226
aria-label="Colors loading"

0 commit comments

Comments
 (0)