@@ -77,30 +77,56 @@ export function MorphemeBox({
7777 return (
7878 < PopoverAnchor asChild >
7979 < div
80- className = { `tw:inline-grid tw:w-fit tw:items-center tw:gap-x-0.5 tw:gap-y-0.5 tw:rounded tw:border tw:bg-background tw:p-0.5${ popoverOpen ? ' tw:ring-1 tw:ring-ring' : ' tw:border-border ' } ` }
80+ className = { `tw:inline-grid tw:w-fit tw:items-center tw:gap-x-0.5 tw:gap-y-0.5 tw:rounded tw:border tw:border-border tw: bg-background tw:p-0.5${ popoverOpen ? ' tw:ring-1 tw:ring-ring' : '' } ` }
8181 style = { { gridTemplateColumns : `repeat(${ morphemes . length } , minmax(1ch, auto))` } }
8282 >
83- { /* Forms row: one clickable cell per morpheme, exposed to assistive tech as a single
84- "edit breakdown" control. The cells share grid columns with the gloss inputs below so
85- each form sits directly above its gloss. */ }
86- { morphemes . map ( ( m , i ) => (
87- < button
88- key = { m . id }
89- aria-label = { i === 0 ? editLabel : undefined }
90- className = { `tw:flex tw:items-center tw:justify-center tw:whitespace-nowrap tw:rounded tw:px-0.5 tw:font-mono tw:text-xs tw:text-muted-foreground tw:transition-colors${ disabled ? '' : ' tw:cursor-pointer' } ${ isFormsHovered && ! disabled ? ' tw:bg-accent' : '' } ` }
91- style = { { gridColumn : i + 1 , gridRow : 1 } }
92- tabIndex = { i === 0 ? 0 : - 1 }
93- type = "button"
94- onClick = { ( e ) => {
95- e . preventDefault ( ) ;
96- if ( ! disabled ) onEditBreakdown ( ) ;
97- } }
98- onMouseEnter = { ( ) => setIsFormsHovered ( true ) }
99- onMouseLeave = { ( ) => setIsFormsHovered ( false ) }
100- >
101- { m . form }
102- </ button >
103- ) ) }
83+ { /* Forms row. The first cell is the single accessible "edit breakdown" control (a real
84+ button); the rest are presentational form cells that share its click and hover behavior
85+ but carry no button semantics, so assistive tech sees one control for the whole
86+ breakdown. The cells share grid columns with the gloss inputs below so each form sits
87+ directly above its gloss. */ }
88+ { morphemes . map ( ( m , i ) => {
89+ const formClassName = `tw:flex tw:items-center tw:justify-center tw:whitespace-nowrap tw:rounded tw:px-0.5 tw:font-mono tw:text-xs tw:text-muted-foreground tw:transition-colors${ disabled ? '' : ' tw:cursor-pointer' } ${ isFormsHovered && ! disabled ? ' tw:bg-accent' : '' } ` ;
90+ const formStyle = { gridColumn : i + 1 , gridRow : 1 } ;
91+ const handleClick = ( ) => {
92+ if ( ! disabled ) onEditBreakdown ( ) ;
93+ } ;
94+ const handleMouseEnter = ( ) => setIsFormsHovered ( true ) ;
95+ const handleMouseLeave = ( ) => setIsFormsHovered ( false ) ;
96+
97+ if ( i === 0 )
98+ return (
99+ < button
100+ key = { m . id }
101+ aria-label = { editLabel }
102+ className = { formClassName }
103+ style = { formStyle }
104+ type = "button"
105+ onClick = { ( e ) => {
106+ e . preventDefault ( ) ;
107+ handleClick ( ) ;
108+ } }
109+ onMouseEnter = { handleMouseEnter }
110+ onMouseLeave = { handleMouseLeave }
111+ >
112+ { m . form }
113+ </ button >
114+ ) ;
115+
116+ return (
117+ < span
118+ key = { m . id }
119+ aria-hidden = "true"
120+ className = { formClassName }
121+ style = { formStyle }
122+ onClick = { handleClick }
123+ onMouseEnter = { handleMouseEnter }
124+ onMouseLeave = { handleMouseLeave }
125+ >
126+ { m . form }
127+ </ span >
128+ ) ;
129+ } ) }
104130 { /* Gloss row: each input fills its column and sits directly under its morpheme form. */ }
105131 { morphemes . map ( ( m , i ) => (
106132 < MorphemeGlossInput
0 commit comments