@companix/uikit 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/dist/Button/index.d.ts +20 -0
  2. package/dist/ButtonGroup/index.d.ts +7 -0
  3. package/dist/Checkbox/index.d.ts +10 -0
  4. package/dist/Countdown/index.d.ts +7 -0
  5. package/dist/DateInput/index.d.ts +13 -0
  6. package/dist/DatePicker/Calendar.d.ts +14 -0
  7. package/dist/DatePicker/CalendarHeader.d.ts +10 -0
  8. package/dist/DatePicker/index.d.ts +12 -0
  9. package/dist/Dialog/index.d.ts +12 -0
  10. package/dist/DialogAlert/Alert.d.ts +19 -0
  11. package/dist/DialogAlert/Viewport.d.ts +8 -0
  12. package/dist/DialogAlert/index.d.ts +11 -0
  13. package/dist/Drawer/index.d.ts +13 -0
  14. package/dist/File/index.d.ts +10 -0
  15. package/dist/Form/index.d.ts +17 -0
  16. package/dist/Icon/index.d.ts +7 -0
  17. package/dist/LoadButton/index.d.ts +5 -0
  18. package/dist/NumberInput/index.d.ts +6 -0
  19. package/dist/OptionItem/OptionItem.d.ts +7 -0
  20. package/dist/OptionItem/OptionsList.d.ts +8 -0
  21. package/dist/Popover/index.d.ts +26 -0
  22. package/dist/Radio/index.d.ts +20 -0
  23. package/dist/Scrollable/ImitateScroll.d.ts +10 -0
  24. package/dist/Scrollable/index.d.ts +33 -0
  25. package/dist/Select/SelectInput.d.ts +14 -0
  26. package/dist/Select/index.d.ts +15 -0
  27. package/dist/SelectTags/index.d.ts +15 -0
  28. package/dist/Spinner/index.d.ts +8 -0
  29. package/dist/Stepper/index.d.ts +8 -0
  30. package/dist/Switch/index.d.ts +10 -0
  31. package/dist/Tabs/index.d.ts +13 -0
  32. package/dist/TextArea/index.d.ts +7 -0
  33. package/dist/Toaster/RemoveListener.d.ts +3 -0
  34. package/dist/Toaster/Toast.d.ts +9 -0
  35. package/dist/Toaster/Viewport.d.ts +13 -0
  36. package/dist/Toaster/index.d.ts +15 -0
  37. package/dist/Tooltip/index.d.ts +8 -0
  38. package/dist/__hooks/use-frooze-closing.d.ts +5 -0
  39. package/dist/__hooks/use-loading.d.ts +8 -0
  40. package/dist/__hooks/use-local-storage.d.ts +1 -0
  41. package/dist/__hooks/use-popover-position.d.ts +8 -0
  42. package/dist/__hooks/use-previos.d.ts +2 -0
  43. package/dist/__hooks/use-resize.d.ts +3 -0
  44. package/dist/__hooks/use-scrollbox.d.ts +7 -0
  45. package/dist/__hooks/use-stepper-input.d.ts +13 -0
  46. package/dist/__hooks/use-update.d.ts +1 -0
  47. package/dist/__hooks/useCalendar.d.ts +17 -0
  48. package/dist/__hooks/useCalendarOptions-copy.d.ts +22 -0
  49. package/dist/__hooks/useCalendarOptions.d.ts +31 -0
  50. package/dist/__libs/calendar.d.ts +25 -0
  51. package/dist/__utils/utils.d.ts +25 -0
  52. package/dist/bundle.es.js +58 -0
  53. package/dist/bundle.es10.js +38 -0
  54. package/dist/bundle.es11.js +33 -0
  55. package/dist/bundle.es12.js +18 -0
  56. package/dist/bundle.es13.js +10 -0
  57. package/dist/bundle.es14.js +35 -0
  58. package/dist/bundle.es15.js +27 -0
  59. package/dist/bundle.es16.js +23 -0
  60. package/dist/bundle.es17.js +24 -0
  61. package/dist/bundle.es18.js +15 -0
  62. package/dist/bundle.es19.js +40 -0
  63. package/dist/bundle.es2.js +45 -0
  64. package/dist/bundle.es20.js +18 -0
  65. package/dist/bundle.es21.js +36 -0
  66. package/dist/bundle.es22.js +23 -0
  67. package/dist/bundle.es23.js +42 -0
  68. package/dist/bundle.es24.js +113 -0
  69. package/dist/bundle.es25.js +114 -0
  70. package/dist/bundle.es26.js +38 -0
  71. package/dist/bundle.es27.js +13 -0
  72. package/dist/bundle.es28.js +27 -0
  73. package/dist/bundle.es29.js +38 -0
  74. package/dist/bundle.es3.js +13 -0
  75. package/dist/bundle.es30.js +26 -0
  76. package/dist/bundle.es31.js +83 -0
  77. package/dist/bundle.es32.js +20 -0
  78. package/dist/bundle.es33.js +16 -0
  79. package/dist/bundle.es34.js +24 -0
  80. package/dist/bundle.es35.js +7 -0
  81. package/dist/bundle.es36.js +23 -0
  82. package/dist/bundle.es37.js +16 -0
  83. package/dist/bundle.es38.js +72 -0
  84. package/dist/bundle.es39.js +70 -0
  85. package/dist/bundle.es4.js +87 -0
  86. package/dist/bundle.es40.js +34 -0
  87. package/dist/bundle.es41.js +70 -0
  88. package/dist/bundle.es42.js +33 -0
  89. package/dist/bundle.es43.js +77 -0
  90. package/dist/bundle.es44.js +51 -0
  91. package/dist/bundle.es45.js +45 -0
  92. package/dist/bundle.es5.js +87 -0
  93. package/dist/bundle.es6.js +80 -0
  94. package/dist/bundle.es7.js +28 -0
  95. package/dist/bundle.es8.js +87 -0
  96. package/dist/bundle.es9.js +75 -0
  97. package/dist/index.d.ts +30 -0
  98. package/{src → dist}/index.scss +3 -0
  99. package/{src → dist}/mixins.scss +4 -3
  100. package/{src → dist}/theme.scss +0 -2
  101. package/dist/types.d.ts +13 -0
  102. package/package.json +10 -6
  103. package/.eslintrc +0 -54
  104. package/declaration.d.ts +0 -4
  105. package/index.html +0 -12
  106. package/playground/App.tsx +0 -166
  107. package/playground/Example.tsx +0 -14
  108. package/playground/Test.tsx +0 -44
  109. package/playground/animation-test-1/index.scss +0 -20
  110. package/playground/animation-test-1/index.tsx +0 -17
  111. package/playground/animation-test-2/index.scss +0 -62
  112. package/playground/animation-test-2/index.tsx +0 -32
  113. package/playground/bootstrap.tsx +0 -19
  114. package/playground/buttons/index.tsx +0 -132
  115. package/playground/checkbox/index.tsx +0 -64
  116. package/playground/date-input/index.tsx +0 -45
  117. package/playground/date-picker/index.tsx +0 -41
  118. package/playground/dialog/index.tsx +0 -92
  119. package/playground/dialog-alert/index.tsx +0 -47
  120. package/playground/drawer/index.tsx +0 -55
  121. package/playground/index.css +0 -33
  122. package/playground/index.scss +0 -270
  123. package/playground/input/index.tsx +0 -112
  124. package/playground/number-inputs/index.tsx +0 -50
  125. package/playground/popovers/index.tsx +0 -70
  126. package/playground/radio-group/index.tsx +0 -69
  127. package/playground/select/index.tsx +0 -72
  128. package/playground/select-tags/index.tsx +0 -36
  129. package/playground/styles.scss +0 -2
  130. package/playground/switch/index.tsx +0 -44
  131. package/playground/tabs/index.tsx +0 -16
  132. package/playground/test.scss +0 -0
  133. package/playground/text-area/index.tsx +0 -17
  134. package/playground/text-input/index.tsx +0 -12
  135. package/playground/toaster/index.tsx +0 -156
  136. package/playground/tooltip/index.tsx +0 -26
  137. package/src/Button/index.tsx +0 -72
  138. package/src/ButtonGroup/index.tsx +0 -20
  139. package/src/Checkbox/index.tsx +0 -46
  140. package/src/Countdown/index.tsx +0 -54
  141. package/src/DateInput/index.tsx +0 -96
  142. package/src/DatePicker/Calendar.tsx +0 -157
  143. package/src/DatePicker/CalendarHeader.tsx +0 -139
  144. package/src/DatePicker/index.tsx +0 -177
  145. package/src/Dialog/index.tsx +0 -31
  146. package/src/DialogAlert/Alert.tsx +0 -78
  147. package/src/DialogAlert/Viewport.tsx +0 -52
  148. package/src/DialogAlert/index.tsx +0 -37
  149. package/src/Drawer/index.tsx +0 -46
  150. package/src/File/index.tsx +0 -60
  151. package/src/Form/index.tsx +0 -131
  152. package/src/Icon/index.tsx +0 -43
  153. package/src/LoadButton/index.tsx +0 -17
  154. package/src/NumberInput/index.tsx +0 -74
  155. package/src/OptionItem/OptionItem.tsx +0 -49
  156. package/src/OptionItem/OptionsList.tsx +0 -26
  157. package/src/Popover/index.tsx +0 -117
  158. package/src/Radio/index.tsx +0 -68
  159. package/src/Scrollable/ImitateScroll.tsx +0 -141
  160. package/src/Scrollable/index.tsx +0 -141
  161. package/src/Select/SelectInput.tsx +0 -131
  162. package/src/Select/index.tsx +0 -134
  163. package/src/SelectTags/index.tsx +0 -192
  164. package/src/Spinner/index.tsx +0 -19
  165. package/src/Stepper/index.tsx +0 -76
  166. package/src/Switch/index.tsx +0 -49
  167. package/src/Tabs/index.tsx +0 -89
  168. package/src/TextArea/index.tsx +0 -51
  169. package/src/Toaster/RemoveListener.tsx +0 -11
  170. package/src/Toaster/Toast.tsx +0 -69
  171. package/src/Toaster/Viewport.tsx +0 -117
  172. package/src/Toaster/index.tsx +0 -52
  173. package/src/Tooltip/index.tsx +0 -33
  174. package/src/__hooks/use-frooze-closing.ts +0 -51
  175. package/src/__hooks/use-loading.ts +0 -34
  176. package/src/__hooks/use-local-storage.ts +0 -19
  177. package/src/__hooks/use-popover-position.ts +0 -24
  178. package/src/__hooks/use-previos.ts +0 -25
  179. package/src/__hooks/use-resize.ts +0 -41
  180. package/src/__hooks/use-scrollbox.ts +0 -45
  181. package/src/__hooks/use-stepper-input.ts +0 -82
  182. package/src/__hooks/use-update.ts +0 -19
  183. package/src/__hooks/useCalendar.ts +0 -104
  184. package/src/__hooks/useCalendarOptions-copy.ts +0 -87
  185. package/src/__hooks/useCalendarOptions.ts +0 -68
  186. package/src/__libs/calendar.ts +0 -175
  187. package/src/__utils/utils.ts +0 -137
  188. package/src/index.ts +0 -36
  189. package/src/types.ts +0 -14
  190. package/tailwind.config.js +0 -91
  191. package/themes/classic/animations.scss +0 -179
  192. package/themes/classic/classic.scss +0 -493
  193. package/tsconfig.json +0 -27
  194. package/vite.build.ts +0 -35
  195. package/vite.config.ts +0 -33
  196. /package/{src → dist}/Button/Button.scss +0 -0
  197. /package/{src → dist}/ButtonGroup/ButtonGroup.scss +0 -0
  198. /package/{src → dist}/Checkbox/Checkbox.scss +0 -0
  199. /package/{src → dist}/DateInput/DateInput.scss +0 -0
  200. /package/{src → dist}/DatePicker/Calendar.scss +0 -0
  201. /package/{src → dist}/DatePicker/DatePicker.scss +0 -0
  202. /package/{src → dist}/Dialog/Dialog.scss +0 -0
  203. /package/{src → dist}/Dialog/Popup.scss +0 -0
  204. /package/{src → dist}/DialogAlert/Alert.scss +0 -0
  205. /package/{src → dist}/Drawer/Drawer.scss +0 -0
  206. /package/{src → dist}/Form/Form.scss +0 -0
  207. /package/{src → dist}/Form/Input.scss +0 -0
  208. /package/{src → dist}/Icon/icon.scss +0 -0
  209. /package/{src → dist}/OptionItem/Option.scss +0 -0
  210. /package/{src → dist}/Popover/Popover.scss +0 -0
  211. /package/{src → dist}/Radio/Radio.scss +0 -0
  212. /package/{src → dist}/Scrollable/Scrollable.scss +0 -0
  213. /package/{src → dist}/Select/Select.scss +0 -0
  214. /package/{src → dist}/SelectTags/SelectTags.scss +0 -0
  215. /package/{src → dist}/Spinner/Spinner.scss +0 -0
  216. /package/{src → dist}/Stepper/StepperInput.scss +0 -0
  217. /package/{src → dist}/Switch/Switch.scss +0 -0
  218. /package/{src → dist}/Tabs/Tabs.scss +0 -0
  219. /package/{src → dist}/TextArea/TextArea.scss +0 -0
  220. /package/{src → dist}/Toaster/Toaster.scss +0 -0
  221. /package/{src → dist}/Tooltip/Tooltip.scss +0 -0
  222. /package/{src/css.scss → dist/css-properties.scss} +0 -0
