react-animated-select 0.2.5 → 0.2.7

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.
package/index.d.ts CHANGED
@@ -18,7 +18,7 @@ export interface SelectProps {
18
18
  options?: any[] | Record<string, any>
19
19
  value?: any
20
20
  defaultValue?: any
21
- onChange?: (value: any, option: any) => void
21
+ onChange?: (data: any, id: any) => void
22
22
 
23
23
  disabled?: boolean
24
24
  loading?: boolean
@@ -35,14 +35,17 @@ export interface SelectProps {
35
35
  invalidOption?: string
36
36
 
37
37
  className?: string
38
- id?: string
38
+ style?: CSSProperties
39
+ ArrowIcon?: ElementType | string | ReactNode
40
+ ClearIcon?: ElementType | string | ReactNode
39
41
  }
40
42
 
41
43
  export const Select: FC<SelectProps>
42
44
 
43
45
  export interface OptionProps {
44
- value: any
45
- children: ReactNode
46
+ value?: any
47
+ id?: any
48
+ children?: ReactNode
46
49
  disabled?: boolean
47
50
  className?: string
48
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-animated-select",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "author": "l1nway (https://github.com/l1nway/)",
6
6
  "description": "Animated, accessible, and flexible select component for React",
package/src/icons.jsx CHANGED
@@ -1,27 +1,29 @@
1
1
  export const XMarkIcon = ({className = '', ...props}) => (
2
2
  <svg
3
- className={className}
4
- xmlns="http://www.w3.org/2000/svg"
5
- viewBox="0 0 320 512"
6
- width="1em"
7
- height="1em"
8
- fill="currentColor"
9
- {...props}
3
+ className={className}
4
+ role='button'
5
+ aria-label='Clear selection'
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ viewBox="0 0 320 512"
8
+ width="1em"
9
+ height="1em"
10
+ fill="currentColor"
11
+ {...props}
10
12
  >
11
13
  <path d="M310.6 361.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L160 301.3 54.6 406.6c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L114.7 256 9.4 150.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 210.7 265.4 105.4c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3L205.3 256l105.3 105.4z"/>
12
14
  </svg>
13
15
  )
14
16
 
15
- export const ArrowUpIcon = ({ className = '', ...props }) => (
17
+ export const ArrowUpIcon = ({className = '', ...props}) => (
16
18
  <svg
17
- className={className}
18
- xmlns="http://www.w3.org/2000/svg"
19
- viewBox="0 0 448 512"
20
- width="1em"
21
- height="1em"
22
- fill="currentColor"
23
- {...props}
19
+ className={className}
20
+ xmlns="http://www.w3.org/2000/svg"
21
+ viewBox="0 0 448 512"
22
+ width="1em"
23
+ height="1em"
24
+ fill="currentColor"
25
+ {...props}
24
26
  >
25
- <path d="M34.9 289.5l175.9-175.8c9.4-9.4 24.6-9.4 33.9 0L420.1 289.5c15.1 15.1 4.4 41-17 41H51.9c-21.4 0-32.1-25.9-17-41z"/>
27
+ <path d="M34.9 289.5l175.9-175.8c9.4-9.4 24.6-9.4 33.9 0L420.1 289.5c15.1 15.1 4.4 41-17 41H51.9c-21.4 0-32.1-25.9-17-41z"/>
26
28
  </svg>
27
29
  )
package/src/select.css CHANGED
@@ -21,6 +21,9 @@
21
21
  --rac-select-padding: 0em 0.5em;
22
22
  --rac-disabled-opacity: 0.75;
23
23
 
24
+ --rac-title-anim-shift: 4px;
25
+ --rac-title-anim-entry-ease: cubic-bezier(0.34, 1.56, 0.64, 1);
26
+
24
27
  --rac-dots-height: 3px;
25
28
  --rac-dots-width: 3px;
26
29
  --rac-dots-color: currentColor;
@@ -97,11 +100,26 @@
97
100
  align-items: center;
98
101
  }
99
102
 
103
+ .rac-title-text {
104
+ display: block;
105
+ animation: rac-fade-in var(--rac-duration-base) var(--rac-title-anim-entry-ease);
106
+ }
107
+
108
+ @keyframes rac-fade-in {
109
+ from {
110
+ opacity: 0;
111
+ transform: translateY(var(--rac-title-anim-shift));
112
+ }
113
+ to {
114
+ opacity: 1;
115
+ transform: translateY(0);
116
+ }
117
+ }
118
+
100
119
  .rac-loading-dots {
101
120
  display: inline-flex;
102
121
  gap: var(--rac-dots-gap);
103
122
  padding-left: var(--rac-dots-padding-left);
104
- height: 90%;
105
123
  align-items: var(--rac-dots-align);
106
124
  }
107
125
 
@@ -155,6 +173,11 @@
155
173
  transform: rotate(180deg);
156
174
  }
157
175
 
176
+ .rac-select-arrow,
177
+ .rac-select-cancel {
178
+ object-fit: contain;
179
+ }
180
+
158
181
  .rac-select-list {
159
182
  background-color: var(--rac-list-background);
160
183
  color: var(--rac-list-color);
package/src/select.jsx CHANGED
@@ -1,7 +1,7 @@
1
1
  import './select.css'
2
2
 
3
3
  import {XMarkIcon, ArrowUpIcon} from './icons'
4
- import {useRef, useMemo, useState, useEffect, useCallback, useId} from 'react'
4
+ import {forwardRef, useImperativeHandle, useRef, useMemo, useState, useEffect, useCallback, useId, isValidElement, cloneElement} from 'react'
5
5
 
6
6
  import {SelectContext} from './selectContext'
7
7
  import useSelect from './useSelect'
@@ -10,7 +10,26 @@ import {makeId} from './makeId'
10
10
  import Options from './options'
11
11
  import SlideLeft from './slideLeft'
12
12
 
13
- export default function Select({
13
+ const renderIcon = (Icon, defaultProps) => {
14
+ if (!Icon) return null
15
+
16
+ if (typeof Icon === 'string') {
17
+ return <img src={Icon} {...defaultProps} alt='' />
18
+ }
19
+
20
+ if (isValidElement(Icon)) {
21
+ return cloneElement(Icon, defaultProps)
22
+ }
23
+
24
+ if (typeof Icon === 'function' || (typeof Icon === 'object' && Icon.$$typeof)) {
25
+ const IconComponent = Icon
26
+ return <IconComponent {...defaultProps} />
27
+ }
28
+
29
+ return null
30
+ }
31
+
32
+ const Select = forwardRef(({
14
33
  unmount,
15
34
  children,
16
35
  renderedDropdown,
@@ -21,8 +40,12 @@ export default function Select({
21
40
  easing = 'ease-out',
22
41
  offset = 2,
23
42
  animateOpacity = true,
43
+ style = {},
44
+ className = '',
45
+ ArrowIcon = ArrowUpIcon,
46
+ ClearIcon = XMarkIcon,
24
47
  ...props
25
- }) {
48
+ }, ref) => {
26
49
 
27
50
  const reactId = useId()
28
51
 
@@ -41,6 +64,17 @@ export default function Select({
41
64
  // ref is needed to pass dimensions for the animation hook
42
65
  const selectRef = useRef(null)
43
66
 
67
+ useEffect(() => {
68
+ if (!ref) return
69
+ if (typeof ref === 'function') {
70
+ ref(selectRef.current)
71
+ } else {
72
+ ref.current = selectRef.current
73
+ }
74
+ }, [ref])
75
+
76
+ useImperativeHandle(ref, () => selectRef.current)
77
+
44
78
  // open/closed status select
45
79
  const [internalVisibility, setInternalVisibility] = useState(false)
46
80
 
@@ -203,8 +237,12 @@ export default function Select({
203
237
  {children}
204
238
  {renderedDropdown}
205
239
  <div
206
- style={{'--rac-duration': `${duration}ms`}}
240
+ style={{
241
+ '--rac-duration': `${duration}ms`,
242
+ ...style
243
+ }}
207
244
  className={`rac-select
245
+ ${className}
208
246
  ${(!hasOptions || disabled) ? 'rac-disabled-style' : ''}
209
247
  ${loading ? 'rac-loading-style' : ''}
210
248
  ${error ? 'rac-error-style' : ''}`
@@ -225,12 +263,17 @@ export default function Select({
225
263
  })}
226
264
  >
227
265
  <div
228
- className={`rac-select-title ${selected?.type == 'boolean'
266
+ className={`rac-select-title ${(!error && !loading && selected?.type == 'boolean')
229
267
  ? selected.raw ? 'rac-true-option' : 'rac-false-option'
230
268
  : ''
231
269
  }`}
232
270
  >
233
- {title}
271
+ <span
272
+ className='rac-title-text'
273
+ key={title}
274
+ >
275
+ {title}
276
+ </span>
234
277
  <SlideLeft
235
278
  visibility={loading && !error}
236
279
  duration={duration}
@@ -246,24 +289,24 @@ export default function Select({
246
289
  <SlideLeft
247
290
  visibility={hasActualValue && hasOptions && !disabled && !loading && !error}
248
291
  duration={duration}
292
+ style={{display: 'grid'}}
249
293
  >
250
- <XMarkIcon
251
- className='rac-select-cancel'
252
- role='button'
253
- aria-label='Clear selection'
254
- onClick={(e) => clear(e)}
255
- />
294
+ {renderIcon(ClearIcon, {
295
+ className: 'rac-select-cancel',
296
+ onClick: (e) => clear(e)
297
+ })}
256
298
  </SlideLeft>
257
299
  <SlideLeft
258
300
  visibility={active}
259
301
  duration={duration}
302
+ style={{display: 'grid'}}
260
303
  >
261
304
  <span
262
305
  className={`rac-select-arrow-wrapper ${visibility ? '--open' : ''}`}
263
306
  >
264
- <ArrowUpIcon
265
- className='rac-select-arrow-wrapper'
266
- />
307
+ {renderIcon(ArrowIcon, {
308
+ className: 'rac-select-arrow-wrapper'
309
+ })}
267
310
  </span>
268
311
  </SlideLeft>
269
312
  </div>
@@ -288,4 +331,6 @@ export default function Select({
288
331
  </div>
289
332
  </SelectContext.Provider>
290
333
  )
291
- }
334
+ })
335
+
336
+ export default Select
package/src/slideLeft.jsx CHANGED
@@ -4,8 +4,9 @@ import {useRef} from 'react'
4
4
  function SlideLeft({
5
5
  visibility,
6
6
  children,
7
- duration,
8
- unmount
7
+ duration = 300,
8
+ unmount,
9
+ style
9
10
  }) {
10
11
  const nodeRef = useRef(null)
11
12
 
@@ -26,7 +27,7 @@ function SlideLeft({
26
27
  <div
27
28
  ref={nodeRef}
28
29
  style={{
29
- display: 'grid',
30
+ ...style,
30
31
  overflow: 'hidden',
31
32
  transition: `width ${duration}ms ease`
32
33
  }}