Skip to content

Commit 30eb0cb

Browse files
authored
feat: add BaseSelectNative component (#3169)
1 parent 052faa5 commit 30eb0cb

File tree

13 files changed

+79
-37
lines changed

13 files changed

+79
-37
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as React from 'react';
2+
import { LuChevronDown } from 'react-icons/lu';
3+
4+
import { cn } from '@/common/utils/cn';
5+
6+
export interface BaseSelectPropsNative extends React.SelectHTMLAttributes<HTMLSelectElement> {
7+
children: React.ReactNode;
8+
}
9+
10+
const BaseSelectNative = React.forwardRef<HTMLSelectElement, BaseSelectPropsNative>(
11+
({ className, children, ...props }, ref) => {
12+
return (
13+
<div className="relative">
14+
<select
15+
className={cn(
16+
'peer inline-flex h-10 w-full cursor-pointer appearance-none items-center rounded-md',
17+
'border border-neutral-800 bg-neutral-950 text-sm text-menu-link',
18+
'focus-visible:border-ring transition-colors focus-visible:outline-none focus-visible:ring-1',
19+
'focus-visible:ring-neutral-300 disabled:pointer-events-none disabled:cursor-not-allowed',
20+
'has-[option[disabled]:checked]:text-muted-foreground disabled:opacity-50',
21+
'light:border-neutral-200 light:bg-white light:focus:ring-neutral-950',
22+
23+
props.multiple
24+
? '[&_option:checked]:bg-accent py-1 [&>*]:px-3 [&>*]:py-1'
25+
: 'h-9 pe-8 ps-3',
26+
27+
className,
28+
)}
29+
ref={ref}
30+
{...props}
31+
>
32+
{children}
33+
</select>
34+
{!props.multiple && (
35+
<span className="text-muted-foreground/80 pointer-events-none absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center peer-disabled:opacity-50">
36+
<LuChevronDown
37+
className="size-4 text-neutral-300 opacity-50 light:text-neutral-800"
38+
strokeWidth={2}
39+
aria-hidden="true"
40+
/>
41+
</span>
42+
)}
43+
</div>
44+
);
45+
},
46+
);
47+
BaseSelectNative.displayName = 'BaseSelectNative';
48+
49+
export { BaseSelectNative };

resources/js/common/components/FullPaginator/FullPaginator.test.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ describe('Component: FullPaginator', () => {
107107
);
108108

109109
// ACT
110-
await userEvent.click(screen.getByRole('combobox'));
111-
await userEvent.click(screen.getByRole('option', { name: '2' }));
110+
await userEvent.selectOptions(screen.getByRole('combobox'), ['2']);
112111

113112
// ASSERT
114113
expect(onPageSelectValueChange).toHaveBeenCalledWith(2);

resources/js/common/components/FullPaginator/FullPaginator.tsx

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FC } from 'react';
1+
import { type ChangeEvent, type FC, useState } from 'react';
22
import { useTranslation } from 'react-i18next';
33
import { LuArrowLeft, LuArrowLeftToLine, LuArrowRight, LuArrowRightToLine } from 'react-icons/lu';
44

@@ -11,13 +11,7 @@ import {
1111
import { cn } from '@/common/utils/cn';
1212

1313
import { baseButtonVariants } from '../+vendor/BaseButton';
14-
import {
15-
BaseSelect,
16-
BaseSelectContent,
17-
BaseSelectItem,
18-
BaseSelectTrigger,
19-
BaseSelectValue,
20-
} from '../+vendor/BaseSelect';
14+
import { BaseSelectNative } from '../+vendor/BaseSelectNative';
2115

2216
interface FullPaginatorProps<TData = unknown> {
2317
onPageSelectValueChange: (newPageValue: number) => void;
@@ -36,13 +30,20 @@ export const FullPaginator: FC<FullPaginatorProps> = ({
3630
links: { firstPageUrl, lastPageUrl, nextPageUrl, previousPageUrl },
3731
} = paginatedData;
3832

33+
const [internalValue, setInternalValue] = useState(String(currentPage));
34+
3935
if (!previousPageUrl && !nextPageUrl) {
4036
return <span />;
4137
}
4238

4339
// Generate an array of all page numbers. We'll use this to populate the select control.
4440
const pageOptions = Array.from({ length: lastPage }, (_, i) => i + 1);
4541

42+
const handlePageSelect = (event: ChangeEvent<HTMLSelectElement>) => {
43+
setInternalValue(event.target.value);
44+
onPageSelectValueChange(Number(event.target.value));
45+
};
46+
4647
return (
4748
<BasePagination>
4849
<BasePaginationContent>
@@ -83,22 +84,17 @@ export const FullPaginator: FC<FullPaginatorProps> = ({
8384
>
8485
<span>{t('Page')}</span>
8586

86-
<BaseSelect
87-
value={String(currentPage)}
88-
onValueChange={(value) => onPageSelectValueChange(Number(value))}
87+
<BaseSelectNative
88+
value={internalValue}
89+
onChange={handlePageSelect}
90+
className="!h-[32px] min-w-[70px]"
8991
>
90-
<BaseSelectTrigger className="!h-[32px] min-w-[70px]">
91-
<BaseSelectValue />
92-
</BaseSelectTrigger>
93-
94-
<BaseSelectContent>
95-
{pageOptions.map((page) => (
96-
<BaseSelectItem key={`page-value-${page}`} value={page.toString()}>
97-
{page}
98-
</BaseSelectItem>
99-
))}
100-
</BaseSelectContent>
101-
</BaseSelect>
92+
{pageOptions.map((page) => (
93+
<option key={`page-value-${page}`} value={page.toString()}>
94+
{page}
95+
</option>
96+
))}
97+
</BaseSelectNative>
10298

10399
<span className="whitespace-nowrap">
104100
{t('of {{pageNumber, number}}', { pageNumber: lastPage })}

resources/js/features/comments/AchievementCommentsMainRoot/AchievementCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ describe('Component: AchievementCommentsMainRoot', () => {
191191
// ACT
192192
const comboboxEl = screen.getAllByRole('combobox')[0];
193193
await userEvent.click(comboboxEl);
194-
await userEvent.click(screen.getByRole('option', { name: '2' }));
194+
await userEvent.selectOptions(comboboxEl, ['2']);
195195

196196
// ASSERT
197197
expect(visitSpy).toHaveBeenCalledOnce();

resources/js/features/comments/GameClaimsCommentsMainRoot/GameClaimsCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ describe('Component: GameClaimsCommentsMainRoot', () => {
166166
// ACT
167167
const comboboxEl = screen.getAllByRole('combobox')[0];
168168
await userEvent.click(comboboxEl);
169-
await userEvent.click(screen.getByRole('option', { name: '2' }));
169+
await userEvent.selectOptions(comboboxEl, ['2']);
170170

171171
// ASSERT
172172
expect(visitSpy).toHaveBeenCalledOnce();

resources/js/features/comments/GameCommentsMainRoot/GameCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ describe('Component: GameCommentsMainRoot', () => {
182182
// ACT
183183
const comboboxEl = screen.getAllByRole('combobox')[0];
184184
await userEvent.click(comboboxEl);
185-
await userEvent.click(screen.getByRole('option', { name: '2' }));
185+
await userEvent.selectOptions(comboboxEl, ['2']);
186186

187187
// ASSERT
188188
expect(visitSpy).toHaveBeenCalledOnce();

resources/js/features/comments/GameHashesCommentsMainRoot/GameHashesCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ describe('Component: GameHashesCommentsMainRoot', () => {
166166
// ACT
167167
const comboboxEl = screen.getAllByRole('combobox')[0];
168168
await userEvent.click(comboboxEl);
169-
await userEvent.click(screen.getByRole('option', { name: '2' }));
169+
await userEvent.selectOptions(comboboxEl, ['2']);
170170

171171
// ASSERT
172172
expect(visitSpy).toHaveBeenCalledOnce();

resources/js/features/comments/GameModificationCommentsMainRoot/GameModificationCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ describe('Component: GameModificationCommentsMainRoot', () => {
184184
// ACT
185185
const comboboxEl = screen.getAllByRole('combobox')[0];
186186
await userEvent.click(comboboxEl);
187-
await userEvent.click(screen.getByRole('option', { name: '2' }));
187+
await userEvent.selectOptions(comboboxEl, ['2']);
188188

189189
// ASSERT
190190
expect(visitSpy).toHaveBeenCalledOnce();

resources/js/features/comments/LeaderboardCommentsMainRoot/LeaderboardCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ describe('Component: LeaderboardCommentsMainRoot', () => {
159159
// ACT
160160
const comboboxEl = screen.getAllByRole('combobox')[0];
161161
await userEvent.click(comboboxEl);
162-
await userEvent.click(screen.getByRole('option', { name: '2' }));
162+
await userEvent.selectOptions(comboboxEl, ['2']);
163163

164164
// ASSERT
165165
expect(visitSpy).toHaveBeenCalledOnce();

resources/js/features/comments/UserCommentsMainRoot/UserCommentsMainRoot.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ describe('Component: UserCommentsMainRoot', () => {
179179
// ACT
180180
const comboboxEl = screen.getAllByRole('combobox')[0];
181181
await userEvent.click(comboboxEl);
182-
await userEvent.click(screen.getByRole('option', { name: '2' }));
182+
await userEvent.selectOptions(comboboxEl, ['2']);
183183

184184
// ASSERT
185185
expect(visitSpy).toHaveBeenCalledOnce();

0 commit comments

Comments
 (0)