react-animated-select 0.2.9 → 0.3.6

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
@@ -1,4 +1,4 @@
1
- import {FC, ReactNode} from 'react'
1
+ import {FC, ReactNode, CSSProperties, ElementType} from 'react'
2
2
 
3
3
  export interface SelectProps {
4
4
 
@@ -38,6 +38,15 @@ export interface SelectProps {
38
38
  style?: CSSProperties
39
39
  ArrowIcon?: ElementType | string | ReactNode
40
40
  ClearIcon?: ElementType | string | ReactNode
41
+
42
+ hasMore?: boolean
43
+ loadMore?: () => void
44
+ loadButton?: boolean
45
+ loadButtonText?: string
46
+ loadMoreText?: string
47
+ loadOffset?: number
48
+ loadAhead?: number
49
+ childrenFirst?: boolean
41
50
  }
42
51
 
43
52
  export const Select: FC<SelectProps>
@@ -50,4 +59,13 @@ export interface OptionProps {
50
59
  className?: string
51
60
  }
52
61
 
53
- export const Option: FC<OptionProps>
62
+ export const Option: FC<OptionProps>
63
+
64
+ export interface OptGroupProps {
65
+ value?: any
66
+ id?: any
67
+ name?: any
68
+ label?: any
69
+ }
70
+
71
+ export const OptGroup: FC<OptGroup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-animated-select",
3
- "version": "0.2.9",
3
+ "version": "0.3.6",
4
4
  "type": "module",
5
5
  "author": "l1nway (https://github.com/l1nway/)",
6
6
  "description": "Animated, accessible, and flexible select component for React",
@@ -16,7 +16,7 @@
16
16
  "url": "git+https://github.com/l1nway/react-animated-select.git"
17
17
  },
18
18
  "license": "MIT",
19
- "homepage": "https://github.com/l1nway/react-animated-select#readme",
19
+ "homepage": "https://l1nway.github.io/react-animated-select/",
20
20
  "scripts": {
21
21
  "build": "vite build",
22
22
  "dev": "vite build --watch"
@@ -40,6 +40,7 @@
40
40
  "react-transition-group": "^4.4.5"
41
41
  },
42
42
  "devDependencies": {
43
+ "@types/react": "^19.2.9",
43
44
  "@vitejs/plugin-react": "^5.1.2",
44
45
  "vite": "^7.3.1",
45
46
  "vite-plugin-lib-inject-css": "^2.2.2"
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export {default as Select} from './select'
2
2
  export {default as Option} from './option'
3
+ export {default as OptGroup} from './optgroup'
3
4
 
4
5
  import './select.css'
@@ -0,0 +1,36 @@
1
+ import {useContext, useEffect, useMemo, createContext} from 'react'
2
+ import {SelectContext} from './selectContext'
3
+ import {makeId} from './makeId'
4
+
5
+ export const GroupContext = createContext(null)
6
+
7
+ export default function OptGroup({children, name, label, value, id, emptyGroupText = 'Empty group'}) {
8
+ const ctx = useContext(SelectContext)
9
+
10
+ const groupName = useMemo(() => {
11
+ const val = name ?? label ?? value ?? id
12
+ return (val !== undefined && val !== null && val !== '') ? String(val) : emptyGroupText
13
+ }, [name, label, value, id, emptyGroupText])
14
+
15
+ const groupId = useMemo(() => `group-marker-${makeId(groupName)}`, [groupName])
16
+
17
+ useEffect(() => {
18
+ if (!ctx) return
19
+
20
+ const groupMarker = {
21
+ id: groupId,
22
+ group: groupName,
23
+ isGroupMarker: true,
24
+ disabled: true
25
+ }
26
+
27
+ ctx.registerOption(groupMarker)
28
+ return () => ctx.unregisterOption(groupId)
29
+ }, [ctx.registerOption, ctx.unregisterOption, groupId, groupName])
30
+
31
+ return (
32
+ <GroupContext.Provider value={groupName}>
33
+ {children}
34
+ </GroupContext.Provider>
35
+ )
36
+ }
package/src/option.jsx CHANGED
@@ -1,28 +1,48 @@
1
- import {useEffect, useContext} from 'react'
1
+ import {useEffect, useContext, useMemo, useId} from 'react'
2
2
  import {SelectContext} from './selectContext'
3
- import {makeId} from './makeId'
3
+ import {GroupContext} from './optgroup'
4
4
  import getText from './getText'
5
5
 
6
- export default function Option({value, id, className, children, disabled}) {
6
+ export default function Option({value, id, className, children, disabled, group: manualGroup}) {
7
7
  const ctx = useContext(SelectContext)
8
+ const contextGroup = useContext(GroupContext)
9
+
10
+ const registerOption = ctx?.registerOption;
11
+ const unregisterOption = ctx?.unregisterOption;
12
+
13
+ const uniqueId = useId()
14
+ const stableId = useMemo(() => {
15
+ return id ? String(id) : uniqueId.replace(/:/g, '')
16
+ }, [id, uniqueId])
8
17
 
9
18
  useEffect(() => {
10
- if (!ctx) return
19
+ if (!registerOption) return
11
20
 
12
21
  const textFallback = getText(children)
13
-
22
+ let finalLabel = ''
23
+
24
+ if (typeof children === 'string' && children !== '') {
25
+ finalLabel = children
26
+ } else if (textFallback) {
27
+ finalLabel = textFallback
28
+ } else if (value !== undefined && value !== null) {
29
+ finalLabel = String(value)
30
+ }
31
+
14
32
  const option = {
15
- id: String(id ?? makeId(String(textFallback))),
33
+ id: stableId,
16
34
  value: value !== undefined ? value : textFallback,
17
- label: typeof children === 'string' ? children : String(value ?? id),
35
+ label: finalLabel,
18
36
  jsx: children,
19
37
  className,
20
- disabled: !!disabled
38
+ disabled: !!disabled,
39
+ group: manualGroup || contextGroup || null
21
40
  }
22
41
 
23
- ctx.registerOption(option)
24
- return () => ctx.unregisterOption(option.id)
25
- }, [id, value, children, className, disabled])
42
+ registerOption(option)
43
+ return () => unregisterOption(stableId)
44
+
45
+ }, [stableId, value, children, className, disabled, manualGroup, contextGroup, registerOption, unregisterOption])
26
46
 
27
47
  return null
28
48
  }
