@@ -3,28 +3,20 @@ import { Select } from '@lambdacurry/forms/remix-hook-form/select';
33import { Button } from '@lambdacurry/forms/ui/button' ;
44import type { Meta , StoryObj } from '@storybook/react-vite' ;
55import { expect , userEvent , within } from '@storybook/test' ;
6+ import clsx from 'clsx' ;
67import * as React from 'react' ;
78import { type ActionFunctionArgs , useFetcher } from 'react-router' ;
89import { RemixFormProvider , getValidatedFormData , useRemixForm } from 'remix-hook-form' ;
910import { z } from 'zod' ;
1011import { withReactRouterStubDecorator } from '../lib/storybook/react-router-stub' ;
1112
1213const formSchema = z . object ( {
13- region : z . string ( ) . min ( 1 , 'Please select a region' ) ,
1414 theme : z . string ( ) . min ( 1 , 'Please select a theme' ) ,
1515 fruit : z . string ( ) . min ( 1 , 'Please select a fruit' ) ,
1616} ) ;
1717
1818type FormData = z . infer < typeof formSchema > ;
1919
20- const regionOptions = [
21- { label : 'California' , value : 'CA' } ,
22- { label : 'Ontario' , value : 'ON' } ,
23- { label : 'New York' , value : 'NY' } ,
24- { label : 'Quebec' , value : 'QC' } ,
25- { label : 'Texas' , value : 'TX' } ,
26- ] ;
27-
2820const themeOptions = [
2921 { label : 'Default' , value : 'default' } ,
3022 { label : 'Purple' , value : 'purple' } ,
@@ -45,10 +37,10 @@ const PurpleTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttrib
4537 ref = { ref }
4638 type = "button"
4739 { ...props }
48- className = {
49- 'flex items-center justify-between w-full rounded-md border-2 border-purple-300 bg-purple-50 px-3 py-2 h-10 text-sm text-purple-900 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 ' +
50- ( props . className || '' )
51- }
40+ className = { clsx (
41+ 'flex items-center justify-between w-full rounded-md border-2 border-purple-300 bg-purple-50 px-3 py-2 h-10 text-sm text-purple-900 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2' ,
42+ props . className ,
43+ ) }
5244 />
5345 ) ,
5446) ;
@@ -63,10 +55,10 @@ const PurpleItem = React.forwardRef<
6355 ref = { ref }
6456 type = "button"
6557 { ...props }
66- className = {
67- 'w-full text-left cursor-pointer select-none py-3 px-3 transition-colors duration-150 flex items-center gap-2 rounded text-purple-900 hover:bg-purple-100 data-[selected=true]:bg-purple-100 ' +
68- ( props . className || '' )
69- }
58+ className = { clsx (
59+ 'w-full text-left cursor-pointer select-none py-3 px-3 transition-colors duration-150 flex items-center gap-2 rounded text-purple-900 hover:bg-purple-100 data-[selected=true]:bg-purple-100' ,
60+ props . className ,
61+ ) }
7062 />
7163) ) ;
7264PurpleItem . displayName = 'PurpleItem' ;
@@ -77,7 +69,10 @@ const PurpleSearchInput = React.forwardRef<HTMLInputElement, React.InputHTMLAttr
7769 < input
7870 ref = { ref }
7971 { ...props }
80- className = { 'w-full h-9 rounded-md bg-white px-2 text-sm leading-none border-2 border-purple-200 focus:border-purple-400 focus:outline-none ' + ( props . className || '' ) }
72+ className = { clsx (
73+ 'w-full h-9 rounded-md bg-white px-2 text-sm leading-none border-2 border-purple-200 focus:border-purple-400 focus:outline-none' ,
74+ props . className ,
75+ ) }
8176 />
8277 ) ,
8378) ;
@@ -92,10 +87,10 @@ const GreenItem = React.forwardRef<
9287 ref = { ref }
9388 type = "button"
9489 { ...props }
95- className = {
96- 'w-full text-left cursor-pointer select-none py-3 px-3 transition-colors duration-150 flex items-center gap-2 rounded hover:bg-emerald-100 data-[selected=true]:bg-emerald-100 ' +
97- ( props . className || '' )
98- }
90+ className = { clsx (
91+ 'w-full text-left cursor-pointer select-none py-3 px-3 transition-colors duration-150 flex items-center gap-2 rounded hover:bg-emerald-100 data-[selected=true]:bg-emerald-100' ,
92+ props . className ,
93+ ) }
9994 />
10095) ) ;
10196GreenItem . displayName = 'GreenItem' ;
@@ -106,7 +101,6 @@ const SelectCustomizationExample = () => {
106101 const methods = useRemixForm < FormData > ( {
107102 resolver : zodResolver ( formSchema ) ,
108103 defaultValues : {
109- region : '' ,
110104 theme : '' ,
111105 fruit : '' ,
112106 } ,
@@ -118,15 +112,6 @@ const SelectCustomizationExample = () => {
118112 < RemixFormProvider { ...methods } >
119113 < fetcher . Form onSubmit = { methods . handleSubmit } className = "space-y-6" >
120114 < div className = "grid gap-6 w-[320px]" >
121- { /* Default Select */ }
122- < Select
123- name = "region"
124- label = "Region"
125- description = "Default Select styling"
126- options = { regionOptions }
127- placeholder = "Select a region"
128- />
129-
130115 { /* Custom Trigger and Item using components */ }
131116 < Select
132117 name = "theme"
@@ -231,17 +216,17 @@ Each custom component should use React.forwardRef to preserve focus, ARIA, and k
231216 await step ( 'Open and choose Theme' , async ( ) => {
232217 const themeSelect = canvas . getByLabelText ( 'Theme' ) ;
233218 await userEvent . click ( themeSelect ) ;
234- const purple = await within ( document . body ) . findByRole ( 'option' , { name : 'Purple' } ) ;
235- await userEvent . click ( purple ) ;
236- expect ( themeSelect ) . toHaveTextContent ( 'Purple' ) ;
219+ const listbox = await within ( document . body ) . findByRole ( 'listbox' ) ;
220+ await userEvent . click ( within ( listbox ) . getByRole ( 'option' , { name : / P u r p l e / i } ) ) ;
221+ await expect ( canvas . findByRole ( 'combobox' , { name : 'Theme' } ) ) . resolves . toHaveTextContent ( 'Purple' ) ;
237222 } ) ;
238223
239224 await step ( 'Open and choose Fruit' , async ( ) => {
240225 const fruitSelect = canvas . getByLabelText ( 'Favorite Fruit' ) ;
241226 await userEvent . click ( fruitSelect ) ;
242- const banana = await within ( document . body ) . findByRole ( 'option' , { name : '🍌 Banana' } ) ;
243- await userEvent . click ( banana ) ;
244- expect ( fruitSelect ) . toHaveTextContent ( '🍌 Banana' ) ;
227+ const listbox = await within ( document . body ) . findByRole ( 'listbox' ) ;
228+ await userEvent . click ( within ( listbox ) . getByTestId ( 'select-option- banana' ) ) ;
229+ await expect ( canvas . findByRole ( 'combobox' , { name : 'Favorite Fruit' } ) ) . resolves . toHaveTextContent ( 'Banana' ) ;
245230 } ) ;
246231
247232 await step ( 'Submit the form' , async ( ) => {
0 commit comments