@@ -1,141 +0,0 @@
1
- import cn from 'classnames'
2
-
3
- import { useRef, useLayoutEffect, useMemo, useCallback, useEffect } from 'react'
4
- import { getContainers, pc, px } from '@companix/utils-browser'
5
-
6
- interface Props {
7
- children: React.ReactNode
8
- thumbClassName: string
9
- thumbColor?: string
10
- trackWidth?: number
11
- thumbMargin?: number
12
- scrollableClassName?: string
13
- }
14
-
15
- // Отслеживание изменений scrollHeight:
16
- // https://stackoverflow.com/questions/44428370/detect-scrollheight-change-with-mutationobserver
17
-
18
- const ImitateScroll = ({
19
- children,
20
- thumbClassName,
21
- scrollableClassName,
22
- thumbMargin = 0,
23
- trackWidth = 20
24
- }: Props) => {
25
- const scrollThumbRef = useRef<HTMLDivElement>(null)
26
- const scrollableRef = useRef<HTMLDivElement>(null)
27
-
28
- const data = useMemo(() => {
29
- return { positons: { top: 0, y: 0 }, scrollRatio: 0 }
30
- }, [])
31
-
32
- const listeners = useMemo(() => {
33
- return {
34
- start() {
35
- document.addEventListener('mousemove', handleMouseMove)
36
- document.addEventListener('mouseup', handleMouseUp)
37
- },
38
- clear() {
39
- document.removeEventListener('mousemove', handleMouseMove)
40
- document.removeEventListener('mouseup', handleMouseUp)
41
- }
42
- }
43
- }, [])
44
-
45
- useEffect(() => {
46
- const observer = new ResizeObserver(setThumbHeight)
47
-
48
- if (scrollableRef.current) {
49
- getContainers(scrollableRef.current, (element) => {
50
- observer.observe(element)
51
- })
52
- }
53
-
54
- return () => {
55
- if (scrollableRef.current) {
56
- getContainers(scrollableRef.current, (element) => {
57
- observer.unobserve(element)
58
- })
59
- }
60
- }
61
- }, [])
62
-
63
- useLayoutEffect(() => {
64
- setThumbHeight()
65
- }, [])
66
-
67
- const setThumbHeight = useCallback(() => {
68
- const { current: container } = scrollableRef
69
- const { current: thumb } = scrollThumbRef
70
-
71
- if (thumb && container) {
72
- const scrollRatio = container.clientHeight / container.scrollHeight
73
-
74
- thumb.style.height = pc(scrollRatio * 100)
75
- thumb.style.display = scrollRatio === 1 ? 'none' : 'block'
76
-
77
- data.scrollRatio = scrollRatio
78
- }
79
- }, [])
80
-
81
- const handleMouseMove = useCallback(({ clientY }: MouseEvent) => {
82
- const { current: container } = scrollableRef
83
-
84
- if (container) {
85
- const dy = clientY - data.positons.y
86
- container.scrollTop = data.positons.top + dy / data.scrollRatio
87
- }
88
- }, [])
89
-
90
- const handleMouseUp = useCallback(() => {
91
- listeners.clear()
92
- }, [])
93
-
94
- const handleMouseDown = useCallback(({ clientY }: React.MouseEvent) => {
95
- const { current: container } = scrollableRef
96
-
97
- if (container) {
98
- data.positons = {
99
- top: container.scrollTop,
100
- y: clientY
101
- }
102
- }
103
-
104
- listeners.start()
105
- }, [])
106
-
107
- const handleScroll = () => {
108
- requestAnimationFrame(() => {
109
- const { current: container } = scrollableRef
110
- const { current: thumb } = scrollThumbRef
111
-
112
- if (thumb && container) {
113
- thumb.style.top = pc((container.scrollTop * 100) / container.scrollHeight)
114
- }
115
- })
116
- }
117
-
118
- return (
119
- <div className="relative h-full overflow-hidden">
120
- <div
121
- className={cn('hidden-scroll h-full overflow-y-scroll', scrollableClassName)}
122
- onScroll={handleScroll}
123
- ref={scrollableRef}
124
- >
125
- {children}
126
- </div>
127
- <div
128
- className="absolute right-0 top-0 box-border h-full"
129
- style={{ width: px(trackWidth), padding: px(thumbMargin) }}
130
- >
131
- <div
132
- onMouseDown={handleMouseDown}
133
- className={`${thumbClassName} relative w-full rounded-full`}
134
- ref={scrollThumbRef}
135
- />
136
- </div>
137
- </div>
138
- )
139
- }
140
-
141
- export { ImitateScroll }
@@ -1,141 +0,0 @@
1
- import './Scrollable.scss'
2
-
3
- import classNames from 'classnames'
4
- import { forwardRef } from 'react'
5
- import { px, varToStyle } from '@companix/utils-browser'
6
-
7
- interface OuterImplementation {
8
- implementation: 'outer'
9
- shadowPadding?: number
10
- scrollbarWidth: number
11
- noneCorrect?: boolean
12
- }
13
-
14
- interface EdgeImplementation {
15
- implementation: 'edge'
16
- scrollbarWidth: number
17
- padding: number
18
- }
19
-
20
- interface InnerImplementation {
21
- implementation: 'inner'
22
- padding: number
23
- }
24
-
25
- interface ScrollableProps {
26
- heightAuto?: boolean
27
- scrollX?: boolean
28
- scrollY?: boolean
29
- interactionKind?: 'static' | 'hover'
30
- thumbPos?: 'center' | 'border'
31
- thumbPadding?: number
32
- thumbColor?: string
33
- onWheel?: React.WheelEventHandler<HTMLDivElement>
34
- onScroll?: React.UIEventHandler<HTMLDivElement>
35
- maxHeight?: number
36
- children: React.ReactNode
37
- style?: React.CSSProperties
38
- className?: string
39
- }
40
-
41
- type Implementation = InnerImplementation | OuterImplementation | EdgeImplementation
42
-
43
- const Scrollable = forwardRef<HTMLDivElement, ScrollableProps & Implementation>((props, ref) => {
44
- let {
45
- interactionKind = 'static',
46
- thumbPos = 'center',
47
- thumbPadding = 4,
48
- heightAuto,
49
- scrollX,
50
- className,
51
- scrollY,
52
- onWheel,
53
- maxHeight,
54
- onScroll,
55
- thumbColor,
56
- children
57
- } = props
58
-
59
- const style: React.CSSProperties = (() => {
60
- if (props.implementation === 'edge') {
61
- thumbPadding = 0
62
-
63
- const { padding, scrollbarWidth } = props
64
-
65
- return {
66
- ...varToStyle({ '--scrollbar-width': px(scrollbarWidth) }),
67
- padding: `0px ${padding - scrollbarWidth}px 0px ${padding}px`
68
- }
69
- }
70
-
71
- if (props.implementation === 'outer') {
72
- const { shadowPadding = 0, noneCorrect, scrollbarWidth } = props
73
-
74
- if ((window as any).IS_MOBILE) {
75
- return {
76
- padding: shadowPadding,
77
- margin: -shadowPadding
78
- }
79
- }
80
-
81
- return {
82
- ...varToStyle({ '--scrollbar-width': px(scrollbarWidth) }),
83
- padding: shadowPadding,
84
- margin: -shadowPadding,
85
- marginRight: noneCorrect ? undefined : `calc(-${scrollbarWidth}px - ${shadowPadding}px)`,
86
- marginBottom: 0
87
- }
88
- }
89
-
90
- if (props.implementation === 'inner') {
91
- const { padding } = props
92
-
93
- if ((window as any).IS_MOBILE) {
94
- return {
95
- [scrollY ? 'paddingLeft' : 'paddingTop']: padding,
96
- [scrollY ? 'paddingRight' : 'paddingBottom']: padding
97
- }
98
- }
99
-
100
- return {
101
- [scrollY ? 'paddingLeft' : 'paddingTop']: padding,
102
- ...varToStyle({ '--scrollbar-width': px(padding) })
103
- }
104
- }
105
-
106
- return {}
107
- })()
108
-
109
- return (
110
- <div
111
- ref={ref}
112
- onWheel={onWheel}
113
- onScroll={onScroll}
114
- onMouseDown={(e) => {
115
- e.preventDefault()
116
- }}
117
- style={{
118
- ...style,
119
- ...props.style,
120
- ...{ maxHeight: maxHeight ? px(maxHeight) : undefined },
121
- ...varToStyle({ '--thumb-padding': px(thumbPadding) }),
122
- ...varToStyle({ '--thumb-color': thumbColor ?? '#c1c2c8bd' })
123
- }}
124
- className={classNames(
125
- !(window as any).IS_MOBILE && 'scrollable',
126
- className,
127
- heightAuto ? '' : 'h-full',
128
- {
129
- 'overflow-y-scroll': scrollY,
130
- 'overflow-x-scroll': scrollX,
131
- 'scrollable-hover-interaction': interactionKind === 'hover',
132
- 'scrollable-border-position': thumbPos === 'border'
133
- }
134
- )}
135
- >
136
- {children}
137
- </div>
138
- )
139
- })
140
-
141
- export { Scrollable }
@@ -1,131 +0,0 @@
1
- import cn from 'classnames'
2
-
3
- import { attr } from '@companix/utils-browser'
4
- import { forwardRef, useCallback, useRef } from 'react'
5
- import { Icon } from '../Icon'
6
- import { faChevronDown, faClose } from '@fortawesome/free-solid-svg-icons'
7
- import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
8
-
9
- export interface SelectFormProps extends React.HTMLAttributes<HTMLDivElement> {
10
- required?: boolean
11
- disabled?: boolean
12
- className?: string
13
- leftElement?: React.ReactNode
14
- placeholder?: string
15
- value?: string | number
16
- size?: 'sm' | 'md' | 'lg'
17
- fill?: boolean
18
- clearButton?: boolean
19
- clearButtonIcon?: boolean
20
- onClear?: (event: React.MouseEvent<HTMLButtonElement>) => void
21
- }
22
-
23
- export const SelectInput = forwardRef<HTMLDivElement, SelectFormProps>(
24
- (
25
- {
26
- required,
27
- size,
28
- fill,
29
- leftElement,
30
- className,
31
- value,
32
- clearButton,
33
- placeholder,
34
- clearButtonIcon,
35
- disabled,
36
- onClear,
37
- ...containerProps
38
- },
39
- ref
40
- ) => {
41
- const selectInputRef = useRef<HTMLInputElement>(null)
42
-
43
- // https://vkui.io/components/custom-select/
44
- const passClickAndFocusToInputOnClick = useCallback(
45
- (e: React.MouseEvent<HTMLDivElement>) => {
46
- if (!selectInputRef.current || !document) {
47
- return
48
- }
49
-
50
- const clickTargetIsNotAnInput = e.target !== selectInputRef.current
51
- if (clickTargetIsNotAnInput) {
52
- selectInputRef.current.click()
53
-
54
- const inputIsNotFocused = document.activeElement !== selectInputRef.current
55
- if (inputIsNotFocused) {
56
- selectInputRef.current.focus()
57
- }
58
- }
59
- },
60
- [selectInputRef]
61
- )
62
-
63
- const preventInputBlurWhenClickInsideFocusedSelectArea = (e: React.MouseEvent<HTMLDivElement>) => {
64
- // Так как инпут больше не оборачивается пустым лэйблом, то клик внутри обертки,
65
- // но вне инпута (например по иконке дропдауна), будет убирать фокус с инпута.
66
- // Чтобы в такой ситуации отключить blur инпута мы превентим mousedown событие обёртки
67
- const isInputFocused = document && document.activeElement === selectInputRef.current
68
- if (isInputFocused) {
69
- e.preventDefault()
70
- }
71
- }
72
-
73
- const onClick = (event: React.MouseEvent<HTMLDivElement>) => {
74
- if (disabled) return
75
- passClickAndFocusToInputOnClick(event)
76
- }
77
-
78
- const onMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
79
- preventInputBlurWhenClickInsideFocusedSelectArea(event)
80
- }
81
-
82
- const handleClear = (event: React.MouseEvent<HTMLButtonElement>) => {
83
- selectInputRef.current && selectInputRef.current.focus()
84
- onClear?.(event)
85
- }
86
-
87
- return (
88
- <div
89
- ref={ref}
90
- className={cn('form select', className)}
91
- data-size={size ?? 'md'}
92
- data-fill={attr(fill)}
93
- data-required={attr(required)}
94
- data-disabled={attr(disabled)}
95
- onMouseDown={onMouseDown}
96
- {...containerProps}
97
- onClick={onClick}
98
- >
99
- <div className="select-layout form-input">
100
- {leftElement && <div className="select-element">{leftElement}</div>}
101
- <div className="select-content">
102
- <div className="select-content-text" aria-disabled={disabled}>
103
- {!value && <span className="select-placeholder">{placeholder}</span>}
104
- {value}
105
- </div>
106
- </div>
107
- <div className="select-element">
108
- {clearButton && value && (
109
- <button className="select-close-button" onClick={handleClear}>
110
- {clearButtonIcon ?? <Icon className="select-close-icon" icon={faClose} size="xxxs" />}
111
- </button>
112
- )}
113
- <Icon className="expand-icon select-expand" icon={faChevronDown} size="xxxs" />
114
- </div>
115
- </div>
116
- <VisuallyHidden asChild>
117
- <input
118
- ref={selectInputRef}
119
- autoComplete="off"
120
- autoCapitalize="none"
121
- autoCorrect="off"
122
- spellCheck="false"
123
- aria-autocomplete="none"
124
- onClick={containerProps.onClick}
125
- readOnly
126
- />
127
- </VisuallyHidden>
128
- </div>
129
- )
130
- }
131
- )
@@ -1,134 +0,0 @@
1
- import { useEffect, useMemo } from 'react'
2
- import { OptionsList } from '../OptionItem/OptionsList'
3
- import { OptionItem } from '../OptionItem/OptionItem'
4
- import { Popover } from '../Popover'
5
- import { useFroozeClosing } from '../__hooks/use-frooze-closing'
6
- import { FormProps } from '../Form'
7
- import type { Option } from '../types'
8
- import { SelectInput } from './SelectInput'
9
- import { useScrollListController } from '../__hooks/use-scrollbox'
10
-
11
- interface SelectProps<T> extends Omit<FormProps, 'value' | 'onChange' | 'rightElement'> {
12
- options: Option<T>[]
13
- onChange: (event: T | null) => void
14
- placeholder?: string
15
- clearButton?: boolean
16
- clearButtonIcon?: boolean
17
- value: T | null
18
- children?: React.ReactNode
19
- minimalOptions?: boolean
20
- matchTarget?: 'width' | 'min-width'
21
- }
22
-
23
- export const Select = <T,>(props: SelectProps<T>) => {
24
- const {
25
- options,
26
- onChange,
27
- minimalOptions,
28
- clearButton,
29
- clearButtonIcon,
30
- matchTarget = 'width',
31
- value,
32
- children,
33
- disabled,
34
- ...inputProps
35
- } = props
36
-
37
- const currentOption = useMemo(() => {
38
- const index = options.findIndex((o) => o.value === value)
39
-
40
- return {
41
- index,
42
- option: options[index] as Option<T> | undefined
43
- }
44
- }, [options, value])
45
-
46
- const active = currentOption.option?.value ?? null
47
-
48
- const { popoverRef, froozePopoverPosition, handleAnimationEnd } = useFroozeClosing()
49
- const { scrollToElement, optionsWrapperRef, scrollBoxRef } = useScrollListController()
50
-
51
- const handleChange = (value: T, close: () => void) => {
52
- froozePopoverPosition()
53
- onChange(value)
54
- close()
55
- }
56
-
57
- const handleClear = (e: React.MouseEvent) => {
58
- e.stopPropagation()
59
- onChange(null)
60
- }
61
-
62
- const onOpened = () => {
63
- if (currentOption.index !== -1) {
64
- scrollToElement(currentOption.index, true)
65
- }
66
- }
67
-
68
- return (
69
- <Popover
70
- minimal
71
- ref={popoverRef}
72
- sideOffset={0}
73
- matchTarget={matchTarget}
74
- onAnimationEnd={handleAnimationEnd}
75
- onOpenAutoFocus={(e) => e.preventDefault()}
76
- onCloseAutoFocus={(e) => e.preventDefault()}
77
- disabled={disabled}
78
- content={({ close }) => (
79
- <SelectPopover<T>
80
- options={options}
81
- active={active}
82
- scrollboxRef={scrollBoxRef}
83
- optionsWrapperRef={optionsWrapperRef}
84
- minimalOptions={minimalOptions}
85
- onOpened={onOpened}
86
- onSelect={(value) => handleChange(value, close)}
87
- />
88
- )}
89
- >
90
- {children ?? (
91
- <SelectInput
92
- {...inputProps}
93
- disabled={disabled}
94
- value={currentOption.option?.title ?? ''}
95
- onClear={handleClear}
96
- clearButton={clearButton}
97
- clearButtonIcon={clearButtonIcon}
98
- />
99
- )}
100
- </Popover>
101
- )
102
- }
103
-
104
- interface SelectPopoverProps<T> {
105
- scrollboxRef?: React.Ref<HTMLDivElement>
106
- optionsWrapperRef?: React.RefObject<HTMLDivElement>
107
- options: Option<T>[]
108
- minimalOptions?: boolean
109
- active?: T | null
110
- onSelect?: (value: T) => void
111
- onOpened?: () => void
112
- }
113
-
114
- const SelectPopover = <T,>(props: SelectPopoverProps<T>) => {
115
- const { active, onOpened, scrollboxRef, optionsWrapperRef, options, onSelect, minimalOptions } = props
116
-
117
- useEffect(() => {
118
- onOpened?.()
119
- }, [])
120
-
121
- return (
122
- <OptionsList scrollboxRef={scrollboxRef} optionsWrapperRef={optionsWrapperRef} maxHeight={300}>
123
- {options.map((option, i) => (
124
- <OptionItem
125
- key={`option-item-${option.value}-${i}`}
126
- active={active === option.value}
127
- onClick={() => onSelect?.(option.value)}
128
- minimal={minimalOptions}
129
- {...option}
130
- />
131
- ))}
132
- </OptionsList>
133
- )
134
- }