1
- import { ReactElement , useState } from 'react'
1
+ import { ReactElement , useEffect , useRef , useState } from 'react'
2
2
import { Icon , IconsProps , SelectPickerOptionType } from '@Shared/Components'
3
3
import { ComponentSizeType } from '@Shared/constants'
4
4
import './segmentedControl.scss'
@@ -36,6 +36,7 @@ export interface NSegmentedControlProps {
36
36
onChange ?: ( selectedTab : SegmentType ) => void
37
37
name : string
38
38
size ?: Extract < ComponentSizeType , ComponentSizeType . xs | ComponentSizeType . small | ComponentSizeType . medium >
39
+ fullWidth ?: boolean
39
40
}
40
41
41
42
export const COMPONENT_SIZE_TO_SEGMENT_CLASS_MAP : Record < NSegmentedControlProps [ 'size' ] , string > = {
@@ -62,70 +63,88 @@ const NSegmentedControl = ({
62
63
name,
63
64
size = ComponentSizeType . medium ,
64
65
value : controlledValue ,
66
+ fullWidth = false ,
65
67
} : NSegmentedControlProps ) => {
68
+ const segmentedControlRefContainer = useRef < HTMLDivElement > ( null )
69
+ const selectedSegmentRef = useRef < HTMLDivElement > ( null )
66
70
const [ selectedSegmentValue , setSelectedSegmentValue ] = useState < SegmentType [ 'value' ] | null > ( segments [ 0 ] . value )
67
71
const segmentValue = controlledValue === undefined ? selectedSegmentValue : controlledValue
68
72
73
+ useEffect ( ( ) => {
74
+ if ( segmentValue ) {
75
+ const { offsetWidth, offsetLeft } = selectedSegmentRef . current
76
+ const { style } = segmentedControlRefContainer . current
77
+
78
+ style . setProperty ( '--segmented-control-highlight-width' , `${ offsetWidth } px` )
79
+ style . setProperty ( '--segmented-control-highlight-x-position' , `${ offsetLeft } px` )
80
+ }
81
+ } , [ segmentValue , size , fullWidth ] )
82
+
69
83
const handleSegmentChange = ( updatedSegment : SegmentType ) => {
70
84
setSelectedSegmentValue ( updatedSegment . value )
71
85
onChange ?.( updatedSegment )
72
86
}
73
87
74
88
return (
75
89
< div
76
- className = { `segmented-control dc__inline-flex dc__content-center dc__align-items-center dc__gap-2 br-6 ${ size === ComponentSizeType . xs ? 'p-1' : 'p-2' } ` }
90
+ className = { `segmented-control ${ ! fullWidth ? ' dc__inline-flex' : '' } br-6 ${ size === ComponentSizeType . xs ? 'p-1' : 'p-2' } ` }
77
91
>
78
- { segments . map ( ( segment ) => {
79
- const { value, icon, isError, label, tooltipProps, ariaLabel } = segment
80
- const isSelected = value === segmentValue
92
+ < div
93
+ className = "segmented-control__container flex left dc__position-rel dc__align-items-center dc__gap-2"
94
+ ref = { segmentedControlRefContainer }
95
+ >
96
+ { segments . map ( ( segment ) => {
97
+ const { value, icon, isError, label, tooltipProps, ariaLabel } = segment
98
+ const isSelected = value === segmentValue
81
99
82
- return (
83
- < ConditionalWrap
84
- key = { value }
85
- condition = { ! ! tooltipProps ?. content }
86
- wrap = { wrapWithTooltip ( tooltipProps ) }
87
- >
88
- < div
89
- // ref={item.ref}
90
- className = "dc__position-rel dc__text-center"
100
+ return (
101
+ < ConditionalWrap
102
+ key = { value }
103
+ condition = { ! ! tooltipProps ?. content }
104
+ wrap = { wrapWithTooltip ( tooltipProps ) }
91
105
>
92
- < input
93
- type = "radio"
94
- value = { value }
95
- id = { `${ name } -${ value } ` }
96
- name = { name }
97
- onChange = { ( ) => handleSegmentChange ( segment ) }
98
- checked = { isSelected }
99
- className = "dc__opacity-0 m-0-imp dc__top-0 dc__left-0 dc__position-abs dc__bottom-0 dc__right-0 w-100 pointer h-100 dc__visibility-hidden"
100
- />
101
-
102
- < label
103
- htmlFor = { `${ name } -${ value } ` }
104
- className = { `pointer m-0 flex left dc__gap-4 br-4 segmented-control__segment segmented-control__segment--${ size } ${ isSelected ? 'bg__primary fw-6 segmented-control__segment--selected' : 'fw-4' } ${ segment . isError ? 'cr-5' : 'cn-9' } ${ COMPONENT_SIZE_TO_SEGMENT_CLASS_MAP [ size ] } ` }
105
- aria-label = { ariaLabel }
106
+ < div
107
+ className = { `dc__position-rel dc__text-center ${ fullWidth ? 'flex-grow-1' : '' } ` }
108
+ ref = { isSelected ? selectedSegmentRef : undefined }
106
109
>
107
- { ( isError || icon ) && (
108
- < span className = { `flex ${ COMPONENT_SIZE_TO_ICON_CLASS_MAP [ size ] } ` } >
109
- < Icon
110
- { ...( isError
111
- ? {
112
- name : 'ic-error' ,
113
- color : null ,
114
- }
115
- : {
116
- name : icon ,
117
- color : isSelected ? 'N900' : 'N700' ,
118
- } ) }
119
- size = { size === ComponentSizeType . xs ? 14 : 16 }
120
- />
121
- </ span >
122
- ) }
123
- { label && < span > { label } </ span > }
124
- </ label >
125
- </ div >
126
- </ ConditionalWrap >
127
- )
128
- } ) }
110
+ < input
111
+ type = "radio"
112
+ value = { value }
113
+ id = { `${ name } -${ value } ` }
114
+ name = { name }
115
+ onChange = { ( ) => handleSegmentChange ( segment ) }
116
+ checked = { isSelected }
117
+ className = "dc__opacity-0 m-0-imp dc__top-0 dc__left-0 dc__position-abs dc__bottom-0 dc__right-0 w-100 pointer h-100 dc__visibility-hidden"
118
+ />
119
+
120
+ < label
121
+ htmlFor = { `${ name } -${ value } ` }
122
+ className = { `pointer m-0 flex ${ ! fullWidth ? 'left' : '' } dc__gap-4 br-4 segmented-control__segment segmented-control__segment--${ size } ${ isSelected ? 'fw-6 segmented-control__segment--selected' : 'fw-4' } ${ segment . isError ? 'cr-5' : 'cn-9' } ${ COMPONENT_SIZE_TO_SEGMENT_CLASS_MAP [ size ] } ` }
123
+ aria-label = { ariaLabel }
124
+ >
125
+ { ( isError || icon ) && (
126
+ < span className = { `flex ${ COMPONENT_SIZE_TO_ICON_CLASS_MAP [ size ] } ` } >
127
+ < Icon
128
+ { ...( isError
129
+ ? {
130
+ name : 'ic-error' ,
131
+ color : null ,
132
+ }
133
+ : {
134
+ name : icon ,
135
+ color : isSelected ? 'N900' : 'N700' ,
136
+ } ) }
137
+ size = { size === ComponentSizeType . xs ? 14 : 16 }
138
+ />
139
+ </ span >
140
+ ) }
141
+ { label && < span > { label } </ span > }
142
+ </ label >
143
+ </ div >
144
+ </ ConditionalWrap >
145
+ )
146
+ } ) }
147
+ </ div >
129
148
</ div >
130
149
)
131
150
}
0 commit comments