1
- import { useState } from 'react'
2
- import { SelectPickerOptionType } from '@Shared/Components'
1
+ import { ReactElement , useState } from 'react'
2
+ import { Icon , IconsProps , SelectPickerOptionType } from '@Shared/Components'
3
3
import { ComponentSizeType } from '@Shared/constants'
4
+ import './segmentedControl.scss'
5
+ import { ConditionalWrap , Tooltip , TooltipProps } from '..'
4
6
5
- type SegmentType = Pick < SelectPickerOptionType , 'label' | 'value' | 'startIcon' | 'tooltipProps' >
7
+ type SegmentTooltipProps = Omit <
8
+ TooltipProps ,
9
+ 'alwaysShowTippyOnHover' | 'showOnTruncate' | 'shortcutKeyCombo' | 'placement'
10
+ >
11
+
12
+ type SegmentType = Pick < SelectPickerOptionType , 'value' > & {
13
+ isError ?: boolean
14
+ icon ?: IconsProps [ 'name' ]
15
+ } & (
16
+ | ( {
17
+ label : SelectPickerOptionType [ 'label' ]
18
+ icon ?: IconsProps [ 'name' ]
19
+ tooltipProps ?: SegmentTooltipProps
20
+ ariaLabel ?: never
21
+ } & Pick < SelectPickerOptionType , 'label' > )
22
+ | {
23
+ label ?: never
24
+ tooltipProps : SegmentTooltipProps
25
+ icon : IconsProps [ 'name' ]
26
+ ariaLabel : string
27
+ }
28
+ )
6
29
7
30
export interface NSegmentedControlProps {
8
31
segments : SegmentType [ ]
9
32
// initialSelectedTab: TabType['value']
10
33
onChange ?: ( selectedTab : SegmentType ) => void
11
- // disabled?: boolean
12
34
name : string
13
35
size ?: Extract < ComponentSizeType , ComponentSizeType . xs | ComponentSizeType . small | ComponentSizeType . medium >
14
36
}
15
37
16
38
export const COMPONENT_SIZE_TO_SEGMENT_CLASS_MAP : Record < NSegmentedControlProps [ 'size' ] , string > = {
17
- [ ComponentSizeType . xs ] : 'py-1 px-5' ,
18
- [ ComponentSizeType . small ] : 'py-1 px-5' ,
19
- [ ComponentSizeType . medium ] : 'py-3 px-7' ,
39
+ [ ComponentSizeType . xs ] : 'py-2 px-6 fs-12 lh-18' ,
40
+ [ ComponentSizeType . small ] : 'py-2 px-6 fs-12 lh-20' ,
41
+ [ ComponentSizeType . medium ] : 'py-4 px-8 fs-13 lh-20' ,
42
+ } as const
43
+
44
+ export const COMPONENT_SIZE_TO_ICON_CLASS_MAP : Record < NSegmentedControlProps [ 'size' ] , string > = {
45
+ [ ComponentSizeType . xs ] : 'py-1' ,
46
+ [ ComponentSizeType . small ] : 'py-2' ,
47
+ [ ComponentSizeType . medium ] : 'py-2' ,
20
48
} as const
21
49
50
+ const wrapWithTooltip = ( tooltipProps : SegmentType [ 'tooltipProps' ] ) => ( children : ReactElement ) => (
51
+ < Tooltip content = { tooltipProps . content } placement = "bottom" { ...tooltipProps } alwaysShowTippyOnHover >
52
+ { children }
53
+ </ Tooltip >
54
+ )
55
+
22
56
const NSegmentedControl = ( { segments, onChange, name, size = ComponentSizeType . medium } : NSegmentedControlProps ) => {
23
57
const [ selectedSegmentValue , setSelectedSegmentValue ] = useState < SegmentType [ 'value' ] | null > ( segments [ 0 ] . value )
24
58
@@ -28,47 +62,60 @@ const NSegmentedControl = ({ segments, onChange, name, size = ComponentSizeType.
28
62
}
29
63
30
64
return (
31
- < div >
32
- < div
33
- className = { `dc__inline-flex dc__content-center dc__align-items-center dc__gap-2 br-6 bg__tertiary ${ size === ComponentSizeType . xs ? 'p-1' : 'p-2' } ` }
34
- >
35
- { segments . map ( ( segment ) => {
36
- const isSelected = segment . value === selectedSegmentValue
65
+ < div
66
+ className = { `dc__inline-flex dc__content-center dc__align-items-center dc__gap-2 br-6 bg__tertiary ${ size === ComponentSizeType . xs ? 'p-1' : 'p-2' } ` }
67
+ >
68
+ { segments . map ( ( segment ) => {
69
+ const { value , icon , isError , label , tooltipProps , ariaLabel } = segment
70
+ const isSelected = value === selectedSegmentValue
37
71
38
- return (
72
+ return (
73
+ < ConditionalWrap
74
+ key = { value }
75
+ condition = { ! ! tooltipProps ?. content }
76
+ wrap = { wrapWithTooltip ( tooltipProps ) }
77
+ >
39
78
< div
40
- key = { segment . value }
41
- // className={`segment ${i === activeIndex ? 'active' : 'inactive'}`}
42
79
// ref={item.ref}
43
80
className = "dc__position-rel dc__text-center"
44
81
>
45
82
< input
46
83
type = "radio"
47
- value = { segment . value }
48
- id = { `${ name } -${ segment . value } ` }
84
+ value = { value }
85
+ id = { `${ name } -${ value } ` }
49
86
name = { name }
50
87
onChange = { ( ) => handleSegmentChange ( segment ) }
51
88
checked = { isSelected }
52
89
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"
53
90
/>
91
+
54
92
< label
55
- htmlFor = { `${ name } -${ segment . value } ` }
56
- className = { `pointer m-0 dc__block br-4 flex py-1 px-5 flex dc__gap-4 ${ isSelected ? 'bg__primary' : '' } ${ COMPONENT_SIZE_TO_SEGMENT_CLASS_MAP [ size ] } ` }
57
- style = {
58
- isSelected
59
- ? {
60
- border : '1px solid var(--border-secondary)' ,
61
- boxShadow : '0px 1px 2px 0px var(--black-20)' ,
62
- }
63
- : { }
64
- }
93
+ htmlFor = { `${ name } -${ value } ` }
94
+ className = { `pointer m-0 flex left dc__gap-4 br-4 dc__gap-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 ] } ` }
95
+ aria-label = { ariaLabel }
65
96
>
66
- { segment . label }
97
+ { ( isError || icon ) && (
98
+ < span className = { `flex ${ COMPONENT_SIZE_TO_ICON_CLASS_MAP [ size ] } ` } >
99
+ < Icon
100
+ { ...( isError
101
+ ? {
102
+ name : 'ic-error' ,
103
+ color : null ,
104
+ }
105
+ : {
106
+ name : icon ,
107
+ color : isSelected ? 'N900' : 'N700' ,
108
+ } ) }
109
+ size = { size === ComponentSizeType . xs ? 14 : 16 }
110
+ />
111
+ </ span >
112
+ ) }
113
+ { label && < span > { label } </ span > }
67
114
</ label >
68
115
</ div >
69
- )
70
- } ) }
71
- </ div >
116
+ </ ConditionalWrap >
117
+ )
118
+ } ) }
72
119
</ div >
73
120
)
74
121
}
0 commit comments