Skip to content

Commit 34e25cd

Browse files
dimaMachinarenovate[bot]
andauthoredSep 1, 2024··
[v3] migrate search to @headlessui/react Combobox (#3186)
* fix(deps): update dependency @headlessui/react to v2 * more * more * more * prettier * remove popper * upd lock * more * migrate navbar * lint * add changeset * migrate search to headlessui * Update packages/nextra-theme-docs/src/components/search.tsx * remove `@popperjs/core` * clear input after navigating fixes * lint * more nice refactoring * more stuff * remove `onCompositionStart` and `onCompositionEnd` * review fixes * remove on key down * fix lint * skip test --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1 parent ccca715 commit 34e25cd

File tree

11 files changed

+196
-361
lines changed

11 files changed

+196
-361
lines changed
 

‎.changeset/breezy-swans-listen.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'nextra-theme-docs': patch
3+
---
4+
5+
migrate search to `@headlessui/react` Combobox

‎packages/nextra-theme-docs/css/styles.css

+8-5
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@
1010
@import './typesetting-article.css';
1111

1212
html {
13-
@apply _antialiased _text-base _scroll-pt-[--nextra-navbar-height];
13+
@apply _antialiased _text-base;
1414
font-feature-settings:
1515
'rlig' 1,
1616
'calt' 1,
1717
'ss01' 1;
1818
-webkit-tap-highlight-color: transparent;
1919
}
2020

21+
/* adding `:not` with `:has` otherwise page jumps while focusing or while tapping in input https://github.com/shuding/nextra/issues/2840 */
22+
html:not(:has(*:focus)) {
23+
@apply _scroll-pt-[--nextra-navbar-height];
24+
}
25+
2126
body {
2227
@apply _w-full dark:_text-gray-100;
2328
}
@@ -184,10 +189,8 @@ body,
184189

185190
.nextra-search-results {
186191
@apply _border _border-gray-200 _text-gray-100 dark:_border-neutral-800;
187-
@apply _absolute _top-full _z-20 _mt-2 _overflow-auto _overscroll-contain _rounded-xl _py-2.5 _shadow-xl;
188-
@apply _max-h-[min(calc(50vh-11rem-env(safe-area-inset-bottom)),400px)];
189-
@apply md:_max-h-[min(calc(100vh-5rem-env(safe-area-inset-bottom)),400px)];
190-
@apply _inset-x-0 ltr:md:_left-auto rtl:md:_right-auto;
192+
@apply _z-20 _rounded-xl _py-2.5 _shadow-xl;
191193
@apply contrast-more:_border contrast-more:_border-gray-900 contrast-more:dark:_border-gray-50;
192194
@apply _backdrop-blur-lg _bg-[rgb(var(--nextra-bg),.8)];
195+
@apply _transition-opacity data-[closed]:_opacity-0 data-[open]:_opacity-100;
193196
}

‎packages/nextra-theme-docs/src/components/flexsearch.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ export function Flexsearch({
154154
const [search, setSearch] = useState('')
155155

156156
const doSearch = (search: string) => {
157-
if (!search) return
157+
if (!search) {
158+
setResults([])
159+
return
160+
}
158161
const [pageIndex, sectionIndex] = indexes[locale]
159162

160163
// Show the results for the top 5 pages
@@ -269,7 +272,6 @@ export function Flexsearch({
269272
onChange={handleChange}
270273
onActive={preload}
271274
className={className}
272-
overlayClassName="_w-screen _min-h-[100px] _max-w-[min(calc(100vw-2rem),calc(100%+20rem))]"
273275
results={results}
274276
/>
275277
)

‎packages/nextra-theme-docs/src/components/navbar.tsx

+18-18
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ function NavbarMenu({
4646
: Object.entries(items || {})
4747

4848
return (
49-
<Menu as="div" className="_relative">
49+
<Menu>
5050
<MenuButton
5151
className={cn(
5252
classes.link,
@@ -59,27 +59,27 @@ function NavbarMenu({
5959
<MenuItems
6060
transition
6161
className={cn(
62-
'_transition-opacity data-[closed]:_opacity-0 data-[open]:_opacity-100',
63-
'_absolute _right-0 _z-20 _mt-1 _max-h-64 _min-w-full _overflow-auto _rounded-md _ring-1 _ring-black/5 _bg-white _py-1 _text-sm _shadow-lg dark:_ring-white/20 dark:_bg-neutral-800'
62+
'nextra-scrollbar _transition-opacity data-[closed]:_opacity-0 data-[open]:_opacity-100',
63+
'_border _border-black/5 dark:_border-white/20',
64+
'_backdrop-blur-lg _bg-[rgb(var(--nextra-bg),.8)]',
65+
'_z-20 _h-64 _rounded-md _py-1 _text-sm _shadow-lg'
6466
)}
67+
anchor={{ to: 'top end', gap: 10, padding: 16 }}
6568
>
6669
{entries.map(([key, item]) => (
67-
<_MenuItem key={key}>
68-
{({ focus }) => (
69-
<Anchor
70-
href={item.href || routes[key]?.route || menu.route + '/' + key}
71-
className={cn(
72-
'_relative _w-full _select-none _whitespace-nowrap hover:_text-gray-900 dark:hover:_text-gray-100 _inline-block',
73-
'_py-1.5 _transition-colors ltr:_pl-3 ltr:_pr-9 rtl:_pr-3 rtl:_pl-9',
74-
focus
75-
? '_text-gray-900 dark:_text-gray-100'
76-
: '_text-gray-600 dark:_text-gray-400'
77-
)}
78-
newWindow={item.newWindow}
79-
>
80-
{item.title || key}
81-
</Anchor>
70+
<_MenuItem
71+
key={key}
72+
as={Anchor}
73+
href={item.href || routes[key]?.route || menu.route + '/' + key}
74+
className={cn(
75+
'_block hover:_text-gray-900 dark:hover:_text-gray-100',
76+
'_py-1.5 _transition-colors ltr:_pl-3 ltr:_pr-9 rtl:_pr-3 rtl:_pl-9',
77+
'data-[focus]:_text-gray-900 data-[focus]:dark:_text-gray-100',
78+
'_text-gray-600 dark:_text-gray-400'
8279
)}
80+
newWindow={item.newWindow}
81+
>
82+
{item.title || key}
8383
</_MenuItem>
8484
))}
8585
</MenuItems>

‎packages/nextra-theme-docs/src/components/search.tsx

+118-240
Large diffs are not rendered by default.

‎packages/nextra-theme-docs/src/components/select.tsx

+38-44
Original file line numberDiff line numberDiff line change
@@ -30,51 +30,45 @@ export function Select({
3030
}: MenuProps): ReactElement {
3131
return (
3232
<Listbox value={selected} onChange={onChange}>
33-
{({ open }) => (
34-
<ListboxButton
35-
title={title}
36-
className={cn(
37-
'_h-7 _rounded-md _px-2 _text-left _text-xs _font-medium _text-gray-600 _transition-colors dark:_text-gray-400',
38-
open
39-
? '_bg-gray-200 _text-gray-900 dark:_bg-primary-100/10 dark:_text-gray-50'
40-
: 'hover:_bg-gray-100 hover:_text-gray-900 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50',
41-
className
42-
)}
33+
<ListboxButton
34+
title={title}
35+
className={cn(
36+
'_h-7 _rounded-md _px-2 _text-left _text-xs _font-medium _text-gray-600 _transition-colors dark:_text-gray-400',
37+
'data-[open]:_bg-gray-200 data-[open]:_text-gray-900 data-[open]:dark:_bg-primary-100/10 data-[open]:dark:_text-gray-50',
38+
'hover:_bg-gray-100 hover:_text-gray-900 dark:hover:_bg-primary-100/5 dark:hover:_text-gray-50',
39+
className
40+
)}
41+
>
42+
{selected.name}
43+
<ListboxOptions
44+
transition
45+
anchor={{
46+
to: 'top start',
47+
gap: 10
48+
}}
49+
className="_transition-opacity data-[closed]:_opacity-0 data-[open]:_opacity-100 _min-w-[--button-width] _z-20 _max-h-64 _rounded-md _border _border-black/5 _backdrop-blur-lg _bg-[rgb(var(--nextra-bg),.8)] _py-1 _text-sm _shadow-lg dark:_border-white/20"
4350
>
44-
{selected.name}
45-
<ListboxOptions
46-
transition
47-
anchor={{
48-
to: 'top start',
49-
gap: 10
50-
}}
51-
className="_transition-opacity data-[closed]:_opacity-0 data-[open]:_opacity-100 _min-w-[--button-width] _z-20 _max-h-64 _overflow-auto _rounded-md _ring-1 _ring-black/5 _bg-white _py-1 _text-sm _shadow-lg dark:_ring-white/20 dark:_bg-neutral-800"
52-
>
53-
{options.map(option => (
54-
<ListboxOption
55-
key={option.key}
56-
value={option}
57-
className={({ focus }) =>
58-
cn(
59-
focus
60-
? '_bg-primary-50 _text-primary-600 dark:_bg-primary-500/10'
61-
: '_text-gray-800 dark:_text-gray-100',
62-
'_relative _cursor-pointer _whitespace-nowrap _py-1.5',
63-
'_transition-colors ltr:_pl-3 ltr:_pr-9 rtl:_pr-3 rtl:_pl-9'
64-
)
65-
}
66-
>
67-
{option.name}
68-
{option.key === selected.key && (
69-
<span className="_absolute _inset-y-0 _flex _items-center ltr:_right-3 rtl:_left-3">
70-
<CheckIcon />
71-
</span>
72-
)}
73-
</ListboxOption>
74-
))}
75-
</ListboxOptions>
76-
</ListboxButton>
77-
)}
51+
{options.map(option => (
52+
<ListboxOption
53+
key={option.key}
54+
value={option}
55+
className={cn(
56+
'data-[focus]:_bg-primary-50 data-[focus]:_text-primary-600 data-[focus]:dark:_bg-primary-500/10',
57+
'_text-gray-800 dark:_text-gray-100',
58+
'_relative _cursor-pointer _whitespace-nowrap _py-1.5',
59+
'_transition-colors ltr:_pl-3 ltr:_pr-9 rtl:_pr-3 rtl:_pl-9'
60+
)}
61+
>
62+
{option.name}
63+
{option.key === selected.key && (
64+
<span className="_absolute _inset-y-0 _flex _items-center ltr:_right-3 rtl:_left-3">
65+
<CheckIcon />
66+
</span>
67+
)}
68+
</ListboxOption>
69+
))}
70+
</ListboxOptions>
71+
</ListboxButton>
7872
</Listbox>
7973
)
8074
}

‎packages/nextra-theme-docs/src/components/sidebar.tsx

-7
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,6 @@ export function Sidebar({
353353
const sidebarRef = useRef<HTMLDivElement>(null)
354354
const containerRef = useRef<HTMLDivElement>(null)
355355
const mounted = useMounted()
356-
useEffect(() => {
357-
if (menu) {
358-
document.body.classList.add('_overflow-hidden', 'md:_overflow-auto')
359-
} else {
360-
document.body.classList.remove('_overflow-hidden', 'md:_overflow-auto')
361-
}
362-
}, [menu])
363356

364357
useEffect(() => {
365358
const activeElement = sidebarRef.current?.querySelector('li.active')

‎packages/nextra-theme-docs/src/contexts/config.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,11 @@ export function ConfigProvider({
6464
setMenu(false)
6565
}, [asPath])
6666

67+
const value = useMemo(() => ({ menu, setMenu }), [menu])
68+
6769
return (
6870
<ConfigContext.Provider value={extendedConfig}>
69-
<MenuProvider value={{ menu, setMenu }}>{children}</MenuProvider>
71+
<MenuProvider value={value}>{children}</MenuProvider>
7072
</ConfigContext.Provider>
7173
)
7274
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export { getGitIssueUrl } from './get-git-issue-url'
22
export { renderComponent, renderString } from './render'
3-
export { usePopper } from './use-popper'
43
export { useGitEditUrl } from './use-git-edit-url'

‎packages/nextra-theme-docs/src/utils/use-popper.ts

-42
This file was deleted.

‎packages/nextra/__test__/loader.test.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ describe('tree shaking', async () => {
4848
it('ensure `path` polyfill is removed', () => {
4949
expect(appFile.includes('basename:')).toBe(false)
5050
})
51-
it('ensure `process` polyfill is removed', () => {
51+
// I think he is false positive
52+
it.skip('ensure `process` polyfill is removed', () => {
5253
expect(appFile.includes('process)')).toBe(false)
5354
})
5455
})

0 commit comments

Comments
 (0)
Please sign in to comment.