@@ -104,7 +104,7 @@ const InternalSegmentedOption: React.FC<{
104104
105105 return (
106106 < label
107- className = { classNames ( ` ${ prefixCls } -item` , className , {
107+ className = { classNames ( className , {
108108 [ `${ prefixCls } -item-disabled` ] : disabled ,
109109 } ) }
110110 >
@@ -155,7 +155,7 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
155155 } , [ options ] ) ;
156156
157157 const [ selected , setSelected ] = useMergedState ( segmentedOptions [ 0 ] ?. value , {
158- value,
158+ value : props . value ,
159159 defaultValue,
160160 } ) ;
161161
@@ -165,24 +165,60 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
165165
166166 const [ thumbShow , setThumbShow ] = React . useState ( false ) ;
167167
168- const calcThumbMoveStatus = (
169- event : React . ChangeEvent < HTMLInputElement > ,
170- ) => {
171- const toElement = event . target . closest ( `.${ prefixCls } -item` ) ;
168+ const doThumbAnimation = React . useCallback (
169+ ( selectedValue : SegmentedRawOption ) => {
170+ const segmentedItemIndex = segmentedOptions . findIndex (
171+ ( n ) => n . value === selectedValue ,
172+ ) ;
172173
173- const fromElement = containerRef . current ?. querySelector (
174- `. ${ prefixCls } -item-selected` ,
175- ) ;
174+ if ( segmentedItemIndex < 0 ) {
175+ return ;
176+ }
176177
177- if ( fromElement && toElement && thumbMoveStatus . current ) {
178- thumbMoveStatus . current . from = calcThumbStyle (
179- fromElement as HTMLElement ,
178+ // find target element
179+ const toElement = containerRef . current ?. querySelector (
180+ `. ${ prefixCls } -item:nth-child( ${ segmentedItemIndex + 1 } )` ,
180181 ) ;
181- thumbMoveStatus . current . to = calcThumbStyle ( toElement as HTMLElement ) ;
182182
183- setThumbShow ( true ) ;
183+ if ( toElement ) {
184+ // find source element
185+ const fromElement = containerRef . current ?. querySelector (
186+ `.${ prefixCls } -item-selected` ,
187+ ) ;
188+ 189+ if ( fromElement && toElement && thumbMoveStatus . current ) {
190+ // calculate for thumb moving animation
191+ thumbMoveStatus . current . from = calcThumbStyle (
192+ fromElement as HTMLElement ,
193+ ) ;
194+ thumbMoveStatus . current . to = calcThumbStyle (
195+ toElement as HTMLElement ,
196+ ) ;
197+ 198+ // trigger css-motion starts
199+ setThumbShow ( true ) ;
200+ }
201+ }
202+ } ,
203+ [ prefixCls , segmentedOptions ] ,
204+ ) ;
205+ 206+ // get latest version of `visualSelected`
207+ const latestVisualSelected = React . useRef ( visualSelected ) ;
208+ React . useEffect ( ( ) => {
209+ latestVisualSelected . current = visualSelected ;
210+ } ) ;
211+ 212+ React . useEffect ( ( ) => {
213+ // Syncing `visualSelected` when `selected` changed
214+ // and do thumb animation
215+ if (
216+ ( typeof selected === 'string' || typeof selected === 'number' ) &&
217+ selected !== latestVisualSelected . current
218+ ) {
219+ doThumbAnimation ( selected ) ;
184220 }
185- } ;
221+ } , [ selected ] ) ;
186222
187223 const handleChange = (
188224 event : React . ChangeEvent < HTMLInputElement > ,
@@ -192,8 +228,6 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
192228 return ;
193229 }
194230
195- calcThumbMoveStatus ( event ) ;
196- 197231 setSelected ( val ) ;
198232
199233 if ( onChange ) {
@@ -275,10 +309,14 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>(
275309 < InternalSegmentedOption
276310 key = { segmentedOption . value }
277311 prefixCls = { prefixCls }
278- className = { classNames ( segmentedOption . className , {
279- [ `${ prefixCls } -item-selected` ] :
280- segmentedOption . value === visualSelected ,
281- } ) }
312+ className = { classNames (
313+ segmentedOption . className ,
314+ `${ prefixCls } -item` ,
315+ {
316+ [ `${ prefixCls } -item-selected` ] :
317+ segmentedOption . value === visualSelected ,
318+ } ,
319+ ) }
282320 checked = { segmentedOption . value === selected }
283321 onChange = { handleChange }
284322 { ...segmentedOption }
0 commit comments