package/src/options.jsx CHANGED
@@ -30,17 +30,17 @@ function Options({
30
30
  const transitionString = `height ${duration}ms ${easing}${animateOpacity ? `, opacity ${duration}ms ${easing}` : ''}`
31
31
 
32
32
  const baseStyles = {
33
- position: 'absolute',
34
- top: `calc(100% + ${offset}px)`,
35
- left: '0',
36
- width: '100%',
37
- overflow: 'hidden',
38
- marginTop: '2px',
39
- zIndex: '1',
40
- height: visibility ? 'auto' : '0px',
41
- opacity: animateOpacity ? (visibility ? 1 : 0) : 1,
42
- pointerEvents: visibility ? 'all' : 'none',
43
- visibility: selectHeight ? 'visible' : 'hidden'
33
+ position: 'absolute',
34
+ top: `calc(100% + ${offset}px)`,
35
+ left: '0',
36
+ width: '100%',
37
+ overflow: 'hidden',
38
+ marginTop: '2px',
39
+ zIndex: '1',
40
+ height: visibility ? 'auto' : '0px',
41
+ opacity: animateOpacity ? (visibility ? 1 : 0) : 1,
42
+ pointerEvents: visibility ? 'all' : 'none',
43
+ visibility: selectHeight ? 'visible' : 'hidden'
44
44
  }
45
45
 
46
46
  const handleEnter = useCallback(() => {
package/src/select.css CHANGED
@@ -56,12 +56,21 @@
56
56
  --rac-list-max-height: 250px;
57
57
 
58
58
  --rac-option-padding: 0.5em;
59
+ --rac-option-min-height: 1em;
59
60
  --rac-disabled-option-color: color-mix(in srgb, GrayText, CanvasText 20%);
60
61
  --rac-invalid-option-color: color-mix(in srgb, var(--rac-base-red), CanvasText 10%);
61
62
  --rac-true-option-color: color-mix(in srgb, var(--rac-base-green), CanvasText 10%);
62
63
  --rac-false-option-color: color-mix(in srgb, var(--rac-base-red), CanvasText 10%);
63
64
  --rac-warning-option-color: color-mix(in srgb, var(--rac-base-yellow), CanvasText 10%);
64
65
 
66
+ --rac-group-header-font-size: 1.25em;
67
+ --rac-group-header-font-weight: bold;
68
+ --rac-group-header-min-height: 1em;
69
+ --rac-group-header-padding: 0.5em;
70
+ --rac-group-arrow-height: 1em;
71
+ --rac-group-arrow-width: 1em;
72
+ --rac-group-arrow-padding: 1px 0 2px;
73
+
65
74
  background: var(--rac-select-background);
66
75
  padding: var(--rac-select-padding);
67
76
  border: var(--rac-select-border);
@@ -197,11 +206,12 @@
197
206
  }
198
207
 
199
208
  .rac-select-option {
209
+ min-height: var(--rac-option-min-height);
200
210
  padding: var(--rac-option-padding);
201
211
  transition: background-color var(--rac-duration-fast) cubic-bezier(0.4,0,0.2,1);
202
212
  }
203
213
 
204
- .rac-select-option:not(.rac-disabled-option):hover {
214
+ .rac-select-option:not(.rac-disabled-option):not(.rac-group-option):hover {
205
215
  background-color: var(--rac-option-hover);
206
216
  }
207
217
 
@@ -232,4 +242,38 @@
232
242
 
233
243
  .rac-false-option {
234
244
  color: var(--rac-false-option-color);
245
+ }
246
+
247
+ .rac-loading-option {
248
+ cursor: wait;
249
+ }
250
+
251
+ .rac-group-header {
252
+ cursor: pointer;
253
+ min-height: var(--rac-group-header-min-height);
254
+ padding: var(--rac-group-header-padding);
255
+ transition: background-color var(--rac-duration-fast) cubic-bezier(0.4,0,0.2,1);
256
+ display: flex;
257
+ justify-content: space-between;
258
+ align-items: center;
259
+ font-weight: var(--rac-group-header-font-weight);
260
+ font-size: var(--rac-group-header-font-size);
261
+ }
262
+
263
+ .rac-group-arrow-wrapper {
264
+ display: block;
265
+ height: var(--rac-group-arrow-height);
266
+ width: var(--rac-group-arrow-width);
267
+ padding: var(--rac-group-arrow-padding);
268
+
269
+ will-change: transform;
270
+ transition:
271
+ transform var(--rac-duration-base) cubic-bezier(.4,0,.2,1),
272
+ padding var(--rac-duration-fast);
273
+ transform-origin: 50% 50%;
274
+ transform: translateZ(0);
275
+ }
276
+
277
+ .rac-group-arrow-wrapper.--open {
278
+ transform: rotate(180deg);
235
279
  }